Skip to content

issubclass() is inconsistent with generic aliases #101162

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
serhiy-storchaka opened this issue Jan 19, 2023 · 1 comment
Closed

issubclass() is inconsistent with generic aliases #101162

serhiy-storchaka opened this issue Jan 19, 2023 · 1 comment
Labels
topic-typing type-bug An unexpected behavior, bug, or error

Comments

@serhiy-storchaka
Copy link
Member

serhiy-storchaka commented Jan 19, 2023

Instances of types.GenericAlias are accepted as the first argument of issubclass():

>>> issubclass(list[int], object)
True
>>> issubclass(list[int], type)
False

while instances of typing.GenericAlias are not:

>>> issubclass(typing.List[int], object)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class
>>> issubclass(typing.List[int], type)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class

Although both are rejected if the second argument is an abstract class:

>>> issubclass(list[int], collections.abc.Sequence)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython/Lib/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class
>>> issubclass(typing.List[int], collections.abc.Sequence)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/serhiy/py/cpython/Lib/abc.py", line 123, in __subclasscheck__
    return _abc_subclasscheck(cls, subclass)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: issubclass() arg 1 must be a class

Usually issubclass(x, y) is preceded by the check isinstance(x, type), so the final result will always be false since 3.11, but if that check is omitted, you can see a difference.

Linked PRs

@sobolevn
Copy link
Member

sobolevn commented Apr 8, 2023

This happens because PyObject_IsSubclass uses abstract_get_bases which returns (object,) for list[int], but raises an error for typing.List[int]:

>>> list[int].__bases__
(<class 'object'>,)
>>> import typing
>>> typing.List[int].__bases__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/sobolev/Desktop/cpython/Lib/typing.py", line 1307, in __getattr__
    raise AttributeError(attr)
AttributeError: __bases__. Did you mean: '__args__'?

But, we can easily change this and forbid __bases__ access for types.GenericAlias objects by adding it to attr_exceptions.

As the result, everything is going to work the same as typing._GenericAlias:

>>> list[int].__bases__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: __bases__. Did you mean: '__args__'?

>>> issubclass(list[int], object)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: issubclass() arg 1 must be a class

Moreover, all typing/types/genericalias tests pass with this change.
I think that it is a reasonable thing to do. Because GenericAlias already has __mro_entries__ method and exposing __bases__ does not actually solve any problems as far as I know.

sobolevn added a commit to sobolevn/cpython that referenced this issue Apr 8, 2023
upils added a commit to canonical/craft-grammar that referenced this issue Mar 13, 2025
issubclass working on a GenericAlias was a bug that was fixed in python 3.13 (see python/cpython#101162)

Fixes #81

Signed-off-by: Paul Mars <paul.mars@canonical.com>
upils added a commit to canonical/craft-grammar that referenced this issue Mar 13, 2025
issubclass working on a GenericAlias was a bug that was fixed in python 3.13 (see python/cpython#101162)

Fixes #81

Signed-off-by: Paul Mars <paul.mars@canonical.com>
upils added a commit to canonical/craft-grammar that referenced this issue Mar 14, 2025
issubclass working on a GenericAlias was a bug that was fixed in python 3.13 (see python/cpython#101162)

Fixes #81

Signed-off-by: Paul Mars <paul.mars@canonical.com>
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants