Skip to content

Commit 23b393b

Browse files
committed
Fix various things in Generic.__class_getitem__
1 parent 75cd9d0 commit 23b393b

File tree

2 files changed

+27
-19
lines changed

2 files changed

+27
-19
lines changed

Lib/test/test_typing.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,6 +2367,11 @@ class NewGeneric(Generic): ...
23672367
class MyGeneric(Generic[T], Generic[S]): ...
23682368
with self.assertRaises(TypeError):
23692369
class MyGeneric(List[T], Generic[S]): ...
2370+
with self.assertRaises(TypeError):
2371+
Generic[()]
2372+
class C(Generic[T]): pass
2373+
with self.assertRaises(TypeError):
2374+
C[()]
23702375

23712376
def test_init(self):
23722377
T = TypeVar('T')

Lib/typing.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,28 +1805,31 @@ def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT:
18051805

18061806
@_tp_cache
18071807
def __class_getitem__(cls, params):
1808+
"""Parameterizes a generic class.
1809+
1810+
At least, parameterizing a generic class is the *main* thing this method
1811+
does. For example, for some generic class `Foo`, this is called when we
1812+
do `Foo[int]` - there, with `cls=Foo` and `params=int`.
1813+
1814+
However, note that this method is also called when defining generic
1815+
classes in the first place with `class Foo(Generic[T]): ...`.
1816+
"""
18081817
if not isinstance(params, tuple):
18091818
params = (params,)
18101819

1811-
try:
1812-
num_class_params = len(cls.__parameters__)
1813-
except AttributeError:
1814-
only_class_parameter_is_typevartuple = False
1815-
else:
1816-
if (
1817-
num_class_params == 1
1818-
and isinstance(cls.__parameters__[0], TypeVarTuple)
1819-
):
1820-
only_class_parameter_is_typevartuple = True
1821-
else:
1822-
only_class_parameter_is_typevartuple = False
1823-
1824-
if (
1825-
not params
1826-
and not (cls is Tuple or only_class_parameter_is_typevartuple)
1827-
):
1828-
raise TypeError(
1829-
f"Parameter list to {cls.__qualname__}[...] cannot be empty")
1820+
if not params:
1821+
# We're only ok with `params` being empty if the class's only type
1822+
# parameter is a `TypeVarTuple` (which can contain zero types).
1823+
class_params = getattr(cls, "__parameters__", None)
1824+
only_class_parameter_is_typevartuple = (
1825+
class_params is not None
1826+
and len(class_params) == 1
1827+
and isinstance(class_params[0], TypeVarTuple)
1828+
)
1829+
if not only_class_parameter_is_typevartuple:
1830+
raise TypeError(
1831+
f"Parameter list to {cls.__qualname__}[...] cannot be empty"
1832+
)
18301833

18311834
params = tuple(_type_convert(p) for p in params)
18321835
if cls in (Generic, Protocol):

0 commit comments

Comments
 (0)