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

"Expected TypedDict key to be string literal" false positive? #4122

Closed
jstasiak opened this issue Oct 16, 2017 · 3 comments · Fixed by #15425
Closed

"Expected TypedDict key to be string literal" false positive? #4122

jstasiak opened this issue Oct 16, 2017 · 3 comments · Fixed by #15425

Comments

@jstasiak
Copy link
Contributor

Shouldn't something like this work?

from mypy_extensions import TypedDict

Details = TypedDict('Details', {'first_name': str, 'last_name': str})
DetailsSubset = TypedDict('DetailsSubset', {'first_name': str, 'last_name': str}, total=False)
defaults = {'first_name': 'John', 'last_name': 'Luther'}  # type: Details


def generate(data: DetailsSubset) -> Details:
    return {**defaults, **data}

I'm getting:

% mypy code.py 
code.py: error: Expected TypedDict key to be string literal

Oh, and the error message is missing the line number, that could be handy to have.

I'm using mypy 0.530 and Python 3.6.2.

@gvanrossum
Copy link
Member

Hm, the missing line number is a bug. The error is clearly about the final line of your example.

Unfortunately mypy isn't smart enough to understand that in this particular case the result will have exactly the desired set of keys. It basically gives up as soon as it sees {**expr}. Maybe we could teach it to calculate the minimal and maximal sets of keys for such usage (if **expr references a TypedDict) and give better diagnostics based on that.

I believe there are many other ways of constructing a TypedDict that won't be accepted; I think the best way is to just use a cast or put # type: ignore on it.

@ilevkivskyi
Copy link
Member

The missing line number should be easy to fix, but the {**expr} type detection might be harder.

@killthekitten
Copy link

killthekitten commented Jul 9, 2020

This is still an issue in 0.782. Has anything changed since 0.530 that could make the type detection for this case feasible? I.e. the discussion in #4441 seems relevant.

My current workaround is to use cast. A bit better than # type: ignore.

ilevkivskyi added a commit that referenced this issue Jun 26, 2023
Fixes #9408
Fixes #4122
Fixes #6462
Supersedes #13353

This PR enables two similar technically unsafe behaviors for TypedDicts,
as @JukkaL explained in
#6462 (comment)
allowing an "incomplete" TypedDict as an argument to `.update()` is
technically unsafe (and a similar argument applies to `**` syntax in
TypedDict literals). These are however very common patterns (judging
from number of duplicates to above issues), so I think we should support
them. Here is what I propose:
* Always support cases that are safe (like passing the type itself to
`update`)
* Allow popular but technically unsafe cases _by default_
* Have a new flag (as part of `--strict`) to fall back to current
behavior

Note that unfortunately we can't use just a custom new error code, since
we need to conditionally tweak some types in a plugin. Btw there are
couple TODOs I add here:
* First is for unsafe behavior for repeated TypedDict keys. This is not
new, I just noticed it when working on this
* Second is for tricky corner case involving multiple `**` items where
we may have false-negatives in strict mode.

Note that I don't test all the possible combinations here (since the
phase space is huge), but I think I am testing all main ingredients (and
I will be glad to add more if needed):
* All syntax variants for TypedDicts creation are handled
* Various shadowing/overrides scenarios
* Required vs non-required keys handling
* Union types (both as item and target types)
* Inference for generic TypedDicts
* New strictness flag

More than half of the tests I took from the original PR #13353
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants