False positive when checking `<class 'types.GenericAlias'>`(e.g.`dict[str, str]`) against `type`
fefe982 opened this issue · comments
Things to check first
-
I have searched the existing issues and didn't find my bug already reported there
-
I have checked that my bug is still present in the latest release
Typeguard version
4.1.5
Python version
3.12.0
What happened?
With this file:
import typeguard
@typeguard.typechecked
def foo(t: type):
pass
foo(dict[str,str])
typeguard reports:
Traceback (most recent call last):
File "/****/test.py", line 7, in <module>
foo(dict[str,str])
File "/****/test.py", line 4, in foo
def foo(t: type):
File "/****/lib/python3.12/site-packages/typeguard/_functions.py", line 138, in check_argument_types
check_type_internal(value, annotation, memo)
File "/****/lib/python3.12/site-packages/typeguard/_checkers.py", line 759, in check_type_internal
checker(value, origin_type, args, memo)
File "/****/lib/python3.12/site-packages/typeguard/_checkers.py", line 438, in check_class
raise TypeCheckError("is not a class")
typeguard.TypeCheckError: argument "t" (types.GenericAlias) is not a class
It should pass the test
How can we reproduce the bug?
With this file:
import typeguard
@typeguard.typechecked
def foo(t: type):
pass
foo(dict[str,str])
typeguard reports:
Traceback (most recent call last):
File "/****/test.py", line 7, in <module>
foo(dict[str,str])
File "/****/test.py", line 4, in foo
def foo(t: type):
File "/****/lib/python3.12/site-packages/typeguard/_functions.py", line 138, in check_argument_types
check_type_internal(value, annotation, memo)
File "/****/lib/python3.12/site-packages/typeguard/_checkers.py", line 759, in check_type_internal
checker(value, origin_type, args, memo)
File "/****/lib/python3.12/site-packages/typeguard/_checkers.py", line 438, in check_class
raise TypeCheckError("is not a class")
typeguard.TypeCheckError: argument "t" (types.GenericAlias) is not a class
Typeguard uses check_class
in _checkers.py
to check for type
annotation.
It first uses
if not isclass(value):
raise TypeCheckError("is not a class")
to check whether the type passed in is a class.
According to Python doc, python introduced generic aliases since 3.9, and dict[str, str]
is an instance of types.GenericAlias
:
>>> from types import GenericAlias
>>> list[int] == GenericAlias(list, (int,))
True
>>> dict[str, int] == GenericAlias(dict, (str, int))
True
Through some test, I found that in python 3.9, inspect.isclass(dict[str, str]
returns True
in 3.9 and 3.10, but returns False
in 3.11 and 3.12. So dict[str,str]
cannot pass the check in 3.11 or 3.12.
I tried to change the check into if not isclass(value) and not isinstance(value, types.GenericAlias):
and it fixed the problem.