Allow unpacking of TypedDict into TypedDict
Description
Closes #9408 (and duplicates, e.g. #10585, #11108). Related tracking issue: #11753
Allows unpacking of TypedDicts into other TypedDicts:
class Foo(TypedDict):
a: int
class Bar(TypedDict):
a: int
b: int
foo1: Foo = {'a': 1}
foo2: Foo = {**foo1}
bar: Bar = {**foo1, 'b': 2}
Should handle NotRequired fields correctly (they are counted as "maybe" present, we don't rely on them being present, but they should never be extraneous or have an incompatible type).
Also handles overwriting of fields correctly, for example:
class Foo(TypedDict):
a: int
b: str
class Bar(TypedDict):
a: int
b: int
foo: Foo = {'a': 1, 'b': '...'}
bar: Bar = {**foo} # Error: b is str instead of int
bar: Bar = {**foo, 'b': 2} # No error: b is overwritten
Limitations
- Unpacking only works if the type of the unpacked expression is correctly inferred as a
TypedDict. This is the case for variables or function return values, but not for dict expressions such as infoo: Foo = {**{'a': 1}} - Unpacking into unions does not work (
foo_or_bar: Union[Foo, Bar] = {**foo1}). This is becausefind_typeddict_contextcan currently only handle one TypedDict in the context - Unpacking from unions does not work (
foo: Bar = {**foo_or_bar}). I'm not sure yet how that could be added, I feel like it might take a bit more work
Test Plan
I have added quite detailed tests in check-typeddict.test.
Diff from mypy_primer, showing the effect of this PR on open source code:
steam.py (https://github.com/Gobot1234/steam.py)
- steam/profile.py:217: error: Expected TypedDict key to be string literal [misc]
+ steam/profile.py:217: error: Any cannot be unpacked into TypedDict (must be TypedDict) [misc]
- steam/profile.py:302: error: Expected TypedDict key to be string literal [misc]
+ steam/profile.py:302: error: Any cannot be unpacked into TypedDict (must be TypedDict) [misc]
Thanks, this is not a full review. Just a couple of minor comments 🙂
Thanks for your comments! I have updated the PR accordingly
Diff from mypy_primer, showing the effect of this PR on open source code:
steam.py (https://github.com/Gobot1234/steam.py)
- steam/profile.py:217: error: Expected TypedDict key to be string literal [misc]
+ steam/profile.py:217: error: Any cannot be unpacked into TypedDict (must be TypedDict) [misc]
- steam/profile.py:302: error: Expected TypedDict key to be string literal [misc]
+ steam/profile.py:302: error: Any cannot be unpacked into TypedDict (must be TypedDict) [misc]
Any progress on this PR ?
@HansAarneLiblik I have recently tried to merge master, but my changes were clashing with these recent changes. I haven't had the chance to figure out yet how to best solve this. If you have time to merge the current master and figure out how to unite both changes, I'd appreciate your help! I will only get around to look into this MR again in about two weeks
This was superseded by https://github.com/python/mypy/pull/15425
Thank you for your efforts anyway, the test cases were in particular helpful!