-
-
Notifications
You must be signed in to change notification settings - Fork 30.7k
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
TypedDict inheritance doesn't work with get_type_hints and postponed evaluation of annotations across modules #85421
Comments
Copied from python/typing#737 I came across this issue while using inheritance to express required keys in a TypedDict, as is recommended by the docs. It's most easily explained by a minimal example I cooked up. Let's say we have a module foo.py: from __future__ import annotations
from typing import Optional
from typing_extensions import TypedDict
class Foo(TypedDict):
a: Optional[int] And another module bar.py: from __future__ import annotations
from typing import get_type_hints
from foo import Foo
class Bar(Foo, total=False):
b: int
print(get_type_hints(Bar)) Note that both foo.py and bar.py have adopted postponed evaluation of annotations (PEP-563) by using the __future__ import. If we execute bar.py, we get the error message NameError: name 'Optional' is not defined. This is due to the combination of:
tp_dict = super(_TypedDictMeta, cls).__new__(cls, name, (dict,), ns) Thus, get_type_hints is unable to resolve the types for annotations that are only imported in foo.py. I ran this example using typing_extensions 3.7.4.2 (released via #709) and Python 3.7.3, but it seems like this would be an issue using the current main branches of both repositories as well. I'm wondering what the right approach is to tackling this issue. It is of course solvable by defining Bar in foo.py instead, but it isn't ideal or intuitive to always need to inherit from a TypedDict in the same module. I was thinking that similarly to __required_keys__ and __optional_keys__, the TypedDict could preserve its original bases in a new dunder attribute, and get_type_hints could work off of that instead of MRO when it is dealing with a TypedDict. I would be willing to contribute the PRs to implement this if the design is acceptable, but am open to other ideas as well. |
TBH this is not very elegant, but I think you can go ahead with this (at least as a quick fix) since I don't see a better solution yet. |
Agreed, given that the current workaround of implementing them in the same module works I think I will stick with that while this is brainstormed further. |
What is/was the initial reason to not preserve the MRO for a TypedDict? |
Hm, I can't say for sure. I believe it had something to do with TypedDict instances being instances of dict at runtime, but I can't actually reconstruct the reason. Maybe it's written up in PEP-589, but I suspect not (I skimmed and couldn't find it). If you ask on typing-sig maybe David Foster (who contributed the initial idea and implementation) remembers. |
Hm that may be true.
I read it completely and could not find anything
I asked here on typing-sig but did not yet get any responses. |
Note that this issue is now only a problem of you use I am out of time to argue about why we chose this behavior, alas. |
The way I fixed this is I added |
While this seems like a good solution I would still like to figure out why TypedDict do not preserve MRO. Because for now I have not found a reason nor did someone on the typing-sig mailinglist have a clue. Should there (no longer) be a reason for this then this problem has a trivial solution (just re-add the MRO and use that). |
Nils, unfortunately, fixing the MRO here won’t fix the issue because The most likely reason for incomplete MRO is that
|
I added a pull request with my fix here: |
How far can/should we backport this? |
It will work in 3.10 and 3.9 without issues. However, I don't remember if bugfixes for __future__ features require special treatment/are excluded from normal bugfix backports. I vaguely remember us not backporting from __future__ annotations very far back (since they usually broke backwards compatibility). Maybe 3.10 is enough? |
Let’s both, since this feels like a real bug fix to me. |
Thanks! ✨ 🍰 ✨ |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: