Skip to content

Enhanced Literal Detection: Allow string type narrowing to literals #16813

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

Closed
CarliJoy opened this issue Jan 24, 2024 · 6 comments
Closed

Enhanced Literal Detection: Allow string type narrowing to literals #16813

CarliJoy opened this issue Jan 24, 2024 · 6 comments
Labels

Comments

@CarliJoy
Copy link

CarliJoy commented Jan 24, 2024

Feature

It would be great if mypy could detect and type narrow strings to Literals if this is statically detectable.
I.e. if accessing TypedDict or Enum values

Pitch

from typing import TypedDict

class Part(TypedDict, total=False):
    a: int
    b: int

class Full(Part, total=False):
    c: int

def make_part(full: Full) -> Part:
    part: Part = {}
    for k, v in full.items():
        if k in Part.__annotations__:
            part[k]=v  #  error: TypedDict key must be a string literal; expected one of ("a", "b")  [literal-required]
    return part 

MyPy Play

Currently there is no way to type this kind of expression without a # type: ignore.

It would be nice if mypy could detect that if k in Part.__annotations__ will narrow k to the Literal of all key of Part.
Also if k == "a" isn't working at the moment, but at least for this I am able to write a TypeGuard.

Also if Literals are explicitly defined, we loose this once we are with a loop

Even if the literal is defined explictly, it gets lost in a for loop

def make_part_two(full: Full) -> Part:
    part: Part = {}
    keys: Final = ("a", "b")
    reveal_type(keys)  # tuple[Literal['a']?, Literal['b']?]
    ok = full[keys[0]]
    for key in keys:
        reveal_type(key) # str
        part[key] = full[key]  # literal-required

If explicitly given as keys: tuple[Literal["a", "b"], ...] it works also in the for loop but I don't want to duplicate these values...

@CarliJoy
Copy link
Author

related to #13767

@JelleZijlstra
Copy link
Member

This is a lot of different feature requests in one. You should probably open multiple issues. The one about __annotations__ might be a step too far, the others are more likely to be OK.

@CarliJoy
Copy link
Author

I will create different issues an link them here. After this I will close this issue.

@CarliJoy
Copy link
Author

Opened three different Issues that should tackle this.

@CarliJoy
Copy link
Author

CarliJoy commented Jan 26, 2024

Note this already works in pyright

Correction: Pyright just doesn't check this correctly

@bcmills
Copy link

bcmills commented Feb 6, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants