Skip to content

WithAnnotations[X, Y] gives runtime error (but typechecker is happy) #719

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

Open
jordanbray opened this issue Sep 24, 2021 · 7 comments
Open
Labels
bug Something isn't working

Comments

@jordanbray
Copy link

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
@jordanbray jordanbray added the bug Something isn't working label Sep 24, 2021
@jordanbray
Copy link
Author

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.

@sobolevn
Copy link
Member

@jordanbray I would be happy to merge a PR with the fix! 👍

@AdrienLemaire
Copy link

AdrienLemaire commented Jun 29, 2022

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 #174 (comment) , I need to add # type: ignore, at every function defining my WithAnnotations types, this is a bit tedious.

@boatcoder
Copy link

The above, sadly, does not work with VSCode and PyLance.

@olethanh
Copy link

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]

@Briscoooe
Copy link

Any updates on this?

@Feuermurmel
Copy link

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]

@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 😅:

WithAnnotations = Annotated[_T, Annotations[_Annotations]]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Development

No branches or pull requests

7 participants