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

Can't match a TypedDict with a Protocol #17074

Open
adamnovak opened this issue Mar 28, 2024 · 0 comments
Open

Can't match a TypedDict with a Protocol #17074

adamnovak opened this issue Mar 28, 2024 · 0 comments
Labels
bug mypy got something wrong

Comments

@adamnovak
Copy link

Bug Report

I was trying to use a Protocol to fish out the value type from a TypedDict type corresponding to a key Literal passed to a function, so I could bind it to a TypeVar. That didn't work, but in trying to debug that I noticed that it's just straight up not possible to get a TypedDict to match a simple Protocol that we can see at type-checking time it does in fact match.

To Reproduce

See https://mypy-play.net/?mypy=latest&python=3.12&gist=928611fe3fcf77630451b8ca6b26dfca

from typing import Literal, TypedDict, Protocol, Optional

class Foo(TypedDict):
    bar: int

concrete_var: Foo = Foo(bar=5)

# This typechecks (though it has to be optional for some reason even if the key
# is Required in the TypedDict):
int_var: Optional[int] = concrete_var.get("bar")

class Gettable(Protocol):
    def get(self, key: Literal["bar"]) -> Optional[int]: ...

# But we don't use that to know that the protocol matches. This fails:
test_var: Gettable = concrete_var 

Actual Behavior

main.py:16: error: Incompatible types in assignment (expression has type "Foo", variable has type "Gettable")  [assignment]
main.py:16: note: Following member(s) of "Foo" have conflicts:
main.py:16: note:     Expected:
main.py:16: note:         def get(self, key: Literal['bar']) -> int | None
main.py:16: note:     Got:
main.py:16: note:         @overload
main.py:16: note:         def get(self, str, /) -> object
main.py:16: note:         @overload
main.py:16: note:         def [_T] get(self, str, /, default: object) -> object
Found 1 error in 1 file (checked 1 source file)

MyPy appears to have forgotten everything it ever knew about the types of the things in the TypedDict when it tries to match the get() method to the protocol.

Your Environment

  • Mypy version used: 1.9.0
  • Python version used: 3.10 and 3.12
@adamnovak adamnovak added the bug mypy got something wrong label Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug mypy got something wrong
Projects
None yet
Development

No branches or pull requests

1 participant