From: Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> Date: Thu, 24 Dec 2020 03:07:51 +0000 (-0800) Subject: bpo-42195: Override _CallableGenericAlias's __getitem__ (GH-23915) X-Git-Tag: v3.9.2rc1~105 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a1251980d20ee8aab8d887fc0d30a726247327af;p=thirdparty%2FPython%2Fcpython.git bpo-42195: Override _CallableGenericAlias's __getitem__ (GH-23915) Added `__getitem__` for `_CallableGenericAlias` so that it returns a subclass (itself) of `types.GenericAlias` rather than the default behavior of returning a plain `types.GenericAlias`. This fixes `repr` issues occuring after `TypeVar` substitution arising from the previous behavior. (cherry picked from commit 6dd3da3cf4a0d6cb62d9c2a155434c127183454d) Co-authored-by: kj <28750310+Fidget-Spinner@users.noreply.github.com> --- diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index cec19ec47349..b6ecf8eac636 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -441,7 +441,7 @@ class _CallableGenericAlias(GenericAlias): raise TypeError( "Callable must be used as Callable[[arg, ...], result].") t_args, t_result = args - if isinstance(t_args, list): + if isinstance(t_args, (list, tuple)): ga_args = tuple(t_args) + (t_result,) # This relaxes what t_args can be on purpose to allow things like # PEP 612 ParamSpec. Responsibility for whether a user is using @@ -463,6 +463,16 @@ class _CallableGenericAlias(GenericAlias): args = list(args[:-1]), args[-1] return _CallableGenericAlias, (Callable, args) + def __getitem__(self, item): + # Called during TypeVar substitution, returns the custom subclass + # rather than the default types.GenericAlias object. + ga = super().__getitem__(item) + args = ga.__args__ + t_result = args[-1] + t_args = args[:-1] + args = (t_args, t_result) + return _CallableGenericAlias(Callable, args) + def _type_repr(obj): """Return the repr() of an object, special-casing types (internal helper). diff --git a/Lib/test/test_genericalias.py b/Lib/test/test_genericalias.py index 5de13fe6d2f6..ccf40b13d3a9 100644 --- a/Lib/test/test_genericalias.py +++ b/Lib/test/test_genericalias.py @@ -347,6 +347,12 @@ class BaseTest(unittest.TestCase): self.assertEqual(C2[int, float, str], Callable[[int, float], str]) self.assertEqual(C3[int], Callable[..., int]) + # multi chaining + C4 = C2[int, V, str] + self.assertEqual(repr(C4).split(".")[-1], "Callable[[int, ~V], str]") + self.assertEqual(repr(C4[dict]).split(".")[-1], "Callable[[int, dict], str]") + self.assertEqual(C4[dict], Callable[[int, dict], str]) + with self.subTest("Testing type erasure"): class C1(Callable): def __call__(self):