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

Inconsistent behavior of issubclass when second argument is builtin collection #111763

Closed
Prometheus3375 opened this issue Nov 6, 2023 · 1 comment
Labels
topic-typing type-bug An unexpected behavior, bug, or error

Comments

@Prometheus3375
Copy link
Contributor

Prometheus3375 commented Nov 6, 2023

Bug report

Bug description:

Function issubclass requires the 1st argument to be a class (an instance of type). Thus, any parametrized generic cannot be passed as the first argument, because parametrized generics are instances of types.GenericAlias or typing._GenericAlias. However, looks like this behavior depends on the seconds argument.

from collections.abc import Collection
from typing import Any, Generic, TypeVar
from re import Pattern


def print_result(code: str, /):
    try:
        result = eval(code)
    except Exception as e:
        print(f'{code!r} -- {e.__class__.__name__}: {e}')
    else:
        print(f'{code!r} -- {result!r}')


T = TypeVar('T')


class A(Generic[T]):
    pass


samples = [
    'issubclass(list[str], list)',
    'issubclass(Collection[str], list)',
    'issubclass(frozenset[str], frozenset)',
    'issubclass(Pattern[str], tuple)',
    'issubclass(A[str], tuple)',

    'issubclass(list[str], Collection)',
    'issubclass(tuple[str, ...], Collection)',

    'issubclass(list[str], list[str])',
    'issubclass(list[str], Collection[str])',
    'issubclass(tuple[str, ...], tuple[Any, ...])',
    'issubclass(tuple[str, ...], Collection[str])',
    'issubclass(Collection[str], list[str])',
    'issubclass(Collection[str], Collection[str])',
    'issubclass(Collection, list[str])',
    ]

if __name__ == '__main__':
    for sample in samples:
        print_result(sample)

Output

'issubclass(list[str], list)' -- False
'issubclass(Collection[str], list)' -- False
'issubclass(frozenset[str], frozenset)' -- False
'issubclass(Pattern[str], tuple)' -- False
'issubclass(A[str], tuple)' -- TypeError: issubclass() arg 1 must be a class
'issubclass(list[str], Collection)' -- TypeError: issubclass() arg 1 must be a class
'issubclass(tuple[str, ...], Collection)' -- TypeError: issubclass() arg 1 must be a class
'issubclass(list[str], list[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(list[str], Collection[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(tuple[str, ...], tuple[Any, ...])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(tuple[str, ...], Collection[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(Collection[str], list[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(Collection[str], Collection[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic
'issubclass(Collection, list[str])' -- TypeError: issubclass() argument 2 cannot be a parameterized generic

As code suggests, if the 1st arg is an instance of types.GenericClass and the 2nd one is builtin collection, then the result is always False. And if for list this makes sense, because list is invariant, for frozenset the result should be True as frozenset is covariant. However, the issue is in the absence of TypeError; I expect that issubclass always fails if the 1st argument is not an instance of type.

If the 1st argument is a generic user class, fails as expected.
If the 2nd argument is some abstract collection, fails as expected.
If both arguments are parametrized generics, fails as expected.

I expect that issubclass always fails if the 1st argument is not an instance of type.

CPython versions tested on:

3.9, 3.10, 3.11

Operating systems tested on:

Windows

@Prometheus3375 Prometheus3375 added the type-bug An unexpected behavior, bug, or error label Nov 6, 2023
@AlexWaygood
Copy link
Member

AlexWaygood commented Nov 6, 2023

Duplicate of #101162. The behavior has been fixed in Python 3.13 (see #103369). Possibly we could consider backporting that PR to Python 3.12 and Python 3.11, but doing so would be risky, as there's a small chance it could break somebody's existing code. See #103369 (comment) for some previous discussion of this

@AlexWaygood AlexWaygood closed this as not planned Won't fix, can't repro, duplicate, stale Nov 6, 2023
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

3 participants