-
-
Notifications
You must be signed in to change notification settings - Fork 126
[3.14] Address invalid inputs of TypeAliasType #477
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 12 commits
507088c
c00494a
4e2f041
b2412b0
54a67ab
64e4007
dccb363
4edee59
c928b20
9ad28aa
4b9a04c
6ba3f5e
e729c1f
83bbb98
ae88d98
6bc5c46
94b8c86
46ab3ac
b38852e
1ef3e00
cdf7fec
c14567d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7312,6 +7312,62 @@ def test_no_instance_subclassing(self): | |
| class MyAlias(TypeAliasType): | ||
| pass | ||
|
|
||
| def test_type_params_compatibility(self): | ||
| # Regression test to assure compatibility with typing variants | ||
| with self.subTest(type_params="typing.TypeVar"): | ||
| TypeAliasType("TypingTypeParams", ..., type_params=(typing.TypeVar('T'),)) | ||
| with self.subTest(type_params="typing.TypeAliasType"): | ||
| if not hasattr(typing, "TypeAliasType"): | ||
| self.skipTest("typing.TypeAliasType is not available before 3.12") | ||
| TypeAliasType("TypingTypeParams", ..., type_params=(typing.TypeVarTuple("Ts"),)) | ||
| with self.subTest(type_params="typing.TypeAliasType"): | ||
Daraan marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if not hasattr(typing, "ParamSpec"): | ||
| self.skipTest("typing.ParamSpec is not available before 3.10") | ||
| TypeAliasType("TypingTypeParams", ..., type_params=(typing.ParamSpec("P"),)) | ||
|
|
||
| def test_type_params_possibilities(self): | ||
| T = TypeVar('T') | ||
| # Test not a tuple | ||
| with self.assertRaisesRegex(TypeError, "type_params must be a tuple"): | ||
| TypeAliasType("InvalidTypeParams", List[T], type_params=[T]) | ||
|
|
||
| # Test default order and other invalid inputs | ||
| T_default = TypeVar('T_default', default=int) | ||
| Ts = TypeVarTuple('Ts') | ||
| Ts_default = TypeVarTuple('Ts_default', default=Unpack[Tuple[str, int]]) | ||
| P = ParamSpec('P') | ||
| P_default = ParamSpec('P_default', default=[str, int]) | ||
|
|
||
| # NOTE: "TypeVars with defaults cannot immediately follow TypeVarTuples" | ||
| # from PEP 696 is currently not enfored for the type statement and are not tested. | ||
| # PEP 695: Double usage of the same name is also not enforced and not tested. | ||
| valid_cases = [ | ||
| (T, P, Ts), | ||
| (T, Ts_default), | ||
| (P_default, T_default), | ||
| (P, T_default, Ts_default), | ||
| (T_default, P_default, Ts_default), | ||
| ] | ||
| invalid_cases = [ | ||
| ((T_default, T), f"non-default type parameter {T!r} follows default"), | ||
| ((P_default, P), f"non-default type parameter {P!r} follows default"), | ||
| ((Ts_default, T), f"non-default type parameter {T!r} follows default"), | ||
|
|
||
| # Potentially add invalid inputs, e.g. literals or classes | ||
| # depends on upstream | ||
| ((1,), "Expected a type param, got 1"), | ||
| ((str,), f"Expected a type param, got {str!r}"), | ||
| ] | ||
|
|
||
| for case in valid_cases: | ||
| with self.subTest(type_params=case): | ||
| TypeAliasType("OkCase", List[T], type_params=case) | ||
| for case, msg in invalid_cases: | ||
| with self.subTest(type_params=case): | ||
| if TYPING_3_12_0 and sys.version_info < (3, 14): | ||
| self.skipTest("No backport for 3.12 and 3.13 requires cpython PR #124795") | ||
|
||
| with self.assertRaisesRegex(TypeError, msg): | ||
| TypeAliasType("InvalidCase", List[T], type_params=case) | ||
|
|
||
| class DocTests(BaseTestCase): | ||
| def test_annotation(self): | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3531,11 +3531,24 @@ class TypeAliasType: | |
| def __init__(self, name: str, value, *, type_params=()): | ||
| if not isinstance(name, str): | ||
| raise TypeError("TypeAliasType name must be a string") | ||
| if not isinstance(type_params, tuple): | ||
| raise TypeError("type_params must be a tuple") | ||
| self.__value__ = value | ||
| self.__type_params__ = type_params | ||
|
|
||
| default_value_encountered = False | ||
| parameters = [] | ||
| for type_param in type_params: | ||
| if not isinstance(type_param, (TypeVar, TypeVarTuple, ParamSpec)): | ||
|
||
| raise TypeError(f"Expected a type param, got {type_param!r}") | ||
| has_default = ( | ||
| getattr(type_param, '__default__', NoDefault) is not NoDefault | ||
| ) | ||
| if default_value_encountered and not has_default: | ||
| raise TypeError(f'non-default type parameter {type_param!r}' | ||
| ' follows default type parameter') | ||
| if has_default: | ||
| default_value_encountered = True | ||
| if isinstance(type_param, TypeVarTuple): | ||
| parameters.extend(type_param) | ||
| else: | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.