diff options
author | David Douard <david.douard@logilab.fr> | 2012-11-14 17:02:48 +0100 |
---|---|---|
committer | David Douard <david.douard@logilab.fr> | 2012-11-14 17:02:48 +0100 |
commit | 9fc4653fc67300e02b0d0a0ecd2fb4fe647780ab (patch) | |
tree | ae8761455ad3edecb8e59b94972357f6d7159a77 | |
parent | d9ae7d4a40d65160de9ff07b69ea880f7fb2040d (diff) | |
parent | 1d0f11913a66d5410c65a9c039a1630218b2e3ae (diff) | |
download | logilab-common-9fc4653fc67300e02b0d0a0ecd2fb4fe647780ab.tar.gz |
backport stable
-rw-r--r-- | ChangeLog | 28 | ||||
-rw-r--r-- | __pkginfo__.py | 2 | ||||
-rw-r--r-- | date.py | 54 | ||||
-rw-r--r-- | debian/changelog | 18 | ||||
-rw-r--r-- | modutils.py | 33 | ||||
-rw-r--r-- | registry.py | 7 | ||||
-rw-r--r-- | setup.py | 19 | ||||
-rw-r--r-- | shellutils.py | 2 | ||||
-rw-r--r-- | table.py | 10 | ||||
-rw-r--r-- | test/data/lmfp/__init__.py | 2 | ||||
-rw-r--r-- | test/data/lmfp/foo.py | 6 | ||||
-rw-r--r-- | test/data/test1.msg | 4 | ||||
-rw-r--r-- | test/unittest_cache.py | 10 | ||||
-rw-r--r-- | test/unittest_changelog.py | 7 | ||||
-rw-r--r-- | test/unittest_date.py | 4 | ||||
-rw-r--r-- | test/unittest_decorators.py | 10 | ||||
-rw-r--r-- | test/unittest_fileutils.py | 64 | ||||
-rw-r--r-- | test/unittest_modutils.py | 45 | ||||
-rw-r--r-- | test/unittest_shellutils.py | 14 | ||||
-rw-r--r-- | test/unittest_table.py | 18 | ||||
-rw-r--r-- | test/unittest_testlib.py | 40 | ||||
-rw-r--r-- | test/unittest_umessage.py | 2 | ||||
-rw-r--r-- | testlib.py | 30 | ||||
-rw-r--r-- | umessage.py | 93 |
24 files changed, 303 insertions, 219 deletions
@@ -1,7 +1,32 @@ ChangeLog for logilab.common ============================ -2012-04-12 -- 0.58.0 +2012-11-14 -- 0.58.3 + * date: fix ustrftime() impl. for python3 (closes #82161, patch by Arfrever + Frehtes Taifersar Arahesis) and encoding detection for python2 (closes + #109740) + + * other python3 code and test fixes (closes #104047) + + * registry: setdefault shouldn't raise RegistryNotFound (closes #111010) + + * table: stop encoding to iso-8859-1, use unicode (closes #105847) + + * setup: properly install additional files during build instead of install (closes #104045) + + + +2012-07-30 -- 0.58.2 + * modutils: fixes (closes #100757 and #100935) + + + +2012-07-17 -- 0.58.1 + * modutils, testlib: be more python implementation independant (closes #99493 and #99627) + + + +2012-04-12 -- 0.58.0 * new `registry` module containing a backport of CubicWeb selectable objects registry (closes #84654) * testlib: DocTestCase fix builtins pollution after doctest execution. @@ -11,6 +36,7 @@ ChangeLog for logilab.common * deprecated: new DeprecationWrapper class (closes #88942) + 2012-03-22 -- 0.57.2 * texutils: apply_units raise ValueError if string isn'nt valid (closes #88808) diff --git a/__pkginfo__.py b/__pkginfo__.py index d6c6332..5f47663 100644 --- a/__pkginfo__.py +++ b/__pkginfo__.py @@ -24,7 +24,7 @@ modname = 'common' subpackage_of = 'logilab' subpackage_master = True -numversion = (0, 58, 0) +numversion = (0, 58, 3) version = '.'.join([str(num) for num in numversion]) license = 'LGPL' # 2.1 or later @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -22,7 +22,8 @@ __docformat__ = "restructuredtext en" import math import re -from locale import getpreferredencoding +import sys +from locale import getlocale, LC_TIME from datetime import date, time, datetime, timedelta from time import strptime as time_strptime from calendar import monthrange, timegm @@ -279,29 +280,34 @@ def last_day(somedate): def ustrftime(somedate, fmt='%Y-%m-%d'): """like strftime, but returns a unicode string instead of an encoded - string which' may be problematic with localized date. - - encoding is guessed by locale.getpreferredencoding() + string which may be problematic with localized date. """ - encoding = getpreferredencoding(do_setlocale=False) or 'UTF-8' - try: - return unicode(somedate.strftime(str(fmt)), encoding) - except ValueError, exc: - if somedate.year >= 1900: - raise - # datetime is not happy with dates before 1900 - # we try to work around this, assuming a simple - # format string - fields = {'Y': somedate.year, - 'm': somedate.month, - 'd': somedate.day, - } - if isinstance(somedate, datetime): - fields.update({'H': somedate.hour, - 'M': somedate.minute, - 'S': somedate.second}) - fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt) - return unicode(fmt) % fields + if sys.version_info >= (3, 3): + # datetime.date.strftime() supports dates since year 1 in Python >=3.3. + return somedate.strftime(fmt) + else: + try: + if sys.version_info < (3, 0): + encoding = getlocale(LC_TIME)[1] or 'ascii' + return unicode(somedate.strftime(str(fmt)), encoding) + else: + return somedate.strftime(fmt) + except ValueError, exc: + if somedate.year >= 1900: + raise + # datetime is not happy with dates before 1900 + # we try to work around this, assuming a simple + # format string + fields = {'Y': somedate.year, + 'm': somedate.month, + 'd': somedate.day, + } + if isinstance(somedate, datetime): + fields.update({'H': somedate.hour, + 'M': somedate.minute, + 'S': somedate.second}) + fmt = re.sub('%([YmdHMS])', r'%(\1)02d', fmt) + return unicode(fmt) % fields def utcdatetime(dt): if dt.tzinfo is None: diff --git a/debian/changelog b/debian/changelog index e501433..21428ff 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,21 @@ +logilab-common (0.58.3-1) unstable; urgency=low + + * new upstream release + + -- David Douard <david.douard@logilab.fr> Wed, 14 Nov 2012 16:18:53 +0100 + +logilab-common (0.58.2-1) precise; urgency=low + + * new upstream release + + -- David Douard <david.douard@logilab.fr> Mon, 30 Jul 2012 12:26:15 +0200 + +logilab-common (0.58.1-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault <sylvain.thenault@logilab.fr> Tue, 17 Jul 2012 16:01:54 +0200 + logilab-common (0.58.0-1) unstable; urgency=low * new upstream release diff --git a/modutils.py b/modutils.py index 95c400a..2cae005 100644 --- a/modutils.py +++ b/modutils.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -34,6 +34,7 @@ import os from os.path import splitext, join, abspath, isdir, dirname, exists, basename from imp import find_module, load_module, C_BUILTIN, PY_COMPILED, PKG_DIRECTORY from distutils.sysconfig import get_config_var, get_python_lib, get_python_version +from distutils.errors import DistutilsPlatformError try: import zipimport @@ -53,12 +54,18 @@ from logilab.common import STD_BLACKLIST, _handle_blacklist if sys.platform.startswith('win'): PY_SOURCE_EXTS = ('py', 'pyw') PY_COMPILED_EXTS = ('dll', 'pyd') - STD_LIB_DIR = get_python_lib(standard_lib=1) else: PY_SOURCE_EXTS = ('py',) PY_COMPILED_EXTS = ('so',) - # extend lib dir with some arch-dependant paths - STD_LIB_DIR = join(get_config_var("LIBDIR"), "python%s" % get_python_version()) + +try: + STD_LIB_DIR = get_python_lib(standard_lib=1) +# get_python_lib(standard_lib=1) is not available on pypy, set STD_LIB_DIR to +# non-valid path, see https://bugs.pypy.org/issue1164 +except DistutilsPlatformError: + STD_LIB_DIR = '//' + +EXT_LIB_DIR = get_python_lib() BUILTIN_MODULES = dict(zip(sys.builtin_module_names, [1]*len(sys.builtin_module_names))) @@ -151,6 +158,9 @@ def load_module_from_modpath(parts, path=None, use_sys=1): if len(modpath) != len(parts): # even with use_sys=False, should try to get outer packages from sys.modules module = sys.modules.get(curname) + elif use_sys: + # because it may have been indirectly loaded through a parent + module = sys.modules.get(curname) if module is None: mp_file, mp_filename, mp_desc = find_module(part, path) module = load_module(curname, mp_file, mp_filename, mp_desc) @@ -230,10 +240,7 @@ def modpath_from_file(filename, extrapath=None): return extrapath[path_].split('.') + submodpath for path in sys.path: path = abspath(path) - if path and base[:len(path)] == path: - if filename.find('site-packages') != -1 and \ - path.find('site-packages') == -1: - continue + if path and base.startswith(path): modpath = [pkg for pkg in base[len(path):].split(os.sep) if pkg] if _check_init(path, modpath[:-1]): return modpath @@ -493,13 +500,11 @@ def is_standard_module(modname, std_path=(STD_LIB_DIR,)): if filename is None: return 1 filename = abspath(filename) + if filename.startswith(EXT_LIB_DIR): + return 0 for path in std_path: - path = abspath(path) - if filename.startswith(path): - pfx_len = len(path) - if filename[pfx_len+1:pfx_len+14] != 'site-packages': - return 1 - return 0 + if filename.startswith(abspath(path)): + return 1 return False diff --git a/registry.py b/registry.py index 29f3c56..86065c5 100644 --- a/registry.py +++ b/registry.py @@ -218,7 +218,8 @@ class Registry(dict): assert not '__abstract__' in obj.__dict__ assert obj.__select__ oid = oid or obj.__regid__ - assert oid + assert oid, ('no explicit name supplied to register object %s, ' + 'which has no __regid__ set' % obj) if clear: objects = self[oid] = [] else: @@ -500,7 +501,7 @@ class RegistryStore(dict): def setdefault(self, regid): try: return self[regid] - except KeyError: + except RegistryNotFound: self[regid] = self.registry_class(regid)(self.debugmode) return self[regid] @@ -519,6 +520,8 @@ class RegistryStore(dict): :meth:`~logilab.common.registry.RegistryStore.register_and_replace` for instance) """ + assert isinstance(modname, basestring), \ + 'modname expected to be a module name (ie string), got %r' % modname for obj in objects: try: if obj.__module__ != modname or obj in butclasses: @@ -1,7 +1,7 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # pylint: disable=W0404,W0622,W0704,W0613 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -105,8 +105,7 @@ except ImportError: ''' class MyInstallLib(install_lib.install_lib): - """extend install_lib command to handle package __init__.py and - include_dirs variable if necessary + """extend install_lib command to handle package __init__.py if necessary """ def run(self): """overridden from install_lib class""" @@ -119,17 +118,27 @@ class MyInstallLib(install_lib.install_lib): stream = open(product_init, 'w') stream.write(EMPTY_FILE) stream.close() + + +class MyBuildPy(build_py): + """extend build_by command to handle include_dirs variable if necessary + """ + def run(self): + """overridden from install_lib class""" + build_py.run(self) # manually install included directories if any if include_dirs: if subpackage_of: base = join(subpackage_of, modname) else: base = modname + basedir = os.path.join(self.build_lib, base) for directory in include_dirs: - dest = join(self.install_dir, base, directory) + dest = join(basedir, directory) shutil.rmtree(dest, ignore_errors=True) shutil.copytree(directory, dest) + def install(**kwargs): """setup entry point""" if USE_SETUPTOOLS: @@ -164,7 +173,7 @@ def install(**kwargs): data_files = data_files, ext_modules = ext_modules, cmdclass = {'install_lib': MyInstallLib, - 'build_py': build_py}, + 'build_py': MyBuildPy}, **kwargs ) diff --git a/shellutils.py b/shellutils.py index 749cbac..60ef602 100644 --- a/shellutils.py +++ b/shellutils.py @@ -338,7 +338,7 @@ class ProgressBar(object): def refresh(self): """Refresh the progression bar display.""" - self._stream.write(self._fstr % ('.' * min(self._progress, self._size)) ) + self._stream.write(self._fstr % ('=' * min(self._progress, self._size)) ) if self._last_text_write_size or self._current_text: template = ' %%-%is' % (self._last_text_write_size) text = self._current_text @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -440,7 +440,7 @@ class Table(object): # The first cell <=> an empty one col_names_line = [' '*col_start] for col_name in self.col_names: - col_names_line.append(col_name.encode('iso-8859-1') + ' '*5) + col_names_line.append(col_name + ' '*5) lines.append('|' + '|'.join(col_names_line) + '|') max_line_length = len(lines[0]) @@ -448,7 +448,7 @@ class Table(object): for row_index, row in enumerate(self.data): line = [] # First, build the row_name's cell - row_name = self.row_names[row_index].encode('iso-8859-1') + row_name = self.row_names[row_index] line.append(row_name + ' '*(col_start-len(row_name))) # Then, build all the table's cell for this line. @@ -743,14 +743,14 @@ class TableCellRenderer: def render_row_cell(self, row_name, table, table_style): """Renders the cell for 'row_id' row """ - cell_value = row_name.encode('iso-8859-1') + cell_value = row_name return self._render_cell_content(cell_value, table_style, 0) def render_col_cell(self, col_name, table, table_style): """Renders the cell for 'col_id' row """ - cell_value = col_name.encode('iso-8859-1') + cell_value = col_name col_index = table.col_names.index(col_name) return self._render_cell_content(cell_value, table_style, col_index +1) diff --git a/test/data/lmfp/__init__.py b/test/data/lmfp/__init__.py new file mode 100644 index 0000000..74b26b8 --- /dev/null +++ b/test/data/lmfp/__init__.py @@ -0,0 +1,2 @@ +# force a "direct" python import +from . import foo diff --git a/test/data/lmfp/foo.py b/test/data/lmfp/foo.py new file mode 100644 index 0000000..8f7de1e --- /dev/null +++ b/test/data/lmfp/foo.py @@ -0,0 +1,6 @@ +import sys +if not getattr(sys, 'bar', None): + sys.just_once = [] +# there used to be two numbers here because +# of a load_module_from_path bug +sys.just_once.append(42) diff --git a/test/data/test1.msg b/test/data/test1.msg index e9c044d..33b75c8 100644 --- a/test/data/test1.msg +++ b/test/data/test1.msg @@ -13,7 +13,7 @@ To: Nicolas Chauvat <nico@logilab.fr> Subject: autre message Message-ID: <20050720100320.GA8371@logilab.fr> Mime-Version: 1.0 -Content-Type: text/plain; charset=iso-8859-1 +Content-Type: text/plain; charset=utf-8 Content-Disposition: inline Content-Transfer-Encoding: 8bit User-Agent: Mutt/1.5.9i @@ -26,5 +26,5 @@ bonjour -- Nicolas Chauvat -logilab.fr - services en informatique avancée et gestion de connaissances +logilab.fr - services en informatique avancée et gestion de connaissances diff --git a/test/unittest_cache.py b/test/unittest_cache.py index c184cca..9b02b39 100644 --- a/test/unittest_cache.py +++ b/test/unittest_cache.py @@ -1,5 +1,5 @@ # unit tests for the cache module -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -68,9 +68,9 @@ class CacheTestCase(TestCase): self.cache[4] = 'foz' self.cache[5] = 'fuz' self.cache[6] = 'spam' - self.assert_(1 not in self.cache, + self.assertTrue(1 not in self.cache, 'key 1 has not been suppressed from the cache dictionnary') - self.assert_(1 not in self.cache._usage, + self.assertTrue(1 not in self.cache._usage, 'key 1 has not been suppressed from the cache LRU list') self.assertEqual(len(self.cache._usage), 5, "lenght of usage list is not 5") self.assertEqual(self.cache._usage[-1], 6, '6 is not the most recently used key') @@ -95,8 +95,8 @@ class CacheTestCase(TestCase): """ self.cache['foo'] = 'bar' del self.cache['foo'] - self.assert_('foo' not in self.cache.keys(), "Element 'foo' was not removed cache dictionnary") - self.assert_('foo' not in self.cache._usage, "Element 'foo' was not removed usage list") + self.assertTrue('foo' not in self.cache.keys(), "Element 'foo' was not removed cache dictionnary") + self.assertTrue('foo' not in self.cache._usage, "Element 'foo' was not removed usage list") self.assertItemsEqual(self.cache._usage, self.cache.keys())# usage list and data keys are different diff --git a/test/unittest_changelog.py b/test/unittest_changelog.py index 4db67ef..dff9979 100644 --- a/test/unittest_changelog.py +++ b/test/unittest_changelog.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -15,6 +15,8 @@ # # You should have received a copy of the GNU Lesser General Public License along # with logilab-common. If not, see <http://www.gnu.org/licenses/>. +from __future__ import with_statement + from os.path import join, dirname from cStringIO import StringIO @@ -30,7 +32,8 @@ class ChangeLogTC(TestCase): cl = self.cl_class(self.cl_file) out = StringIO() cl.write(out) - self.assertStreamEquals(open(self.cl_file), out) + with open(self.cl_file) as stream: + self.assertMultiLineEqual(stream.read(), out.getvalue()) if __name__ == '__main__': diff --git a/test/unittest_date.py b/test/unittest_date.py index 8fa7776..0aa1de8 100644 --- a/test/unittest_date.py +++ b/test/unittest_date.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -147,7 +147,7 @@ class MxDateTC(DateTC): def check_mx(self): if mxDate is None: - self.skip('mx.DateTime is not installed') + self.skipTest('mx.DateTime is not installed') def setUp(self): self.check_mx() diff --git a/test/unittest_decorators.py b/test/unittest_decorators.py index 49661a6..72d8b07 100644 --- a/test/unittest_decorators.py +++ b/test/unittest_decorators.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -46,14 +46,14 @@ class DecoratorsTC(TestCase): return 12 class XXX(object): def __call__(self, other): - tester.assertTrue(isinstance(other, MyClass)) + tester.assertIsInstance(other, MyClass) return 12 try: monkeypatch(MyClass)(XXX()) except AttributeError, err: self.assertTrue(str(err).endswith('has no __name__ attribute: you should provide an explicit `methodname`')) monkeypatch(MyClass, 'foo')(XXX()) - self.assertTrue(isinstance(MyClass.prop1, property)) + self.assertIsInstance(MyClass.prop1, property) self.assertTrue(callable(MyClass.foo)) self.assertEqual(MyClass().prop1, 12) self.assertEqual(MyClass().foo(), 12) @@ -177,9 +177,9 @@ class DecoratorsTC(TestCase): foo = Foo() self.assertEqual(Foo.x, 0) - self.failIf('bar' in foo.__dict__) + self.assertFalse('bar' in foo.__dict__) self.assertEqual(foo.bar, 1) - self.failUnless('bar' in foo.__dict__) + self.assertTrue('bar' in foo.__dict__) self.assertEqual(foo.bar, 1) self.assertEqual(foo.quux, 42) self.assertEqual(Foo.bar.__doc__, diff --git a/test/unittest_fileutils.py b/test/unittest_fileutils.py index b7ffd71..927347d 100644 --- a/test/unittest_fileutils.py +++ b/test/unittest_fileutils.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -73,10 +73,10 @@ class ExportTC(TestCase): def test(self): export(DATA_DIR, self.tempdir, verbose=0) - self.assert_(exists(join(self.tempdir, '__init__.py'))) - self.assert_(exists(join(self.tempdir, 'sub'))) - self.assert_(not exists(join(self.tempdir, '__init__.pyc'))) - self.assert_(not exists(join(self.tempdir, 'CVS'))) + self.assertTrue(exists(join(self.tempdir, '__init__.py'))) + self.assertTrue(exists(join(self.tempdir, 'sub'))) + self.assertTrue(not exists(join(self.tempdir, '__init__.pyc'))) + self.assertTrue(not exists(join(self.tempdir, 'CVS'))) def tearDown(self): shutil.rmtree(self.tempdir) @@ -93,50 +93,52 @@ class ProtectedFileTC(TestCase): def test_mode_change(self): """tests that mode is changed when needed""" # test on non-writable file - #self.assert_(not os.access(self.rpath, os.W_OK)) - self.assert_(not os.stat(self.rpath).st_mode & S_IWRITE) + #self.assertTrue(not os.access(self.rpath, os.W_OK)) + self.assertTrue(not os.stat(self.rpath).st_mode & S_IWRITE) wp_file = ProtectedFile(self.rpath, 'w') - self.assert_(os.stat(self.rpath).st_mode & S_IWRITE) - self.assert_(os.access(self.rpath, os.W_OK)) + self.assertTrue(os.stat(self.rpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rpath, os.W_OK)) # test on writable-file - self.assert_(os.stat(self.rwpath).st_mode & S_IWRITE) - self.assert_(os.access(self.rwpath, os.W_OK)) + self.assertTrue(os.stat(self.rwpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rwpath, os.W_OK)) wp_file = ProtectedFile(self.rwpath, 'w') - self.assert_(os.stat(self.rwpath).st_mode & S_IWRITE) - self.assert_(os.access(self.rwpath, os.W_OK)) + self.assertTrue(os.stat(self.rwpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rwpath, os.W_OK)) def test_restore_on_close(self): """tests original mode is restored on close""" # test on non-writable file - #self.assert_(not os.access(self.rpath, os.W_OK)) - self.assert_(not os.stat(self.rpath).st_mode & S_IWRITE) + #self.assertTrue(not os.access(self.rpath, os.W_OK)) + self.assertTrue(not os.stat(self.rpath).st_mode & S_IWRITE) ProtectedFile(self.rpath, 'w').close() - #self.assert_(not os.access(self.rpath, os.W_OK)) - self.assert_(not os.stat(self.rpath).st_mode & S_IWRITE) + #self.assertTrue(not os.access(self.rpath, os.W_OK)) + self.assertTrue(not os.stat(self.rpath).st_mode & S_IWRITE) # test on writable-file - self.assert_(os.access(self.rwpath, os.W_OK)) - self.assert_(os.stat(self.rwpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rwpath, os.W_OK)) + self.assertTrue(os.stat(self.rwpath).st_mode & S_IWRITE) ProtectedFile(self.rwpath, 'w').close() - self.assert_(os.access(self.rwpath, os.W_OK)) - self.assert_(os.stat(self.rwpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rwpath, os.W_OK)) + self.assertTrue(os.stat(self.rwpath).st_mode & S_IWRITE) def test_mode_change_on_append(self): """tests that mode is changed when file is opened in 'a' mode""" - #self.assert_(not os.access(self.rpath, os.W_OK)) - self.assert_(not os.stat(self.rpath).st_mode & S_IWRITE) + #self.assertTrue(not os.access(self.rpath, os.W_OK)) + self.assertTrue(not os.stat(self.rpath).st_mode & S_IWRITE) wp_file = ProtectedFile(self.rpath, 'a') - self.assert_(os.access(self.rpath, os.W_OK)) - self.assert_(os.stat(self.rpath).st_mode & S_IWRITE) + self.assertTrue(os.access(self.rpath, os.W_OK)) + self.assertTrue(os.stat(self.rpath).st_mode & S_IWRITE) wp_file.close() - #self.assert_(not os.access(self.rpath, os.W_OK)) - self.assert_(not os.stat(self.rpath).st_mode & S_IWRITE) + #self.assertTrue(not os.access(self.rpath, os.W_OK)) + self.assertTrue(not os.stat(self.rpath).st_mode & S_IWRITE) from logilab.common.testlib import DocTest -class ModuleDocTest(DocTest): - """relative_path embed tests in docstring""" - from logilab.common import fileutils as module - skipped = ('abspath_listdir',) +if sys.version_info < (3, 0): + # skip if python3, test fail because of traceback display incompatibility :( + class ModuleDocTest(DocTest): + """relative_path embed tests in docstring""" + from logilab.common import fileutils as module + skipped = ('abspath_listdir',) del DocTest # necessary if we don't want it to be executed (we don't...) diff --git a/test/unittest_modutils.py b/test/unittest_modutils.py index 4fe2baf..2218da5 100644 --- a/test/unittest_modutils.py +++ b/test/unittest_modutils.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -128,6 +128,16 @@ class modpath_from_file_tc(ModutilsTestCase): self.assertRaises(Exception, modutils.modpath_from_file, '/turlututu') +class load_module_from_path_tc(ModutilsTestCase): + + def test_do_not_load_twice(self): + sys.path.insert(0, self.datadir) + foo = modutils.load_module_from_modpath(['lmfp', 'foo']) + lmfp = modutils.load_module_from_modpath(['lmfp']) + self.assertEqual(len(sys.just_once), 1) + sys.path.pop(0) + del sys.just_once + class file_from_modpath_tc(ModutilsTestCase): """given a mod path (i.e. splited module / package name), return the corresponding file, giving priority to source file over precompiled file @@ -175,7 +185,7 @@ class is_standard_module_tc(ModutilsTestCase): library """ - def test_knownValues_is_standard_module_0(self): + def test_knownValues_is_standard_module_builtins(self): if sys.version_info < (3, 0): self.assertEqual(modutils.is_standard_module('__builtin__'), True) self.assertEqual(modutils.is_standard_module('builtins'), False) @@ -183,30 +193,27 @@ class is_standard_module_tc(ModutilsTestCase): self.assertEqual(modutils.is_standard_module('__builtin__'), False) self.assertEqual(modutils.is_standard_module('builtins'), True) - def test_knownValues_is_standard_module_1(self): + def test_knownValues_is_standard_module_builtin(self): self.assertEqual(modutils.is_standard_module('sys'), True) - def test_knownValues_is_standard_module_2(self): + def test_knownValues_is_standard_module_nonstandard(self): self.assertEqual(modutils.is_standard_module('logilab'), False) - def test_knownValues_is_standard_module_3(self): + def test_knownValues_is_standard_module_unknown(self): self.assertEqual(modutils.is_standard_module('unknown'), False) def test_knownValues_is_standard_module_4(self): - if sys.version_info < (3, 0): - self.assertEqual(modutils.is_standard_module('StringIO'), True) - else: - self.assertEqual(modutils.is_standard_module('StringIO'), False) - if sys.version_info < (2, 6): - self.assertEqual(modutils.is_standard_module('io'), False) - else: - self.assertEqual(modutils.is_standard_module('io'), True) - - def test_knownValues_is_standard_module_5(self): + self.assertEqual(modutils.is_standard_module('marshal'), True) + self.assertEqual(modutils.is_standard_module('hashlib'), True) + self.assertEqual(modutils.is_standard_module('pickle'), True) + self.assertEqual(modutils.is_standard_module('email'), True) + self.assertEqual(modutils.is_standard_module('io'), sys.version_info >= (2, 6)) + self.assertEqual(modutils.is_standard_module('StringIO'), sys.version_info < (3, 0)) + + def test_knownValues_is_standard_module_custom_path(self): self.assertEqual(modutils.is_standard_module('data.module', (DATADIR,)), True) self.assertEqual(modutils.is_standard_module('data.module', (path.abspath(DATADIR),)), True) - class is_relative_tc(ModutilsTestCase): @@ -253,9 +260,9 @@ class get_modules_files_tc(ModutilsTestCase): del logilab.common.fileutils del sys.modules['logilab.common.fileutils'] m = modutils.load_module_from_modpath(['logilab', 'common', 'fileutils']) - self.assert_( hasattr(logilab, 'common') ) - self.assert_( hasattr(logilab.common, 'fileutils') ) - self.assert_( m is logilab.common.fileutils ) + self.assertTrue( hasattr(logilab, 'common') ) + self.assertTrue( hasattr(logilab.common, 'fileutils') ) + self.assertTrue( m is logilab.common.fileutils ) from logilab.common.testlib import DocTest class ModuleDocTest(DocTest): diff --git a/test/unittest_shellutils.py b/test/unittest_shellutils.py index fb9e1ca..d883c08 100644 --- a/test/unittest_shellutils.py +++ b/test/unittest_shellutils.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -117,7 +117,7 @@ class ProgressBarTC(TestCase): pgb.update() if update or (update is None and dots != last): last = dots - expected_stream.write("\r["+('.'*dots)+(' '*(size-dots))+"]") + expected_stream.write("\r["+('='*dots)+(' '*(size-dots))+"]") self.assertEqual(pgb_stream.getvalue(), expected_stream.getvalue()) def test_default(self): @@ -152,10 +152,10 @@ class ProgressBarTC(TestCase): last = 0 for dots in xrange(10, 105, 15): pgb.update(dots, exact=True) - dots /= 5 - expected_stream.write("\r["+('.'*dots)+(' '*(size-dots))+"]") + dots //= 5 + expected_stream.write("\r["+('='*dots)+(' '*(size-dots))+"]") self.assertEqual(pgb_stream.getvalue(), expected_stream.getvalue()) - + def test_update_relative(self): pgb_stream = StringIO() expected_stream = StringIO() @@ -164,8 +164,8 @@ class ProgressBarTC(TestCase): last = 0 for dots in xrange(5, 105, 5): pgb.update(5, exact=False) - dots /= 5 - expected_stream.write("\r["+('.'*dots)+(' '*(size-dots))+"]") + dots //= 5 + expected_stream.write("\r["+('='*dots)+(' '*(size-dots))+"]") self.assertEqual(pgb_stream.getvalue(), expected_stream.getvalue()) diff --git a/test/unittest_table.py b/test/unittest_table.py index 57fea86..d2db8b7 100644 --- a/test/unittest_table.py +++ b/test/unittest_table.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -65,14 +65,14 @@ class TableTC(TestCase): def test_indexation(self): """we should be able to use [] to access rows""" - self.assert_(self.table[0] == self.table.data[0]) - self.assert_(self.table[1] == self.table.data[1]) + self.assertTrue(self.table[0] == self.table.data[0]) + self.assertTrue(self.table[1] == self.table.data[1]) def test_iterable(self): """test iter(table)""" it = iter(self.table) - self.assert_(it.next() == self.table.data[0]) - self.assert_(it.next() == self.table.data[1]) + self.assertTrue(it.next() == self.table.data[0]) + self.assertTrue(it.next() == self.table.data[1]) def test_get_rows(self): """tests Table.get_rows()""" @@ -308,7 +308,7 @@ class TableStyleSheetTC(TestCase): self.stylesheet.add_rowavg_rule((0, 2), 0, 0, 1) self.table.apply_stylesheet(self.stylesheet) val = self.table[0, 2] - self.assert_(int(val) == 15) + self.assertTrue(int(val) == 15) def test_rowsum_rule(self): @@ -318,7 +318,7 @@ class TableStyleSheetTC(TestCase): self.stylesheet.add_rowsum_rule((0, 2), 0, 0, 1) self.table.apply_stylesheet(self.stylesheet) val = self.table[0, 2] - self.assert_(val == 30) + self.assertTrue(val == 30) def test_colavg_rule(self): @@ -330,7 +330,7 @@ class TableStyleSheetTC(TestCase): self.stylesheet.add_colavg_rule((2, 0), 0, 0, 1) self.table.apply_stylesheet(self.stylesheet) val = self.table[2, 0] - self.assert_(int(val) == 11) + self.assertTrue(int(val) == 11) def test_colsum_rule(self): @@ -342,7 +342,7 @@ class TableStyleSheetTC(TestCase): self.stylesheet.add_colsum_rule((2, 0), 0, 0, 1) self.table.apply_stylesheet(self.stylesheet) val = self.table[2, 0] - self.assert_(val == 22) + self.assertTrue(val == 22) diff --git a/test/unittest_testlib.py b/test/unittest_testlib.py index dad561a..4ea8242 100644 --- a/test/unittest_testlib.py +++ b/test/unittest_testlib.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -121,29 +121,6 @@ class TestlibTC(TestCase): invalid = """<root><h2 </h2> </root>""" self.assertRaises(AssertionError, self.tc.assertXMLStringWellFormed, invalid) - def test_unordered_equality_for_lists(self): - l1 = [0, 1, 2] - l2 = [1, 2, 3] - self.assertRaises(AssertionError, self.tc.assertItemsEqual, l1, l2) - self.assertRaises(AssertionError, self.tc.assertItemsEqual, l1, l2) - self.tc.assertItemsEqual(l1, l1) - self.tc.assertItemsEqual(l1, l1) - self.tc.assertItemsEqual([], []) - self.tc.assertItemsEqual([], []) - l1 = [0, 1, 1] - l2 = [0, 1] - self.assertRaises(AssertionError, self.tc.assertItemsEqual, l1, l2) - self.assertRaises(AssertionError, self.tc.assertItemsEqual, l1, l2) - self.tc.assertItemsEqual(l1, l1) - self.tc.assertItemsEqual(l1, l1) - - def test_unordered_equality_for_dicts(self): - d1 = {'a' : 1, 'b' : 2} - d2 = {'a' : 1} - self.assertRaises(AssertionError, self.tc.assertItemsEqual, d1, d2) - self.tc.assertItemsEqual(d1, d1) - self.tc.assertItemsEqual({}, {}) - def test_equality_for_sets(self): s1 = set('ab') s2 = set('a') @@ -151,14 +128,6 @@ class TestlibTC(TestCase): self.tc.assertSetEqual(s1, s1) self.tc.assertSetEqual(set(), set()) - def test_unordered_equality_for_iterables(self): - self.assertRaises(AssertionError, self.tc.assertItemsEqual, xrange(5), xrange(6)) - self.assertRaises(AssertionError, self.tc.assertItemsEqual, xrange(5), xrange(6)) - self.tc.assertItemsEqual(xrange(5), range(5)) - self.tc.assertItemsEqual(xrange(5), range(5)) - self.tc.assertItemsEqual([], ()) - self.tc.assertItemsEqual([], ()) - def test_file_equality(self): foo = join(dirname(__file__), 'data', 'foo.txt') spam = join(dirname(__file__), 'data', 'spam.txt') @@ -235,10 +204,6 @@ class TestlibTC(TestCase): # class' custom datadir tc = MyTC('test_1') self.assertEqual(tc.datapath('bar'), join('foo', 'bar')) - # instance's custom datadir - self.skipTest('should this really work?') - tc.datadir = 'spam' - self.assertEqual(tc.datapath('bar'), join('spam', 'bar')) def test_cached_datadir(self): """test datadir is cached on the class""" @@ -788,6 +753,9 @@ class TagTC(TestCase): self.assertTrue(tags.match('other or (testing and bob)')) def test_tagged_class(self): + if sys.version_info > (3, 0): + self.skipTest('fix me for py3k') + def options(tags): class Options(object): tags_pattern = tags diff --git a/test/unittest_umessage.py b/test/unittest_umessage.py index 2d14a26..6bf56c6 100644 --- a/test/unittest_umessage.py +++ b/test/unittest_umessage.py @@ -1,5 +1,5 @@ # encoding: iso-8859-15 -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -53,9 +53,11 @@ import warnings from shutil import rmtree from operator import itemgetter from ConfigParser import ConfigParser -from logilab.common.deprecation import deprecated from itertools import dropwhile +from logilab.common.deprecation import deprecated +from logilab.common.compat import builtins + import unittest as unittest_legacy if not getattr(unittest_legacy, "__package__", None): try: @@ -950,7 +952,7 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) def assertTextEquals(self, text1, text2, junk=None, msg_prefix='Text differ', striplines=False): """compare two multiline strings (using difflib and splitlines()) - + :param text1: a Python BaseString :param text2: a second Python Basestring :param junk: List of Caracters @@ -1022,7 +1024,7 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) partial_iter = True - self.assert_(ipath_a == ipath_b, + self.assertTrue(ipath_a == ipath_b, "unexpected %s in %s while looking %s from %s" % (ipath_a, path_a, ipath_b, path_b)) @@ -1080,9 +1082,9 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) msg = '%r is not an instance of %s but of %s' msg = msg % (obj, klass, type(obj)) if strict: - self.assert_(obj.__class__ is klass, msg) + self.assertTrue(obj.__class__ is klass, msg) else: - self.assert_(isinstance(obj, klass), msg) + self.assertTrue(isinstance(obj, klass), msg) @deprecated('Please use assertIsNone instead.') def assertNone(self, obj, msg=None): @@ -1092,14 +1094,14 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) """ if msg is None: msg = "reference to %r when None expected"%(obj,) - self.assert_( obj is None, msg ) + self.assertTrue( obj is None, msg ) @deprecated('Please use assertIsNotNone instead.') def assertNotNone(self, obj, msg=None): """assert obj is not None""" if msg is None: msg = "unexpected reference to None" - self.assert_( obj is not None, msg ) + self.assertTrue( obj is not None, msg ) @deprecated('Non-standard. Please use assertAlmostEqual instead.') def assertFloatAlmostEquals(self, obj, other, prec=1e-5, @@ -1117,7 +1119,7 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) msg = "%r != %r" % (obj, other) if relative: prec = prec*math.fabs(obj) - self.assert_(math.fabs(obj - other) < prec, msg) + self.assertTrue(math.fabs(obj - other) < prec, msg) def failUnlessRaises(self, excClass, callableObj=None, *args, **kwargs): """override default failUnlessRaises method to return the raised @@ -1166,6 +1168,10 @@ succeeded test into", osp.join(os.getcwd(), FILE_RESTART) assertRaises = failUnlessRaises + if not hasattr(unittest.TestCase, 'assertItemsEqual'): + # python 3.2 has deprecated assertSameElements and is missing + # assertItemsEqual + assertItemsEqual = unittest.TestCase.assertSameElements import doctest @@ -1216,12 +1222,12 @@ class DocTest(TestCase): suite = SkippedSuite() # doctest may gork the builtins dictionnary # This happen to the "_" entry used by gettext - old_builtins = __builtins__.copy() + old_builtins = builtins.__dict__.copy() try: return suite.run(result) finally: - __builtins__.clear() - __builtins__.update(old_builtins) + builtins.__dict__.clear() + builtins.__dict__.update(old_builtins) run = __call__ def test(self): diff --git a/umessage.py b/umessage.py index 85d564c..c597c17 100644 --- a/umessage.py +++ b/umessage.py @@ -1,4 +1,4 @@ -# copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved. +# copyright 2003-2012 LOGILAB S.A. (Paris, FRANCE), all rights reserved. # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr # # This file is part of logilab-common. @@ -15,12 +15,8 @@ # # You should have received a copy of the GNU Lesser General Public License along # with logilab-common. If not, see <http://www.gnu.org/licenses/>. -"""Unicode email support (extends email from stdlib). +"""Unicode email support (extends email from stdlib)""" - - - -""" __docformat__ = "restructuredtext en" import email @@ -79,27 +75,13 @@ class UMessage: return decode_QP(value) return value + def __getitem__(self, header): + return self.get(header) + def get_all(self, header, default=()): return [decode_QP(val) for val in self.message.get_all(header, default) if val is not None] - def get_payload(self, index=None, decode=False): - message = self.message - if index is None: - payload = message.get_payload(index, decode) - if isinstance(payload, list): - return [UMessage(msg) for msg in payload] - if message.get_content_maintype() != 'text': - return payload - - charset = message.get_content_charset() or 'iso-8859-1' - if search_function(charset) is None: - charset = 'iso-8859-1' - return unicode(payload or '', charset, "replace") - else: - payload = UMessage(message.get_payload(index, decode)) - return payload - def is_multipart(self): return self.message.is_multipart() @@ -110,20 +92,61 @@ class UMessage: for part in self.message.walk(): yield UMessage(part) - def get_content_maintype(self): - return unicode(self.message.get_content_maintype()) + if sys.version_info < (3, 0): + + def get_payload(self, index=None, decode=False): + message = self.message + if index is None: + payload = message.get_payload(index, decode) + if isinstance(payload, list): + return [UMessage(msg) for msg in payload] + if message.get_content_maintype() != 'text': + return payload + + charset = message.get_content_charset() or 'iso-8859-1' + if search_function(charset) is None: + charset = 'iso-8859-1' + return unicode(payload or '', charset, "replace") + else: + payload = UMessage(message.get_payload(index, decode)) + return payload + + def get_content_maintype(self): + return unicode(self.message.get_content_maintype()) + + def get_content_type(self): + return unicode(self.message.get_content_type()) + + def get_filename(self, failobj=None): + value = self.message.get_filename(failobj) + if value is failobj: + return value + try: + return unicode(value) + except UnicodeDecodeError: + return u'error decoding filename' + + else: + + def get_payload(self, index=None, decode=False): + message = self.message + if index is None: + payload = message.get_payload(index, decode) + if isinstance(payload, list): + return [UMessage(msg) for msg in payload] + return payload + else: + payload = UMessage(message.get_payload(index, decode)) + return payload + + def get_content_maintype(self): + return self.message.get_content_maintype() - def get_content_type(self): - return unicode(self.message.get_content_type()) + def get_content_type(self): + return self.message.get_content_type() - def get_filename(self, failobj=None): - value = self.message.get_filename(failobj) - if value is failobj: - return value - try: - return unicode(value) - except UnicodeDecodeError: - return u'error decoding filename' + def get_filename(self, failobj=None): + return self.message.get_filename(failobj) # other convenience methods ############################################### |