diff options
Diffstat (limited to 'Lib/test')
-rw-r--r-- | Lib/test/test_functools.py | 68 |
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() |