Skip to content
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

Cannot turn existing dictionary into TypedDict #8890

Open
astrojuanlu opened this issue May 26, 2020 · 4 comments
Open

Cannot turn existing dictionary into TypedDict #8890

astrojuanlu opened this issue May 26, 2020 · 4 comments

Comments

@astrojuanlu
Copy link
Contributor

astrojuanlu commented May 26, 2020

I expected any of these forms to be allowed by MyPy, but they aren't:

# typed_dict_test.py
from typing import TypedDict

class D(TypedDict):
    a: str
    b: int


d_untyped = {"a": "foo", "b": 1}

d0 = D({"a": "foo", "b": 1})  # The only one that works
print(d0)

d1 = D(d_untyped)
print(d1)

d2 = D(**d_untyped)
print(d2)

d3 = D(dict(d_untyped))
print(d3)

d4 = D(dict(**d_untyped))
print(d4)
$ python typed_dict_test.py
{'a': 'foo', 'b': 1}
{'a': 'foo', 'b': 1}
{'a': 'foo', 'b': 1}
{'a': 'foo', 'b': 1}
{'a': 'foo', 'b': 1}
$ python -V
Python 3.8.3
$ mypy typed_dict_test.py 
typed_dict_test.py:13: error: Expected keyword arguments, {...}, or dict(...) in TypedDict constructor  [misc]
    d1 = D(d_untyped)
         ^
typed_dict_test.py:16: error: Expected keyword arguments, {...}, or dict(...) in TypedDict constructor  [misc]
    d2 = D(**d_untyped)
         ^
typed_dict_test.py:19: error: Expected keyword arguments, {...}, or dict(...) in TypedDict constructor  [misc]
    d3 = D(dict(d_untyped))
         ^
typed_dict_test.py:22: error: Expected keyword arguments, {...}, or dict(...) in TypedDict constructor  [misc]
    d4 = D(dict(**d_untyped))
         ^
Found 4 errors in 1 file (checked 1 source file)
$ cat mypy.ini 
[mypy]
warn_redundant_casts = True
warn_unused_configs = True
pretty = True
show_error_codes = True

disallow_any_generics = True
disallow_subclassing_any = True
disallow_untyped_calls = True
disallow_incomplete_defs = True
check_untyped_defs = True
disallow_untyped_decorators = True
no_implicit_optional = True
warn_unused_ignores = True
warn_return_any = True
no_implicit_reexport = True

I checked that cast(D, ...) works, but I wonder if this is the right way to proceed, or a workaround.

@benkuhn
Copy link
Contributor

benkuhn commented Jul 22, 2020

While this is difficult in principle if d_untyped is not annotated (because it's inferred as Dict[str,object]), the same errors occur even if it's hand-annotated as D.

This gap makes it quite tough to do more complicated manipulations involving TypedDicts since there's no easy way to express "adding keys to one typeddict to make a different typeddict".

@GPHemsley
Copy link

GPHemsley commented Dec 18, 2020

This gap makes it quite tough to do more complicated manipulations involving TypedDicts since there's no easy way to express "adding keys to one typeddict to make a different typeddict".

Indeed, even the following doesn't work:

class D2(D):
    c: str

d5a = D2(d0.copy(), c="bar")
d5b = D2(dict(d0.copy(), c="bar"))
d6a = D2(d0, c="bar")
d6b = D2(dict(d0, c="bar"))

@tony
Copy link

tony commented Sep 9, 2022

If there's any workarounds for this - or even best practices - (perhaps not even using the constructor and using a TypeGuard), feel free to mention as well (and post Python + mypy version)

@martinbaerwolff
Copy link

martinbaerwolff commented Apr 9, 2023

I just stumbled over the same problem and used this as a solution:

import typing

class D(TypedDict):
    a: str
    b: int

d_untyped = {"a": "foo", "b": 1}

d_typed = typing.cast(D, d_untyped)

See also this blog post: https://adamj.eu/tech/2021/07/06/python-type-hints-how-to-use-typing-cast/

Don´t know, if that is the way to go for now and would be interested in other opinions, too :)

erictraut pushed a commit to microsoft/pyright that referenced this issue Apr 9, 2023
…it accepts another instance of the same TypedDict (or another TypedDict that is type compatible) as an argument. This makes pyright compatible with mypy in this regard. See python/mypy#8890 for details.
mymoomin added a commit to mymoomin/RSStoWebhook that referenced this issue Oct 12, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants