django-stubs
django-stubs copied to clipboard
WithAnnotations[X, Y] gives runtime error (but typechecker is happy)
Bug report
What's wrong
I am trying to use the WithAnnotations
as documented with two parameters. The first is a django model, and the second is a typed dictionary. Here is a minified example:
from typing import TypedDict
from django_stubs_ext import WithAnnotations
from django.contrib.auth.models import User
class MinedData(TypedDict):
"""Use data science to get the information we need."""
nose_hair_length: float
# Option 1: As Documented
def potential_customer(user: WithAnnotations[User, MinedData]) -> bool:
return user.nose_hair_length > 2.0
# Option 2: As I tried to write it
PotentialRazorCustomer = WithAnnotations[User, MinedData]
def potential_customer2(user: PotentialRazorCustomer) -> bool:
return user.nose_hair_length > 2.0
$ mypy --strict tester.py
Works as anticipated. However, when I try to run the program (in this case, with python manage.py shell < tester.py
) the traceback for both Option 1 and Option 2 above is the same (save line numbers):
Traceback (most recent call last):
File "/.../manage.py", line 22, in <module>
execute_from_command_line(sys.argv)
File "/.../lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/.../lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/.../lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/.../lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/.../lib/python3.9/site-packages/django/core/management/commands/shell.py", line 93, in handle
exec(sys.stdin.read(), globals())
File "<string>", line 12, in <module>
File "/usr/lib/python3.9/typing.py", line 275, in inner
return func(*args, **kwds)
File "/usr/lib/python3.9/typing.py", line 758, in __getitem__
_check_generic(self, params, len(self.__parameters__))
File "/usr/lib/python3.9/typing.py", line 212, in _check_generic
raise TypeError(f"Too {'many' if alen > elen else 'few'} parameters for {cls};"
TypeError: Too many parameters for typing.Annotated[~_T, django_stubs_ext.annotations.Annotations[+_Annotations]]; actual 2, expected 1
How is that should be
The above should typecheck correctly, and also run.
System information
- OS: Linux (I use Arch, btw)
-
python
version: 3.9.6 -
django
version: 3.2 -
mypy
version: 0.910 -
django-stubs
version: 1.9.0 -
django-stubs-ext
version: 0.3.1
For people who find this via google, the above can be "fixed" by replacing:
PotentialRazorCustomer = WithAnnotations[User, MinedData]
with:
from typing import TYPE_CHECKING
if TYPE_CHECKING:
PotentialRazorCustomer = WithAnnotations[User, MinedData]
else:
PotentialRazorCustomer = WithAnnotations[User]
This more-or-less gets you the best of both worlds.
@jordanbray I would be happy to merge a PR with the fix! 👍
When I try to do this, I get the error #1024 .
I also have pyright complaigning about the same error, seemingly ignoring the TYPE_CHECKING
If, as per https://github.com/typeddjango/django-stubs/issues/174#issuecomment-534210437 , I need to add
# type: ignore
, at every function defining my WithAnnotations types, this is a bit tedious.
The above, sadly, does not work with VSCode and PyLance.
From what I gathered it seems to be an error that occur with Python 3.8 ?
I managed to fix it in my code base by replacing by replacing WithAnnotation
with Annotated
from TypingExtension
eg
from typing_extensions import Annotated
class FormStatAnnotation(typing.TypedDict):
form_stats: typing.Mapping[str, typing.Mapping]
OrgUnitWithFormStat = Annotated[OrgUnit, FormStatAnnotation]
Any updates on this?
From what I gathered it seems to be an error that occur with Python 3.8 ?
I managed to fix it in my code base by replacing by replacing
WithAnnotation
withAnnotated
from TypingExtensioneg
from typing_extensions import Annotated class FormStatAnnotation(typing.TypedDict): form_stats: typing.Mapping[str, typing.Mapping] OrgUnitWithFormStat = Annotated[OrgUnit, FormStatAnnotation]
@olethanh But is that doing the same thing? {typing,typing_extensions}.Annotated[T, X]
is the type T
with some metadata represented by X
, e.g. to be interpreted at runtime. OTOH django_stubs_ext.WithAnnotations[T, X]
is a new type, T
with additional members specified by the typed dict X
. I haven't checked, but I assume OrgUnitWithFormStat
won't be considered as having an attribute form_stats
in your example.
This line is not easy to parse 😅: https://github.com/typeddjango/django-stubs/blob/0a006f2dda989679b3d09fc876677bd90e1e5cb4/ext/django_stubs_ext/annotations.py#L18