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

issubclass() is inconsistent with generic aliases #101162

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic-typing type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

No branches or pull requests

2 participants