diff options
author | Alexandre Fayolle <alexandre.fayolle@logilab.fr> | 2008-05-07 13:46:01 +0200 |
---|---|---|
committer | Alexandre Fayolle <alexandre.fayolle@logilab.fr> | 2008-05-07 13:46:01 +0200 |
commit | 0b84587cfd9a8e042ada3f32e2eac903601d467a (patch) | |
tree | 5079d027d524916630737206a409dea92fe6394b | |
parent | e26e5f5b7f10de0408bbf1fecf0d96701811f742 (diff) | |
parent | 904d11f3f7e8cc158c97eae1a6b6399821dd69be (diff) | |
download | logilab-common-0b84587cfd9a8e042ada3f32e2eac903601d467a.tar.gz |
merge
-rw-r--r-- | README | 78 | ||||
-rw-r--r-- | astutils.py | 2 | ||||
-rw-r--r-- | cache.py | 4 | ||||
-rw-r--r-- | clcommands.py | 1 | ||||
-rw-r--r-- | compat.py | 4 | ||||
-rw-r--r-- | logger.py | 2 | ||||
-rw-r--r-- | optparser.py | 2 | ||||
-rw-r--r-- | pdf_ext.py | 3 | ||||
-rw-r--r-- | test/unittest_cache.py | 59 | ||||
-rw-r--r-- | testlib.py | 42 |
10 files changed, 140 insertions, 57 deletions
@@ -30,26 +30,35 @@ Provided modules Here is a brief description of the available modules : +* adbh.py: + helper functions for using database advanced. Supported RDBMS +include PostgreSQL, MySQL and sqlite. See also db.py. + * astutils: - Some utilities function to manipulate Python's AST. + Deprecated module. Use logilab.astng. * bind.py : + Deprecated module. Provides a way to optimize globals in certain functions by binding their names to values provided in a dictionnary. * cache.py : A cache implementation with a least recently used algorithm. +* clcommands.py: + helper functions for command line programs handling different + subcommands + * cli.py : - Command line interface helper classes. + Command line interface helper classes (for interactive programs + using the command line) * compat.py: Transparent compatibility layer between different python version - (actually 2.2 vs 2.3 for now) * configuration.py : Two mix-in classes to handle configuration from both command line - (using optik) and configuration file. + (using optik/optparse) and configuration file. * corbautils.py: Usefull functions for use with the OmniORB CORBA library. @@ -57,50 +66,95 @@ Here is a brief description of the available modules : * daemon.py : A daemon mix-in class. +* date.py: + date manipulation helper functions + * db.py : - A generic method to get a database connection. + A generic method to get a database connection. See also adbh.py. -* html.py : - Return an html formatted traceback from python exception infos. +* debugger.py: + pdb customization + +* decorators.py: + useful decorators (cached, timed...) + +* deprecation.py: + mark functions / classes as deprecated or moved * fileutils.py : Some file / file path manipulation utilities. +* graph.py: + graph manipulations, dot file generation + +* html.py : + Deprecated module + Return an html formatted traceback from python exception infos. + * interface.py Bases class for interfaces. * logger.py : + Deprecated module : use logging from stdlib. Define a logger interface and two concrete loggers : one which prints everything on stdout, the other using syslog. +* logging_ext.py: + extensions to stdlib's logging module + +* logservice.py: + Deprecated module. Use logging from stdlib. + * modutils.py : Module manipulation utilities. +* monclient.py: + Deprecated module + +* monserver.py: + Deprecated module + * optik_ext : Add an abstraction level to transparently import optik classes from optparse (python >= 2.3) or the optik package. It also defines two - new option types : regexp and csv. + new option types (regexp, csv, color, date...) + +* optparser.py: + extend optparse's OptionParser to support commands * patricia.py : A Python implementation of PATRICIA trie (Practical Algorithm to Retrieve Information Coded in Alphanumeric). -* shellutils: +* pdf_ext.py: + pdf and fdf file manipulations, with pdftk. + +* pytest.py: + unittest runner. See testlib + +* shellutils.py: Some utilities to replace shell scripts with python scripts. * sqlgen.py : Helper class to generate SQL strings to use with python's DB-API. +* table.py: + manage tabular data (supports column and row names, sorting, grouping... + * testlib.py : Generic tests execution methods. * textutils.py: - Some text manipulation utilities. + Some text manipulation utilities (ansi colorization, line wrapping, + rest support...) * tree.py : Base class to represent tree structure, and some others to make it works with the visitor implementation (see below). +* umessage.py: + unicode email support + * ureports: Provides a way to create simple reports using python objects without care of the final formatting. Some formatters text and html @@ -118,12 +172,14 @@ Here is a brief description of the available modules : distutils syntax. Note that you can use this to install files that are not twisted plugins in any package directory of your application. +* xmlrpcutils.py: + Auth support for XML RPC Comments, support, bug reports ------------------------------ Use the python-projects@logilab.org mailing list. Since we do not have publicly available bug tracker yet, bug reports should be emailed -there too. +there too. You can subscribe to this mailing list at http://www.logilab.org/mailinglists/python_projects/mailinglist_register_form diff --git a/astutils.py b/astutils.py index 1a14106..a6e1c32 100644 --- a/astutils.py +++ b/astutils.py @@ -18,7 +18,7 @@ from warnings import warn warn('this module has been moved into logilab.astng and will disappear from \ -logilab.common in a near release', +logilab.common in a future release', DeprecationWarning, stacklevel=1) __author__ = u"Sylvain Thenault" @@ -46,7 +46,7 @@ class Cache: if not self._usage: self._usage.append(key) - if self._usage[-1] != key: + elif self._usage[-1] != key: try: self._usage.remove(key) except ValueError: @@ -57,6 +57,8 @@ class Cache: del self.data[self._usage[0]] del self._usage[0] self._usage.append(key) + else: + pass # key is already the most recently used key def __getitem__(self, key): diff --git a/clcommands.py b/clcommands.py index d3ebbe6..8b1adec 100644 --- a/clcommands.py +++ b/clcommands.py @@ -20,6 +20,7 @@ command'specific :contact: http://www.logilab.fr/ -- mailto:python-projects@logilab.org """ +# XXX : merge with optparser ? import sys from os.path import basename @@ -15,8 +15,8 @@ # You should have received a copy of the GNU General Public License along with # this program; if not, write to the Free Software Foundation, Inc., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -"""some wrapper around tools introduced into python 2.3, making them available -in python 2.2 +"""some wrapper around some builtins introduced in python 2.3, 2.4 and +2.5, making them available in for earlier versions of python. """ from __future__ import generators @@ -18,7 +18,7 @@ everything on stdout, the other using syslog. """ from warnings import warn -warn('logger module is deprecated and will disappear in a near release. \ +warn('logger module is deprecated and will disappear in a future release. \ use logging module instead.', DeprecationWarning, stacklevel=1) diff --git a/optparser.py b/optparser.py index 6ae42a9..3461ce5 100644 --- a/optparser.py +++ b/optparser.py @@ -28,7 +28,7 @@ Example: With mymod.build that defines two functions run and add_options """ -# XXX merge with optik_ext ? +# XXX merge with optik_ext ? merge with clcommands ? import sys import optparse @@ -23,6 +23,9 @@ to merge fdf and pdf: without flatten, one could further edit the resulting form. with flatten, everything is turned into text. """ +# XXX seems very unix specific +# TODO: check availability of pdftk at import + import os diff --git a/test/unittest_cache.py b/test/unittest_cache.py index c2a5b29..dfc9315 100644 --- a/test/unittest_cache.py +++ b/test/unittest_cache.py @@ -11,28 +11,36 @@ class CacheTestCase(TestCase): def test_setitem1(self): """Checks that the setitem method works""" self.cache[1] = 'foo' - self.assert_(self.cache.data[1] == 'foo',"1 : 'foo' is not in cache.data") - self.assert_(len(self.cache._usage) == 1, "lenght of usage list is not 1") - self.assert_(self.cache._usage[-1] == 1, '1 is not the most recently used key') - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assertEqual(self.cache.data[1], 'foo', "1:foo is not in cache") + self.assertEqual(len(self.cache._usage), 1) + self.assertEqual(self.cache._usage[-1], 1, + '1 is not the most recently used key') + self.assertSetEqual(self.cache._usage, + self.cache.data.keys(), + "usage list and data keys are different") def test_setitem2(self): """Checks that the setitem method works for multiple items""" self.cache[1] = 'foo' self.cache[2] = 'bar' - self.assert_(self.cache.data[2] == 'bar',"2 : 'bar' is not in cache.data") - self.assert_(len(self.cache._usage) == 2, "lenght of usage list is not 2") - self.assert_(self.cache._usage[-1] == 2, '1 is not the most recently used key') - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assertEqual(self.cache.data[2], 'bar', + "2 : 'bar' is not in cache.data") + self.assertEqual(len(self.cache._usage), 2, + "lenght of usage list is not 2") + self.assertEqual(self.cache._usage[-1], 2, + '1 is not the most recently used key') + self.assertSetEqual(self.cache._usage, + self.cache.data.keys())# usage list and data keys are different def test_setitem3(self): """Checks that the setitem method works when replacing an element in the cache""" self.cache[1] = 'foo' self.cache[1] = 'bar' - self.assert_(self.cache.data[1] == 'bar',"1 : 'bar' is not in cache.data") - self.assert_(len(self.cache._usage) == 1, "lenght of usage list is not 1") - self.assert_(self.cache._usage[-1] == 1, '1 is not the most recently used key') - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assertEqual(self.cache.data[1], 'bar', "1 : 'bar' is not in cache.data") + self.assertEqual(len(self.cache._usage), 1, "lenght of usage list is not 1") + self.assertEqual(self.cache._usage[-1], 1, '1 is not the most recently used key') + self.assertSetEqual(self.cache._usage, + self.cache.data.keys())# usage list and data keys are different def test_recycling1(self): """Checks the removal of old elements""" @@ -42,11 +50,14 @@ class CacheTestCase(TestCase): self.cache[4] = 'foz' self.cache[5] = 'fuz' self.cache[6] = 'spam' - self.assert_(not self.cache.data.has_key(1), 'key 1 has not been suppressed from the cache dictionnary') - self.assert_(1 not in self.cache._usage, 'key 1 has not been suppressed from the cache LRU list') - self.assert_(len(self.cache._usage) == 5, "lenght of usage list is not 5") - self.assert_(self.cache._usage[-1] == 6, '6 is not the most recently used key') - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assert_(not self.cache.data.has_key(1), + 'key 1 has not been suppressed from the cache dictionnary') + self.assert_(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') + self.assertSetEqual(self.cache._usage, + self.cache.data.keys())# usage list and data keys are different def test_recycling2(self): """Checks that accessed elements get in the front of the list""" @@ -55,9 +66,10 @@ class CacheTestCase(TestCase): self.cache[3] = 'baz' self.cache[4] = 'foz' a = self.cache[1] - self.assert_(a == 'foo') - self.assert_(self.cache._usage[-1] == 1, '1 is not the most recently used key') - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assertEqual(a, 'foo') + self.assertEqual(self.cache._usage[-1], 1, '1 is not the most recently used key') + self.assertSetEqual(self.cache._usage, + self.cache.data.keys())# usage list and data keys are different def test_delitem(self): """Checks that elements are removed from both element dict and element @@ -67,7 +79,8 @@ class CacheTestCase(TestCase): del self.cache['foo'] self.assert_('foo' not in self.cache.data.keys(),"Element 'foo' was not removed cache dictionnary") self.assert_('foo' not in self.cache._usage,"Element 'foo' was not removed usage list") - self.assert_(self.cache._usage.sort() == self.cache.data.keys().sort(), "usage list and data keys are different") + self.assertSetEqual(self.cache._usage, + self.cache.data.keys())# usage list and data keys are different def test_nullsize(self): @@ -75,9 +88,9 @@ class CacheTestCase(TestCase): """ null_cache = Cache(0) null_cache['foo'] = 'bar' - self.assert_(null_cache.size == 0, 'Cache size should be O, not %d' % \ + self.assertEqual(null_cache.size, 0, 'Cache size should be O, not %d' % \ null_cache.size) - self.assert_(len(null_cache) == 0, 'Cache should be empty !') + self.assertEqual(len(null_cache), 0, 'Cache should be empty !') # Assert null_cache['foo'] raises a KeyError self.assertRaises(KeyError, null_cache.__getitem__, 'foo') # Deleting element should not raise error @@ -427,7 +427,6 @@ class SkipAwareTextTestRunner(unittest.TextTestRunner): self.cvg = cvg self.test_pattern = test_pattern self.skipped_patterns = skipped_patterns - self.options = options def _this_is_skipped(self, testedname): return any([(pat in testedname) for pat in self.skipped_patterns]) @@ -884,7 +883,6 @@ class TestCase(unittest.TestCase): self._out = [] self._err = [] self._current_test_descr = None - self._options_ = None def datadir(cls): """helper attribute holding the standard test's data directory @@ -969,7 +967,6 @@ class TestCase(unittest.TestCase): def _get_test_method(self): return getattr(self, self.__testMethodName) - def optval(self, option, default=None): return getattr(self._options_, option, default) @@ -1100,19 +1097,25 @@ class TestCase(unittest.TestCase): self.fail('\n'.join(msgs)) assertDictEqual = assertDictEquals - def assertSetEquals(self, got, expected): + def assertSetEquals(self, got, expected, msg=None): """compares two iterables and shows difference between both""" got, expected = list(got), list(expected) - self.assertEquals(len(got), len(expected), '%s != %s' % (got, expected)) + if msg is None: + msg1 = '%s != %s' % (got, expected) + else: + msg1 = msg + self.assertEquals(len(got), len(expected), msg1) got, expected = set(got), set(expected) if got != expected: missing = expected - got unexpected = got - expected - self.fail('\tunexepected: %s\n\tmissing: %s' % (unexpected, - missing)) + if msg is None: + msg = '\tunexepected: %s\n\tmissing: %s' % (unexpected, + missing) + self.fail(msg) assertSetEqual = assertSetEquals - def assertListEquals(self, l1, l2): + def assertListEquals(self, l1, l2, msg=None): """compares two lists If the two list differ, the first difference is shown in the error @@ -1128,32 +1131,37 @@ class TestCase(unittest.TestCase): self.fail('%r != %r for index %d' % (_l1[0], value, i)) del _l1[0] except IndexError: - msg = 'l1 has only %d elements, not %s (at least %r missing)' - self.fail(msg % (i, len(l2), value)) + if msg is None: + msg = 'l1 has only %d elements, not %s (at least %r missing)'% (i, len(l2), value) + self.fail(msg) if _l1: - self.fail('l2 is lacking %r' % _l1) + if msg is None: + msg = 'l2 is lacking %r' % _l1 + self.fail(msg) assertListEqual = assertListEquals - def assertLinesEquals(self, l1, l2): + def assertLinesEquals(self, l1, l2, msg=None): """assert list of lines are equal""" - self.assertListEquals(l1.splitlines(), l2.splitlines()) + self.assertListEquals(l1.splitlines(), l2.splitlines(), msg) assertLineEqual = assertLinesEquals - def assertXMLWellFormed(self, stream): + def assertXMLWellFormed(self, stream, msg=None): """asserts the XML stream is well-formed (no DTD conformance check)""" from xml.sax import make_parser, SAXParseException parser = make_parser() try: parser.parse(stream) except SAXParseException: - self.fail('XML stream not well formed') + if msg is None: + msg = 'XML stream not well formed' + self.fail(msg) assertXMLValid = deprecated_function(assertXMLWellFormed, 'assertXMLValid renamed to more precise assertXMLWellFormed') - def assertXMLStringWellFormed(self, xml_string): + def assertXMLStringWellFormed(self, xml_string, msg=None): """asserts the XML string is well-formed (no DTD conformance check)""" stream = StringIO(xml_string) - self.assertXMLWellFormed(stream) + self.assertXMLWellFormed(stream, msg) assertXMLStringValid = deprecated_function( assertXMLStringWellFormed, 'assertXMLStringValid renamed to more precise assertXMLStringWellFormed') |