summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichele Simionato <michele.simionato@gmail.com>2015-07-23 14:40:09 +0200
committerMichele Simionato <michele.simionato@gmail.com>2015-07-23 14:40:09 +0200
commitbf1748df8d229bbfe40de6944c48349228e5b5bc (patch)
treefaf5fb5db86e2bed6a7de4ca528b479979bffea5 /src
parent6d099d1b69144e5bd491e457ec493b8f100480a1 (diff)
downloadpython-decorator-git-bf1748df8d229bbfe40de6944c48349228e5b5bc.tar.gz
More algorithmic fixes
Diffstat (limited to 'src')
-rw-r--r--src/decorator.py8
-rw-r--r--src/tests/documentation.py24
-rw-r--r--src/tests/test.py3
3 files changed, 19 insertions, 16 deletions
diff --git a/src/decorator.py b/src/decorator.py
index 2a96b4a..bab05b4 100644
--- a/src/decorator.py
+++ b/src/decorator.py
@@ -285,13 +285,15 @@ def append(a, vancestors):
Append ``a`` to the list of the virtual ancestors, unless it is already
included.
"""
+ add = True
for j, va in enumerate(vancestors):
if issubclass(va, a):
+ add = False
break
if issubclass(a, va):
vancestors[j] = a
- break
- else:
+ add = False
+ if add:
vancestors.append(a)
@@ -330,7 +332,7 @@ def dispatch_on(*dispatch_args):
for t, type_, ra in zip(types, types_, ras):
if issubclass(t, type_) and type_ not in t.__mro__:
append(type_, ra)
- return map(set, ras)
+ return [set(ra) for ra in ras]
def mros(*types):
"""
diff --git a/src/tests/documentation.py b/src/tests/documentation.py
index 4591611..c5f8c7d 100644
--- a/src/tests/documentation.py
+++ b/src/tests/documentation.py
@@ -821,30 +821,30 @@ implementation for ``Set`` is taken:
>>> get_length(SomeSet())
1
-
-The implementation of generic functions in the decorator module is
-still experimental. In this initial phase implicity was preferred
-over perfect consistency with the way ``functools.singledispatch`` works in
-the standard library. So there are some subtle differences in special
-cases.
-
-Considered a class ``C`` registered both as ``collections.Iterable``
-and ``collections.Sized`` and define a generic function ``g`` with
+Some times it is not clear how to dispatch. For instance, consider a
+class ``C`` registered both as ``collections.Iterable`` and
+``collections.Sized`` and define a generic function ``g`` with
implementations both for ``collections.Iterable`` and
``collections.Sized``. It is impossible to decide which implementation
-to use, and the following code will fail with a RuntimeError:
+to use, since the ancestors are independent, and the following code
+will fail with a RuntimeError:
$$singledispatch_example
This is consistent with the "refuse the temptation to guess"
-philosophy. ``functools.singledispatch`` will raise a similar error.
+philosophy. ``functools.singledispatch`` would raise a similar error.
+
It would be easy to rely on the order of registration to decide the
precedence order. This is reasonable, but also fragile: if during some
refactoring you change the registration order by mistake, a different
implementation could be taken. If implementations of the generic
functions are distributed across modules, and you change the import
order, a different implementation could be taken. So the decorator
-module is using the same approach of the standard library.
+module prefers to raise an error in the face of ambiguity. This is the
+same approach taken by the standard library. Notice that the dispatch
+algorithm used by the decorator module is different from the one used
+by ``functools.singledispatch``, so there are cases where you will get
+different answers.
Finally let me notice that the decorator module implementation does
not use any cache, whereas the one in ``singledispatch`` has a cache.
diff --git a/src/tests/test.py b/src/tests/test.py
index 8413a58..2de144e 100644
--- a/src/tests/test.py
+++ b/src/tests/test.py
@@ -320,7 +320,8 @@ class TestSingleDispatch(unittest.TestCase):
def i_sequence(arg):
return "sequence"
r = R()
- #self.assertEqual(i(r), "mapping") # was sequence
+ with doc.assertRaises(RuntimeError):
+ self.assertEqual(i(r), "mapping")
class S(object):
pass