diff options
-rw-r--r-- | setup.py | 8 | ||||
-rw-r--r-- | singledispatch.py | 18 | ||||
-rw-r--r-- | singledispatch_helpers.py | 12 | ||||
-rw-r--r-- | test_singledispatch.py | 63 | ||||
-rw-r--r-- | tox.ini | 8 |
5 files changed, 72 insertions, 37 deletions
@@ -41,6 +41,10 @@ with codecs.open( # We let it die a horrible tracebacking death if reading the file fails. # We couldn't sensibly recover anyway: we need the long description. +install_requires = ['six'] +if sys.version_info[:2] < (2, 7): + install_requires.append('ordereddict') + setup ( name = 'singledispatch', version = '3.4.0.2', @@ -56,9 +60,7 @@ setup ( license = 'MIT', py_modules = ('singledispatch', 'singledispatch_helpers'), zip_safe = True, - install_requires = [ - 'six', - ], + install_requires = install_requires, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', diff --git a/singledispatch.py b/singledispatch.py index b428920..87603fd 100644 --- a/singledispatch.py +++ b/singledispatch.py @@ -148,7 +148,7 @@ def _find_impl(cls, registry): if (t in registry and t not in cls.__mro__ and match not in cls.__mro__ and not issubclass(match, t)): - raise RuntimeError("Ambiguous dispatch: {} or {}".format( + raise RuntimeError("Ambiguous dispatch: {0} or {1}".format( match, t)) break if t in registry: @@ -167,7 +167,8 @@ def singledispatch(func): """ registry = {} dispatch_cache = WeakKeyDictionary() - cache_token = None + def ns(): pass + ns.cache_token = None def dispatch(cls): """generic_func.dispatch(cls) -> <function implementation> @@ -176,12 +177,11 @@ def singledispatch(func): for the given *cls* registered on *generic_func*. """ - nonlocal cache_token - if cache_token is not None: + if ns.cache_token is not None: current_token = get_cache_token() - if cache_token != current_token: + if ns.cache_token != current_token: dispatch_cache.clear() - cache_token = current_token + ns.cache_token = current_token try: impl = dispatch_cache[cls] except KeyError: @@ -198,12 +198,11 @@ def singledispatch(func): Registers a new implementation for the given *cls* on a *generic_func*. """ - nonlocal cache_token if func is None: return lambda f: register(cls, f) registry[cls] = func - if cache_token is None and hasattr(cls, '__abstractmethods__'): - cache_token = get_cache_token() + if ns.cache_token is None and hasattr(cls, '__abstractmethods__'): + ns.cache_token = get_cache_token() dispatch_cache.clear() return func @@ -217,3 +216,4 @@ def singledispatch(func): wrapper._clear_cache = dispatch_cache.clear update_wrapper(wrapper, func) return wrapper + diff --git a/singledispatch_helpers.py b/singledispatch_helpers.py index 3a71831..8fcdce4 100644 --- a/singledispatch_helpers.py +++ b/singledispatch_helpers.py @@ -7,9 +7,17 @@ from __future__ import print_function from __future__ import unicode_literals from abc import ABCMeta -from collections import MutableMapping, UserDict +from collections import MutableMapping import sys try: + from collections import UserDict +except ImportError: + from UserDict import UserDict +try: + from collections import OrderedDict +except ImportError: + from ordereddict import OrderedDict +try: from thread import get_ident except ImportError: try: @@ -143,7 +151,7 @@ class ChainMap(MutableMapping): class MappingProxyType(UserDict): def __init__(self, data): - super(MappingProxyType, self).__init__() + UserDict.__init__(self) self.data = data diff --git a/test_singledispatch.py b/test_singledispatch.py index 0705cff..779cb6d 100644 --- a/test_singledispatch.py +++ b/test_singledispatch.py @@ -16,10 +16,25 @@ try: except ImportError: from singledispatch_helpers import ChainMap collections.ChainMap = ChainMap -import unittest +try: + from collections import OrderedDict +except ImportError: + from singledispatch_helpers import OrderedDict + collections.OrderedDict = OrderedDict +try: + import unittest2 as unittest +except ImportError: + import unittest support = Support() +for _prefix in ('collections.abc', '_abcoll'): + if _prefix in repr(collections.Container): + abcoll_prefix = _prefix + break +else: + abcoll_prefix = '?' +del _prefix class TestSingleDispatch(unittest.TestCase): @@ -38,7 +53,7 @@ class TestSingleDispatch(unittest.TestCase): @functools.singledispatch def g(obj): return "base" - class A: + class A(object): pass class C(A): pass @@ -153,7 +168,7 @@ class TestSingleDispatch(unittest.TestCase): c = collections d = {"a": "b"} l = [1, 2, 3] - s = {object(), None} + s = set([object(), None]) f = frozenset(s) t = (1, 2, 3) @functools.singledispatch @@ -251,9 +266,10 @@ class TestSingleDispatch(unittest.TestCase): class B(A): def __len__(self): return 0 # implies Sized - @c.Container.register + #@c.Container.register class C(object): pass + c.Container.register(C) class D(object): pass # unrelated class X(D, C, B): @@ -288,7 +304,7 @@ class TestSingleDispatch(unittest.TestCase): c.Set.register(O) self.assertEqual(g(o), "set") # because c.Set is a subclass of # c.Sized and c.Container - class P: + class P(object): pass p = P() self.assertEqual(g(p), "base") @@ -299,10 +315,10 @@ class TestSingleDispatch(unittest.TestCase): g(p) self.assertIn( str(re_one.exception), - (("Ambiguous dispatch: <class 'collections.abc.Container'> " - "or <class 'collections.abc.Iterable'>"), - ("Ambiguous dispatch: <class 'collections.abc.Iterable'> " - "or <class 'collections.abc.Container'>")), + (("Ambiguous dispatch: <class '{prefix}.Container'> " + "or <class '{prefix}.Iterable'>").format(prefix=abcoll_prefix), + ("Ambiguous dispatch: <class '{prefix}.Iterable'> " + "or <class '{prefix}.Container'>").format(prefix=abcoll_prefix)), ) class Q(c.Sized): def __len__(self): @@ -331,10 +347,10 @@ class TestSingleDispatch(unittest.TestCase): h(c.defaultdict(lambda: 0)) self.assertIn( str(re_two.exception), - (("Ambiguous dispatch: <class 'collections.abc.Container'> " - "or <class 'collections.abc.Sized'>"), - ("Ambiguous dispatch: <class 'collections.abc.Sized'> " - "or <class 'collections.abc.Container'>")), + (("Ambiguous dispatch: <class '{prefix}.Container'> " + "or <class '{prefix}.Sized'>").format(prefix=abcoll_prefix), + ("Ambiguous dispatch: <class '{prefix}.Sized'> " + "or <class '{prefix}.Container'>").format(prefix=abcoll_prefix)), ) class R(c.defaultdict): pass @@ -350,7 +366,7 @@ class TestSingleDispatch(unittest.TestCase): return "sequence" r = R() self.assertEqual(i(r), "sequence") - class S: + class S(object): pass class T(S, c.Sized): def __len__(self): @@ -359,7 +375,7 @@ class TestSingleDispatch(unittest.TestCase): self.assertEqual(h(t), "sized") c.Container.register(T) self.assertEqual(h(t), "sized") # because it's explicitly in the MRO - class U: + class U(object): def __len__(self): return 0 u = U() @@ -371,10 +387,10 @@ class TestSingleDispatch(unittest.TestCase): h(u) self.assertIn( str(re_three.exception), - (("Ambiguous dispatch: <class 'collections.abc.Container'> " - "or <class 'collections.abc.Sized'>"), - ("Ambiguous dispatch: <class 'collections.abc.Sized'> " - "or <class 'collections.abc.Container'>")), + (("Ambiguous dispatch: <class '{prefix}.Container'> " + "or <class '{prefix}.Sized'>").format(prefix=abcoll_prefix), + ("Ambiguous dispatch: <class '{prefix}.Sized'> " + "or <class '{prefix}.Container'>").format(prefix=abcoll_prefix)), ) class V(c.Sized, S): def __len__(self): @@ -395,10 +411,13 @@ class TestSingleDispatch(unittest.TestCase): # Sized in the MRO def test_cache_invalidation(self): - from collections import UserDict + try: + from collections import UserDict + except ImportError: + from UserDict import UserDict class TracingDict(UserDict): def __init__(self, *args, **kwargs): - super(TracingDict, self).__init__(*args, **kwargs) + UserDict.__init__(self, *args, **kwargs) self.set_ops = [] self.get_ops = [] def __getitem__(self, key): @@ -451,7 +470,7 @@ class TestSingleDispatch(unittest.TestCase): self.assertEqual(td.set_ops, [dict, list, dict, list]) self.assertEqual(td.data[list], functools._find_impl(list, g.registry)) - class X: + class X(object): pass c.MutableMapping.register(X) # Will not invalidate the cache, # not using ABCs yet. @@ -1,6 +1,12 @@ [tox] -envlist = py33 +envlist = py26,py27,py32,py33,pypy [testenv] commands = {envbindir}/python test_singledispatch.py + +[testenv:py26] +basepython = python2.6 +deps = + ordereddict + unittest2 |