agronholm / typeguard

Run-time type checker for Python
Other
1.5k stars 112 forks source link

"from __future__ import annotations" breaks the parsing of NotRequired in check_type #424

Closed kilroy42 closed 5 months ago

kilroy42 commented 8 months ago

Things to check first

Typeguard version

4.1.5

Python version

3.11 / 3.12

What happened?

The following program should output the dictionary and not raise an Exception.

from __future__ import annotations

from typing import TypedDict, NotRequired
from typeguard import check_type

class TestType(TypedDict):
    needed: str
    notNeeded: NotRequired[str]

print(check_type({'needed': ''}, TestType))

But the following happens:

typeguard.TypeCheckError: dict is missing required key(s): "notNeeded"

BUT if you remove the first line (from __future__ import annotations), it works as expected.

How can we reproduce the bug?

Run the code once unmodified. Then run the code with the first line removed.

agronholm commented 5 months ago

Typeguard relies on the __required_keys__ attribute which still contains notNeeded in this case. I need a workaround that compiles the list of required keys differently.

agronholm commented 5 months ago

To make matters even worse, get_type_hints() completely erases the NotRequired annotation.

agronholm commented 5 months ago

I have a fix in place, but having some trouble writing a proper test for it.

d-k-bo commented 5 months ago

For future reference, this is a known limitation of NotRequired/Required reported previously in https://github.com/python/typing_extensions/issues/55 & https://github.com/python/cpython/issues/97727 and it is unlikely that it will ever be fixed upstream.