summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSylvain Th?nault <sylvain.thenault@logilab.fr>2009-11-23 14:45:11 +0100
committerSylvain Th?nault <sylvain.thenault@logilab.fr>2009-11-23 14:45:11 +0100
commit57b10e1b76dd3bd3c834bacd338076de6e35cabe (patch)
tree3f59f0a76e5bcb0bd760b37edac7b2fe906a2473
parentb7e84e3fc5418641041f95a80f08fe053c004c27 (diff)
parent1b4d12cbd2ab6e6e586743df592648faa42fa26e (diff)
downloadlogilab-common-57b10e1b76dd3bd3c834bacd338076de6e35cabe.tar.gz
-rw-r--r--ChangeLog2
-rw-r--r--db.py35
-rw-r--r--debugger.py9
-rw-r--r--graph.py6
-rw-r--r--pyro_ext.py3
-rw-r--r--pytest.py13
-rw-r--r--shellutils.py15
-rw-r--r--test/unittest_db.py11
-rw-r--r--test/unittest_graph.py18
-rw-r--r--test/unittest_testlib.py57
-rw-r--r--testlib.py9
11 files changed, 144 insertions, 34 deletions
diff --git a/ChangeLog b/ChangeLog
index 67ebb61..116160f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6,6 +6,8 @@ ChangeLog for logilab.common
- proper bytes and time option types support
- make Method usable as 'callback' value
- fix #8849 Using plugins, options and .pylintrc crashes PyLint
+ * graph: fix has_path returned value to include the destination node, else we get
+ an empty list which makes think there is no path (test added)
2009-08-26 -- 0.45.0
* added function for parsing XML processing instructions
diff --git a/db.py b/db.py
index 79a3abb..ba9109f 100644
--- a/db.py
+++ b/db.py
@@ -410,14 +410,45 @@ class _PySqlite2Adapter(DBAPIAdapter):
sqlite.register_converter('time', convert_mxtime)
# else use datetime.datetime
else:
- from datetime import time
+ from datetime import time, timedelta
+ # datetime.time
def adapt_time(data):
return data.strftime('%H:%M:%S')
sqlite.register_adapter(time, adapt_time)
def convert_time(data):
return time(*[int(i) for i in data.split(':')])
sqlite.register_converter('time', convert_time)
-
+ # datetime.timedelta
+ def adapt_timedelta(data):
+ '''the sign in the result only refers to the number of days. day
+ fractions always indicate a positive offset. this may seem strange,
+ but it is the same that is done by the default __str__ method. we
+ redefine it here anyways (instead of simply doing "str") because we
+ do not want any "days," string within the representation.
+ '''
+ days = data.days
+ frac = data - timedelta(days)
+ return "%d %s" % (data.days, frac)
+ sqlite.register_adapter(timedelta, adapt_timedelta)
+ def convert_timedelta(data):
+ parts = data.split(" ")
+ if len(parts) == 2:
+ daypart, timepart = parts
+ days = int(daypart)
+ else:
+ days = 0
+ timepart = parts[-1]
+ timepart_full = timepart.split(".")
+ hours, minutes, seconds = map(int, timepart_full[0].split(":"))
+ if len(timepart_full) == 2:
+ microseconds = int(float("0." + timepart_full[1]) * 1000000)
+ else:
+ microseconds = 0
+ data = timedelta(days,
+ hours*3600 + minutes*60 + seconds,
+ microseconds)
+ return data
+ sqlite.register_converter('interval', convert_timedelta)
def connect(self, host='', database='', user='', password='', port=None):
diff --git a/debugger.py b/debugger.py
index 53a7bd9..96e6a52 100644
--- a/debugger.py
+++ b/debugger.py
@@ -74,11 +74,12 @@ class Debugger(Pdb):
- overrides list command to search for current block instead
of using 5 lines of context
"""
- def __init__(self, tcbk):
+ def __init__(self, tcbk=None):
Pdb.__init__(self)
self.reset()
- while tcbk.tb_next is not None:
- tcbk = tcbk.tb_next
+ if tcbk:
+ while tcbk.tb_next is not None:
+ tcbk = tcbk.tb_next
self._tcbk = tcbk
self._histfile = osp.join(os.environ["HOME"], ".pdbhist")
@@ -187,3 +188,5 @@ def pm():
dbg = Debugger(sys.last_traceback)
dbg.start()
+def set_trace():
+ Debugger().set_trace(sys._getframe().f_back)
diff --git a/graph.py b/graph.py
index 573a1ba..ddd5abd 100644
--- a/graph.py
+++ b/graph.py
@@ -189,16 +189,16 @@ def has_path(graph_dict, fromnode, tonode, path=None):
node has key associated to a list of nodes directly reachable from it.
Return None if no path exists to go from `fromnode` to `tonode`, else the
- first path found
+ first path found (as a list including the destination node at last)
"""
if path is None:
path = []
elif fromnode in path:
- return False
+ return None
path.append(fromnode)
for destnode in graph_dict[fromnode]:
if destnode == tonode or has_path(graph_dict, destnode, tonode, path):
- return path[1:]
+ return path[1:] + [tonode]
path.pop()
return None
diff --git a/pyro_ext.py b/pyro_ext.py
index a531188..e7915c6 100644
--- a/pyro_ext.py
+++ b/pyro_ext.py
@@ -14,12 +14,15 @@ Main functions available:
__docformat__ = "restructuredtext en"
import logging
+import tempfile
from Pyro import core, naming, errors, util, config
_LOGGER = logging.getLogger('pyro')
_MARKER = object()
+config.PYRO_STORAGE = tempfile.gettempdir()
+
def ns_group_and_id(idstr, defaultnsgroup=_MARKER):
try:
nsgroup, nsid = idstr.rsplit('.', 1)
diff --git a/pytest.py b/pytest.py
index e61cfb4..6e1f432 100644
--- a/pytest.py
+++ b/pytest.py
@@ -725,17 +725,10 @@ def run():
import traceback
traceback.print_exc()
finally:
- tester.show_report()
if covermode:
cvg.stop()
cvg.save()
- here = osp.abspath(os.getcwd())
- if this_is_a_testdir(here):
- morfdir = osp.normpath(osp.join(here, '..'))
- else:
- morfdir = here
- print "computing code coverage (%s), this might take some time" % \
- morfdir
- cvg.annotate([morfdir])
- cvg.report([morfdir], False)
+ tester.show_report()
+ if covermode:
+ print 'coverage information stored, use it with pycoverage -ra'
sys.exit(tester.errcode)
diff --git a/shellutils.py b/shellutils.py
index b9f6253..ed5d23f 100644
--- a/shellutils.py
+++ b/shellutils.py
@@ -42,7 +42,7 @@ def chown(path, login=None, group=None):
try:
uid = int(login)
except ValueError:
- import pwd
+ import pwd # Platforms: Unix
uid = pwd.getpwnam(login).pw_uid
if group is None:
gid = -1
@@ -285,6 +285,7 @@ def confirm(question, default_is_yes=True):
"""ask for confirmation and return true on positive answer"""
return RawInput().confirm(question, default_is_yes)
+
class RawInput(object):
def __init__(self, input=None, printer=None):
@@ -331,3 +332,15 @@ class RawInput(object):
return answer == 'y'
ASK = RawInput()
+
+
+def getlogin():
+ """avoid using os.getlogin() because of strange tty / stdin problems
+ (man 3 getlogin)
+ Another solution would be to use $LOGNAME, $USER or $USERNAME
+ """
+ import pwd # Platforms: Unix
+ return pwd.getpwuid(os.getuid())[0]
+
+
+
diff --git a/test/unittest_db.py b/test/unittest_db.py
index 0f818ec..af288ff 100644
--- a/test/unittest_db.py
+++ b/test/unittest_db.py
@@ -1,12 +1,10 @@
"""
unit tests for module logilab.common.db
"""
-
-import os
-import pwd
import socket
from logilab.common.testlib import TestCase, unittest_main
+from logilab.common.shellutils import getlogin
from logilab.common.db import *
from logilab.common.db import PREFERED_DRIVERS
from logilab.common.adbh import (_GenericAdvFuncHelper, _SqliteAdvFuncHelper,
@@ -15,13 +13,6 @@ from logilab.common.adbh import (_GenericAdvFuncHelper, _SqliteAdvFuncHelper,
auto_register_function)
-def getlogin():
- """avoid usinng os.getlogin() because of strange tty / stdin problems
- (man 3 getlogin)
- Another solution would be to use $LOGNAME, $USER or $USERNAME
- """
- return pwd.getpwuid(os.getuid())[0]
-
class PreferedDriverTC(TestCase):
def setUp(self):
self.drivers = {"pg":[('foo', None), ('bar', None)]}
diff --git a/test/unittest_graph.py b/test/unittest_graph.py
index b8f5394..ce272e5 100644
--- a/test/unittest_graph.py
+++ b/test/unittest_graph.py
@@ -1,9 +1,9 @@
# unit tests for the cache module
from logilab.common.testlib import TestCase, unittest_main
-from logilab.common.graph import get_cycles
+from logilab.common.graph import get_cycles, has_path
-class getCycleTestCase(TestCase):
+class getCyclesTC(TestCase):
def test_known0(self):
self.assertEqual(get_cycles({1:[2], 2:[3], 3:[1]}), [[1, 2, 3]])
@@ -15,5 +15,19 @@ class getCycleTestCase(TestCase):
self.assertEqual(get_cycles({1:[2], 2:[3], 3:[0], 0:[]}), [])
+class hasPathTC(TestCase):
+
+ def test_direct_connection(self):
+ self.assertEquals(has_path({'A': ['B'], 'B': ['A']}, 'A', 'B'), ['B'])
+
+ def test_indirect_connection(self):
+ self.assertEquals(has_path({'A': ['B'], 'B': ['A', 'C'], 'C': ['B']}, 'A', 'C'), ['B', 'C'])
+
+ def test_no_connection(self):
+ self.assertEquals(has_path({'A': ['B'], 'B': ['A']}, 'A', 'C'), None)
+
+ def test_cycle(self):
+ self.assertEquals(has_path({'A': ['A']}, 'A', 'B'), None)
+
if __name__ == "__main__":
unittest_main()
diff --git a/test/unittest_testlib.py b/test/unittest_testlib.py
index 1bf5123..5e37cf0 100644
--- a/test/unittest_testlib.py
+++ b/test/unittest_testlib.py
@@ -20,7 +20,7 @@ except NameError:
from unittest import TestSuite
-from logilab.common.testlib import TestCase, SkipAwareTextTestRunner
+from logilab.common.testlib import TestCase, SkipAwareTextTestRunner, Tags
from logilab.common.testlib import mock_object, NonStrictTestLoader, create_files
from logilab.common.testlib import capture_stdout, unittest_main, InnerTest
from logilab.common.testlib import with_tempdir, tag
@@ -776,6 +776,21 @@ class TagTC(TestCase):
self.func = bob
+ class TagTestTC(TestCase):
+ tags = Tags(('one', 'two'))
+
+ def test_one(self):
+ self.assertTrue(True)
+
+ @tag('two', 'three')
+ def test_two(self):
+ self.assertTrue(True)
+
+ @tag('three')
+ def test_three(self):
+ self.assertTrue(True)
+ self.cls = TagTestTC
+
def test_tag_decorator(self):
bob = self.func
@@ -804,5 +819,45 @@ class TagTC(TestCase):
self.assertTrue(tags.match('not other or (testing and bibi)'))
self.assertTrue(tags.match('other or (testing and bob)'))
+ def test_tagged_class(self):
+ def options(tags):
+ class Options(object):
+ tags_pattern = tags
+ return Options()
+
+ cls = self.cls
+
+ runner = SkipAwareTextTestRunner()
+ self.assertTrue(runner.does_match_tags(cls.test_one))
+ self.assertTrue(runner.does_match_tags(cls.test_two))
+ self.assertTrue(runner.does_match_tags(cls.test_three))
+
+ runner = SkipAwareTextTestRunner(options=options('one'))
+ self.assertTrue(runner.does_match_tags(cls.test_one))
+ self.assertFalse(runner.does_match_tags(cls.test_two))
+ self.assertFalse(runner.does_match_tags(cls.test_three))
+
+ runner = SkipAwareTextTestRunner(options=options('two'))
+ self.assertTrue(runner.does_match_tags(cls.test_one))
+ self.assertTrue(runner.does_match_tags(cls.test_two))
+ self.assertFalse(runner.does_match_tags(cls.test_three))
+
+ runner = SkipAwareTextTestRunner(options=options('three'))
+ self.assertFalse(runner.does_match_tags(cls.test_one))
+ self.assertTrue(runner.does_match_tags(cls.test_two))
+ self.assertTrue(runner.does_match_tags(cls.test_three))
+
+ runner = SkipAwareTextTestRunner(options=options('two or three'))
+ self.assertTrue(runner.does_match_tags(cls.test_one))
+ self.assertTrue(runner.does_match_tags(cls.test_two))
+ self.assertTrue(runner.does_match_tags(cls.test_three))
+
+ runner = SkipAwareTextTestRunner(options=options('two and three'))
+ self.assertFalse(runner.does_match_tags(cls.test_one))
+ self.assertTrue(runner.does_match_tags(cls.test_two))
+ self.assertFalse(runner.does_match_tags(cls.test_three))
+
+
+
if __name__ == '__main__':
unittest_main()
diff --git a/testlib.py b/testlib.py
index c3d8496..aeaedb3 100644
--- a/testlib.py
+++ b/testlib.py
@@ -466,8 +466,13 @@ class SkipAwareTextTestRunner(unittest.TextTestRunner):
if self.options is not None:
tags_pattern = getattr(self.options, 'tags_pattern', None)
if tags_pattern is not None:
- tags = getattr(test, 'tags', Tags())
- return tags.match(tags_pattern)
+ tags = getattr(test, 'tags', None)
+ if tags is not None:
+ return tags.match(tags_pattern)
+ if isinstance(test, types.MethodType):
+ tags = getattr(test.im_class, 'tags', Tags())
+ return tags.match(tags_pattern)
+ return False
return True # no pattern
def _makeResult(self):