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

Star-star syntax not allowed with TypedDict #9408

Closed
intgr opened this issue Sep 3, 2020 · 2 comments · Fixed by #15425
Closed

Star-star syntax not allowed with TypedDict #9408

intgr opened this issue Sep 3, 2020 · 2 comments · Fixed by #15425

Comments

@intgr
Copy link
Contributor

intgr commented Sep 3, 2020

🐛 Bug Report

This is similar to #6462 and #9335 but with the star-star syntax.

There are cases where mypy could prove the following program type-safe, but currently this is never allowed:

To Reproduce

from typing import TypedDict


class Value(TypedDict):
    key1: str
    key2: str


const1: Value = {"key1": "foo", "key2": "bar"}
const2: Value = {**const1, "key2": "eggs"}
#                ^^^^^^^^
# mypy: Expected TypedDict key to be string literal (10:20)
  • Mypy version used: mypy 0.780
  • Python version used: 3.8.6
@AlexWaygood
Copy link
Member

I'm raising the priority of this issue, since it has been requested many times and there have been at least three duplicate issues.

@eflorico
Copy link

eflorico commented Aug 7, 2022

I've just given this issue a go in my pull request: #13353

lucaswerkmeister added a commit to lucaswerkmeister/tool-lexeme-forms that referenced this issue Apr 15, 2023
A given language item ID is almost always used with a single language
code (but note the Hindustani/Hindi/Urdu exception!), so it makes sense
to combine the two into one value.

My original idea was to directly spread these variables into the
template dicts (which is also why they’re named e.g. language_English
instead of English_language – “language” resembles the “key”):

    # ...
    'label': 'English noun',
    **language_English,
    'lexical_category_item_id': noun,
    # ...

Unfortunately, mypy doesn’t support spreading TypedDicts like this yet
(python/mypy#9408), so work around it by assigning the language dict to
a new member inside the dict (now with an internal-only intermediate
type), and then later rewrite that into the previous form for the
module’s exports. (It would probably also be feasible to make all our
code use the new form, but we also expose the templates via an API, and
I don’t want to change the output format there right now.) Maybe we can
go back to the spread operator with a future mypy version.
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
5 participants