Skip to content
47 changes: 47 additions & 0 deletions src/test_typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -5779,6 +5779,39 @@ class D(Protocol[T1, T2, Unpack[Ts]]): pass
with self.assertRaises(TypeError):
klass[int]

def test_with_non_typevartuple(self):
# These functions are, among others, used to determine typing._GenericAlias.__parameters__
# and are monkey patched.
T = TypeVar('T')
class MyTypedDict(TypedDict):
foo: int
bar: str
class MyTypedDictT(Generic[T], TypedDict):
foo: T
bar: str

with self.subTest("_collect_type_vars"):
if not hasattr(typing_extensions, "_collect_type_vars"):
self.skipTest("No _collect_type_vars")
self.assertEqual(typing_extensions._collect_type_vars((Unpack[MyTypedDict], )), ())
self.assertEqual(typing_extensions._collect_type_vars((Unpack[MyTypedDictT], )), ())
self.assertEqual(typing_extensions._collect_type_vars((Unpack[MyTypedDictT[T]], )), (T,))
self.assertEqual(typing_extensions._collect_type_vars((Unpack[Tuple[int]], )), ())
self.assertEqual(typing_extensions._collect_type_vars((Unpack[Tuple[int, T]], )), (T,))
with self.subTest("_collect_parameters"):
if not hasattr(typing_extensions, "_collect_parameters"):
self.skipTest("No _collect_parameters")
self.assertEqual(typing_extensions._collect_parameters((Unpack[MyTypedDict], )), ())
self.assertEqual(typing_extensions._collect_parameters((Unpack[MyTypedDictT], )), ())
self.assertEqual(typing_extensions._collect_parameters((Unpack[MyTypedDictT[T]], )), (T,))
self.assertEqual(typing_extensions._collect_parameters((Unpack[Tuple[int]], )), ())
self.assertEqual(typing_extensions._collect_parameters((Unpack[Tuple[int, T]], )), (T,))
self.assertEqual(typing._GenericAlias(Any, Unpack[MyTypedDict]).__parameters__, ())
self.assertEqual(typing._GenericAlias(Any, Unpack[MyTypedDictT]).__parameters__, ())
self.assertEqual(typing._GenericAlias(Any, Unpack[MyTypedDictT[T]]).__parameters__, (T,))
self.assertEqual(typing._GenericAlias(Any, Unpack[Tuple[int]]).__parameters__, ())
self.assertEqual(typing._GenericAlias(Any, Unpack[Tuple[int, T]]).__parameters__, (T,))


class TypeVarTupleTests(BaseTestCase):

Expand Down Expand Up @@ -7247,6 +7280,20 @@ def test_getitem(self):
self.assertEqual(get_args(fully_subscripted), (Iterable[float],))
self.assertIs(get_origin(fully_subscripted), ListOrSetT)

def tset_unpack_parameter_collection(self):
class Foo(Generic[T], TypedDict):
bar: Tuple[T]

FooAlias = TypeAliasType("FooAlias", Foo[T], type_params=(T,))
self.assertEqual(FooAlias[Unpack[Tuple[str]]].__parameters__, ())
self.assertEqual(FooAlias[Unpack[Tuple[T]]].__parameters__, (T,))
self.assertEqual(FooAlias[Unpack[Foo[T]]].__parameters__, (T,))

P = ParamSpec("P")
CallableP = TypeAliasType("CallableP", Callable[P, Any], type_params=(P,))
call_int_T = CallableP[Unpack[Tuple[int, T]]]
self.assertEqual(call_int_T.__parameters__, (T,))

def test_pickle(self):
global Alias
Alias = TypeAliasType("Alias", int)
Expand Down
5 changes: 4 additions & 1 deletion src/typing_extensions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3068,7 +3068,10 @@ def _collect_type_vars(types, typevar_types=None):
for t in types:
if _is_unpacked_typevartuple(t):
type_var_tuple_encountered = True
elif isinstance(t, typevar_types) and t not in tvars:
elif (
isinstance(t, typevar_types) and not isinstance(t, _UnpackAlias)
and t not in tvars
):
if enforce_default_ordering:
has_default = getattr(t, '__default__', NoDefault) is not NoDefault
if has_default:
Expand Down