diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2024-05-08 19:31:41 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-05-08 19:31:41 (GMT) |
commit | c6680cdc5a7bfe7684af4dba981383cc80c889a8 (patch) | |
tree | 14da0a0ae489a14ad30630bfe5380c7788d0a799 | |
parent | 02d49af21929519f191af33856be53f0ab9e874b (diff) | |
download | cpython-c6680cdc5a7bfe7684af4dba981383cc80c889a8.zip cpython-c6680cdc5a7bfe7684af4dba981383cc80c889a8.tar.gz cpython-c6680cdc5a7bfe7684af4dba981383cc80c889a8.tar.bz2 |
[3.13] gh-118772: Allow TypeVars without a default to follow those with a default when constructing aliases (GH-118774) (#118776)
(cherry picked from commit aac6b019fe91e2f9f7a955d4fc4db5d5efd968c9)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
-rw-r--r-- | Lib/test/test_typing.py | 17 | ||||
-rw-r--r-- | Lib/typing.py | 25 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst | 2 |
3 files changed, 34 insertions, 10 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py index bd116bb..fff81f7 100644 --- a/Lib/test/test_typing.py +++ b/Lib/test/test_typing.py @@ -668,6 +668,23 @@ class TypeParameterDefaultsTests(BaseTestCase): with self.assertRaises(TypeError): class Y(Generic[*Ts_default, T]): ... + def test_allow_default_after_non_default_in_alias(self): + T_default = TypeVar('T_default', default=int) + T = TypeVar('T') + Ts = TypeVarTuple('Ts') + + a1 = Callable[[T_default], T] + self.assertEqual(a1.__args__, (T_default, T)) + + a2 = dict[T_default, T] + self.assertEqual(a2.__args__, (T_default, T)) + + a3 = typing.Dict[T_default, T] + self.assertEqual(a3.__args__, (T_default, T)) + + a4 = Callable[*Ts, T] + self.assertEqual(a4.__args__, (*Ts, T)) + def test_paramspec_specialization(self): T = TypeVar("T") P = ParamSpec('P', default=[str, int]) diff --git a/Lib/typing.py b/Lib/typing.py index 8e61f50..c8649e3 100644 --- a/Lib/typing.py +++ b/Lib/typing.py @@ -257,7 +257,7 @@ def _type_repr(obj): return repr(obj) -def _collect_parameters(args): +def _collect_parameters(args, *, enforce_default_ordering: bool = True): """Collect all type variables and parameter specifications in args in order of first appearance (lexicographic order). @@ -286,15 +286,16 @@ def _collect_parameters(args): parameters.append(collected) elif hasattr(t, '__typing_subst__'): if t not in parameters: - if type_var_tuple_encountered and t.has_default(): - raise TypeError('Type parameter with a default' - ' follows TypeVarTuple') + if enforce_default_ordering: + if type_var_tuple_encountered and t.has_default(): + raise TypeError('Type parameter with a default' + ' follows TypeVarTuple') - if t.has_default(): - default_encountered = True - elif default_encountered: - raise TypeError(f'Type parameter {t!r} without a default' - ' follows type parameter with a default') + if t.has_default(): + default_encountered = True + elif default_encountered: + raise TypeError(f'Type parameter {t!r} without a default' + ' follows type parameter with a default') parameters.append(t) else: @@ -1416,7 +1417,11 @@ class _GenericAlias(_BaseGenericAlias, _root=True): args = (args,) self.__args__ = tuple(... if a is _TypingEllipsis else a for a in args) - self.__parameters__ = _collect_parameters(args) + enforce_default_ordering = origin in (Generic, Protocol) + self.__parameters__ = _collect_parameters( + args, + enforce_default_ordering=enforce_default_ordering, + ) if not name: self.__module__ = origin.__module__ diff --git a/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst b/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst new file mode 100644 index 0000000..474454b --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-05-08-09-21-49.gh-issue-118772.c16E8X.rst @@ -0,0 +1,2 @@ +Allow :class:`typing.TypeVar` instances without a default to follow +instances without a default in some cases. Patch by Jelle Zijlstra. |