Skip to content
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

Add missing dunder attributes for TypeAliasType instances #470

Merged
merged 13 commits into from
Sep 26, 2024
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
with `@typing_extensions.deprecated`. Patch by Sebastian Rittau.
- Fix bug where `TypeAliasType` instances could be subscripted even
where they were not generic. Patch by [Daraan](https://github.com/Daraan).
- Fix bug where a subscripted `TypeAliasType` instance did not have all
attributes of the original `TypeAliasType` instance on older Python versions.
Patch by [Daraan](https://github.com/Daraan) and Alex Waygood.

# Release 4.12.2 (June 7, 2024)

Expand Down
24 changes: 23 additions & 1 deletion src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7247,6 +7247,29 @@ def test_getitem(self):
self.assertEqual(get_args(fully_subscripted), (Iterable[float],))
self.assertIs(get_origin(fully_subscripted), ListOrSetT)

def test_alias_attributes(self):
T = TypeVar('T')
T2 = TypeVar('T2')
ListOrSetT = TypeAliasType("ListOrSetT", Union[List[T], Set[T]], type_params=(T,))

subscripted = ListOrSetT[int]
self.assertEqual(subscripted.__module__, ListOrSetT.__module__)
self.assertEqual(subscripted.__name__, "ListOrSetT")
self.assertEqual(subscripted.__value__, Union[List[T], Set[T]])
self.assertEqual(subscripted.__type_params__, (T,))

still_generic = ListOrSetT[Iterable[T2]]
self.assertEqual(still_generic.__module__, ListOrSetT.__module__)
self.assertEqual(still_generic.__name__, "ListOrSetT")
self.assertEqual(still_generic.__value__, Union[List[T], Set[T]])
self.assertEqual(still_generic.__type_params__, (T,))

fully_subscripted = still_generic[float]
self.assertEqual(fully_subscripted.__module__, ListOrSetT.__module__)
self.assertEqual(fully_subscripted.__name__, "ListOrSetT")
self.assertEqual(fully_subscripted.__value__, Union[List[T], Set[T]])
self.assertEqual(fully_subscripted.__type_params__, (T,))

def test_subscription_without_type_params(self):
Simple = TypeAliasType("Simple", int)
with self.assertRaises(TypeError, msg="Only generic type aliases are subscriptable"):
Expand All @@ -7260,7 +7283,6 @@ def test_subscription_without_type_params(self):
with self.assertRaises(TypeError, msg="Only generic type aliases are subscriptable"):
MissingTypeParamsErr[int]


def test_pickle(self):
global Alias
Alias = TypeAliasType("Alias", int)
Expand Down
22 changes: 19 additions & 3 deletions src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3452,6 +3452,19 @@ def _is_unionable(obj):
TypeAliasType,
))

if sys.version_info < (3, 10):
class _TypeAliasGenericAlias(typing._GenericAlias, _root=True):
def __getattr__(self, attr):
if attr in {"__value__", "__type_params__", "__name__"}:
return getattr(self.__origin__, attr)
return super().__getattr__(attr)

if sys.version_info < (3, 9):
def __getitem__(self, item):
result = super().__getitem__(item)
result.__class__ = type(self)
return result

class TypeAliasType:
"""Create named, parameterized type aliases.

Expand Down Expand Up @@ -3529,13 +3542,16 @@ def __getitem__(self, parameters):
raise TypeError("Only generic type aliases are subscriptable")
if not isinstance(parameters, tuple):
parameters = (parameters,)
parameters = [
# Using 3.9 here will create problems with Concatenate
if sys.version_info >= (3, 10):
return _types.GenericAlias(self, parameters)
parameters = tuple(
typing._type_check(
item, f'Subscripting {self.__name__} requires a type.'
)
for item in parameters
]
return typing._GenericAlias(self, tuple(parameters))
)
return _TypeAliasGenericAlias(self, parameters)

def __reduce__(self):
return self.__name__
Expand Down
Loading