From 8ed3dd8b6d265e721aa5151b8800effda9fb593a Mon Sep 17 00:00:00 2001 From: sobolevn Date: Wed, 15 Mar 2023 13:23:08 +0300 Subject: [PATCH 1/2] gh-102721: Improve coverage of `_collections_abc._CallableGenericAlias` --- Lib/_collections_abc.py | 7 ------- Lib/test/test_typing.py | 36 +++++++++++++++++++++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py index c62233b81a5c95..a2537e8b6fb8c2 100644 --- a/Lib/_collections_abc.py +++ b/Lib/_collections_abc.py @@ -481,15 +481,8 @@ def __getitem__(self, item): # rather than the default types.GenericAlias object. Most of the # code is copied from typing's _GenericAlias and the builtin # types.GenericAlias. - if not isinstance(item, tuple): item = (item,) - # A special case in PEP 612 where if X = Callable[P, int], - # then X[int, str] == X[[int, str]]. - if (len(self.__parameters__) == 1 - and _is_param_expr(self.__parameters__[0]) - and item and not _is_param_expr(item[0])): - item = (item,) new_args = super().__getitem__(item).__args__ diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index c17be6cd0bbc4a..2bcab861661377 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1921,14 +1921,28 @@ def test_weakref(self): self.assertEqual(weakref.ref(alias)(), alias) def test_pickle(self): + global T_pickle, P_pickle, TS_pickle # needed for pickling Callable = self.Callable - alias = Callable[[int, str], float] - for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + T_pickle = TypeVar('T_pickle') + P_pickle = ParamSpec('P_pickle') + TS_pickle = TypeVarTuple('TS_pickle') + + samples = [ + Callable[[int, str], float], + Callable[P_pickle, int], + Callable[P_pickle, T_pickle], + Callable[Concatenate[int, P_pickle], int], + Callable[Concatenate[*TS_pickle, P_pickle], int], + ] + for alias in samples: + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) + + del T_pickle, P_pickle, TS_pickle # cleaning up global state def test_var_substitution(self): Callable = self.Callable @@ -1954,6 +1968,14 @@ def test_var_substitution(self): self.assertEqual(C5[int, str, float], Callable[[typing.List[int], tuple[str, int], float], int]) + def test_type_subst_error(self): + Callable = self.Callable + P = ParamSpec('P') + T = TypeVar('T') + + with self.assertRaises(TypeError): + Callable[P, T][0, int] + def test_type_erasure(self): Callable = self.Callable class C1(Callable): From afe8f372965c54dfc3a416a8b501e8a7abf542e8 Mon Sep 17 00:00:00 2001 From: Nikita Sobolev Date: Wed, 15 Mar 2023 17:32:26 +0300 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Alex Waygood --- Lib/test/test_typing.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index 2bcab861661377..2f29ab3e9a38cc 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -1936,11 +1936,12 @@ def test_pickle(self): ] for alias in samples: for proto in range(pickle.HIGHEST_PROTOCOL + 1): - s = pickle.dumps(alias, proto) - loaded = pickle.loads(s) - self.assertEqual(alias.__origin__, loaded.__origin__) - self.assertEqual(alias.__args__, loaded.__args__) - self.assertEqual(alias.__parameters__, loaded.__parameters__) + with self.subTest(alias=alias, proto=proto): + s = pickle.dumps(alias, proto) + loaded = pickle.loads(s) + self.assertEqual(alias.__origin__, loaded.__origin__) + self.assertEqual(alias.__args__, loaded.__args__) + self.assertEqual(alias.__parameters__, loaded.__parameters__) del T_pickle, P_pickle, TS_pickle # cleaning up global state @@ -1973,7 +1974,9 @@ def test_type_subst_error(self): P = ParamSpec('P') T = TypeVar('T') - with self.assertRaises(TypeError): + pat = "Expected a list of types, an ellipsis, ParamSpec, or Concatenate." + + with self.assertRaisesRegex(TypeError, pat): Callable[P, T][0, int] def test_type_erasure(self):