Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Add test case to check whether GenericAlias objects are not considere…
…d to be class, update docstring of typing._GenericAlias
  • Loading branch information
AbduazizZiyodov committed May 6, 2025
commit 0e5d19615e56cf31e2052596ca24208219fbd6c8
15 changes: 15 additions & 0 deletions Lib/test/test_typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5638,6 +5638,21 @@ def foo(x: T):

foo(42)

def test_genericalias_isclass(self):
T = TypeVar('T')

class Node(Generic[T]):
def __init__(self, label: T,
left: 'Node[T] | None' = None,
right: 'Node[T] | None' = None):
self.label = label
self.left = left
self.right = right

self.assertTrue(inspect.isclass(Node))
self.assertFalse(inspect.isclass(Node[int]))
self.assertFalse(inspect.isclass(Node[str]))

def test_implicit_any(self):
T = TypeVar('T')

Expand Down
110 changes: 57 additions & 53 deletions Lib/typing.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,31 +1283,34 @@ def __dir__(self):


class _GenericAlias(_BaseGenericAlias, _root=True):
# The type of parameterized generics.
#
# That is, for example, `type(List[int])` is `_GenericAlias`.
#
# Objects which are instances of this class include:
# * Parameterized container types, e.g. `Tuple[int]`, `List[int]`.
# * Note that native container types, e.g. `tuple`, `list`, use
# `types.GenericAlias` instead.
# * Parameterized classes:
# class C[T]: pass
# # C[int] is a _GenericAlias
# * `Callable` aliases, generic `Callable` aliases, and
# parameterized `Callable` aliases:
# T = TypeVar('T')
# # _CallableGenericAlias inherits from _GenericAlias.
# A = Callable[[], None] # _CallableGenericAlias
# B = Callable[[T], None] # _CallableGenericAlias
# C = B[int] # _CallableGenericAlias
# * Parameterized `Final`, `ClassVar`, `TypeGuard`, and `TypeIs`:
# # All _GenericAlias
# Final[int]
# ClassVar[float]
# TypeGuard[bool]
# TypeIs[range]

"""The type of parameterized generics.

That is, for example, `type(List[int])` is `_GenericAlias`.

Objects which are instances of this class include:
* Parameterized container types, e.g. `Tuple[int]`, `List[int]`.
* Note that native container types, e.g. `tuple`, `list`, use
`types.GenericAlias` instead.
* Parameterized classes:
class C[T]: pass
# C[int] is a _GenericAlias
* `Callable` aliases, generic `Callable` aliases, and
parameterized `Callable` aliases:
T = TypeVar('T')
# _CallableGenericAlias inherits from _GenericAlias.
A = Callable[[], None] # _CallableGenericAlias
B = Callable[[T], None] # _CallableGenericAlias
C = B[int] # _CallableGenericAlias
* Parameterized `Final`, `ClassVar`, `TypeGuard`, and `TypeIs`:
# All _GenericAlias
Final[int]
ClassVar[float]
TypeGuard[bool]
TypeIs[range]

Note that objects of this class is not considered to be a class (e.g by `inspect.isclass`),
even though they behave like them.
"""
def __init__(self, origin, args, *, inst=True, name=None):
super().__init__(origin, inst=inst, name=name)
if not isinstance(args, tuple):
Expand Down Expand Up @@ -1339,20 +1342,21 @@ def __ror__(self, left):

@_tp_cache
def __getitem__(self, args):
# Parameterizes an already-parameterized object.
#
# For example, we arrive here doing something like:
# T1 = TypeVar('T1')
# T2 = TypeVar('T2')
# T3 = TypeVar('T3')
# class A(Generic[T1]): pass
# B = A[T2] # B is a _GenericAlias
# C = B[T3] # Invokes _GenericAlias.__getitem__
#
# We also arrive here when parameterizing a generic `Callable` alias:
# T = TypeVar('T')
# C = Callable[[T], None]
# C[int] # Invokes _GenericAlias.__getitem__
"""Parameterizes an already-parameterized object.

For example, we arrive here doing something like:
T1 = TypeVar('T1')
T2 = TypeVar('T2')
T3 = TypeVar('T3')
class A(Generic[T1]): pass
B = A[T2] # B is a _GenericAlias
C = B[T3] # Invokes _GenericAlias.__getitem__

We also arrive here when parameterizing a generic `Callable` alias:
T = TypeVar('T')
C = Callable[[T], None]
C[int] # Invokes _GenericAlias.__getitem__
"""

if self.__origin__ in (Generic, Protocol):
# Can't subscript Generic[...] or Protocol[...].
Expand All @@ -1369,20 +1373,20 @@ def __getitem__(self, args):
return r

def _determine_new_args(self, args):
# Determines new __args__ for __getitem__.
#
# For example, suppose we had:
# T1 = TypeVar('T1')
# T2 = TypeVar('T2')
# class A(Generic[T1, T2]): pass
# T3 = TypeVar('T3')
# B = A[int, T3]
# C = B[str]
# `B.__args__` is `(int, T3)`, so `C.__args__` should be `(int, str)`.
# Unfortunately, this is harder than it looks, because if `T3` is
# anything more exotic than a plain `TypeVar`, we need to consider
# edge cases.

"""Determines new __args__ for __getitem__.

For example, suppose we had:
T1 = TypeVar('T1')
T2 = TypeVar('T2')
class A(Generic[T1, T2]): pass
T3 = TypeVar('T3')
B = A[int, T3]
C = B[str]
`B.__args__` is `(int, T3)`, so `C.__args__` should be `(int, str)`.
Unfortunately, this is harder than it looks, because if `T3` is
anything more exotic than a plain `TypeVar`, we need to consider
edge cases.
"""
params = self.__parameters__
# In the example above, this would be {T3: str}
for param in params:
Expand Down
Loading