summaryrefslogtreecommitdiff
path: root/Lib/test
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test')
-rw-r--r--Lib/test/test_functools.py68
1 files changed, 68 insertions, 0 deletions
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 68e94e7ae1..35ec2e2f48 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -10,6 +10,7 @@ import sys
from test import support
import threading
import time
+import typing
import unittest
import unittest.mock
from weakref import proxy
@@ -2119,6 +2120,73 @@ class TestSingleDispatch(unittest.TestCase):
g._clear_cache()
self.assertEqual(len(td), 0)
+ def test_annotations(self):
+ @functools.singledispatch
+ def i(arg):
+ return "base"
+ @i.register
+ def _(arg: collections.abc.Mapping):
+ return "mapping"
+ @i.register
+ def _(arg: "collections.abc.Sequence"):
+ return "sequence"
+ self.assertEqual(i(None), "base")
+ self.assertEqual(i({"a": 1}), "mapping")
+ self.assertEqual(i([1, 2, 3]), "sequence")
+ self.assertEqual(i((1, 2, 3)), "sequence")
+ self.assertEqual(i("str"), "sequence")
+
+ # Registering classes as callables doesn't work with annotations,
+ # you need to pass the type explicitly.
+ @i.register(str)
+ class _:
+ def __init__(self, arg):
+ self.arg = arg
+
+ def __eq__(self, other):
+ return self.arg == other
+ self.assertEqual(i("str"), "str")
+
+ def test_invalid_registrations(self):
+ msg_prefix = "Invalid first argument to `register()`: "
+ msg_suffix = (
+ ". Use either `@register(some_class)` or plain `@register` on an "
+ "annotated function."
+ )
+ @functools.singledispatch
+ def i(arg):
+ return "base"
+ with self.assertRaises(TypeError) as exc:
+ @i.register(42)
+ def _(arg):
+ return "I annotated with a non-type"
+ self.assertTrue(str(exc.exception).startswith(msg_prefix + "42"))
+ self.assertTrue(str(exc.exception).endswith(msg_suffix))
+ with self.assertRaises(TypeError) as exc:
+ @i.register
+ def _(arg):
+ return "I forgot to annotate"
+ self.assertTrue(str(exc.exception).startswith(msg_prefix +
+ "<function TestSingleDispatch.test_invalid_registrations.<locals>._"
+ ))
+ self.assertTrue(str(exc.exception).endswith(msg_suffix))
+
+ # FIXME: The following will only work after PEP 560 is implemented.
+ return
+
+ with self.assertRaises(TypeError) as exc:
+ @i.register
+ def _(arg: typing.Iterable[str]):
+ # At runtime, dispatching on generics is impossible.
+ # When registering implementations with singledispatch, avoid
+ # types from `typing`. Instead, annotate with regular types
+ # or ABCs.
+ return "I annotated with a generic collection"
+ self.assertTrue(str(exc.exception).startswith(msg_prefix +
+ "<function TestSingleDispatch.test_invalid_registrations.<locals>._"
+ ))
+ self.assertTrue(str(exc.exception).endswith(msg_suffix))
+
if __name__ == '__main__':
unittest.main()