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

Using Literal typed variables as keys for TypedDict causes "TypedDict key must be a string literal" #6262

Closed
chungwu opened this issue Jan 28, 2019 · 4 comments · Fixed by #6558

Comments

@chungwu
Copy link

chungwu commented Jan 28, 2019

Please provide more information to help us understand the issue:

  • Are you reporting a bug, or opening a feature request?
    Bug

  • Please insert below the code you are checking with mypy,
    or a mock-up repro if the source is private. We would appreciate
    if you try to simplify your case to a minimal repro.

from mypy_extensions import TypedDict
from typing_extensions import Literal

class Test(TypedDict):
  a: str
  b: str

TestKey = Literal['a', 'b']

def read(test: Test, key: TestKey):
  return test[key]
  • What is the actual behavior/output?
    mypy.py:13: error: TypedDict key must be a string literal; expected one of ('a', 'b')

  • What is the behavior/output you expect?
    No type check errors

  • What are the versions of mypy and Python you are using?
    mypy -- 0.660
    python -- 3.6.3

    Do you see the same issue after installing mypy from Git master?
    Yes

  • What are the mypy flags you are using? (For example --strict-optional)
    None

  • If mypy crashed with a traceback, please paste
    the full traceback below.

(You can freely edit this text, please remove all the lines
you believe are unnecessary.)

@Michael0x2a
Copy link
Collaborator

Thanks for the bug report!

What's happening in this case is that mypy doesn't yet understand how to handle indexing TypedDicts using Unions of Literals -- it can currently handle indexing using only Literals. It probably should, though. I'll look into making a fix when I find some time later this week/next week.

@chungwu
Copy link
Author

chungwu commented Jan 28, 2019

Thanks! This is very useful for typing JSON blobs, and having functions that extract information from the JSON blobs using specific keys.

It would also be nice to extract a keys type from a TypedDict, like so :-)

class Test(TypedDict):
  a: str
  b: str

TestKey = Test.keys()  # same as Literal['a', 'b']

Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Mar 17, 2019
This pull request hacks on supports for union math when using Unions of
Literals to index into tuples, NamedTuples, and TypedDicts.

It also fixes a bug I apparently introduced. Currently, mypy correctly
reports an error with this code:

    class Test(TypedDict):
        foo: int

    t: Test

    # Error: int can't be assigned a str value
    t.setdefault("foo", "unrelated value")

...but does not report an error with:

    key: Literal["foo"]
    t.setdefault(key, "unrelated value")

This diff should make mypy report an error in both cases.

Resolves python#6262.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Mar 31, 2019
This pull request hacks on supports for union math when using Unions of
Literals to index into tuples, NamedTuples, and TypedDicts.

It also fixes a bug I apparently introduced. Currently, mypy correctly
reports an error with this code:

    class Test(TypedDict):
        foo: int

    t: Test

    # Error: int can't be assigned a str value
    t.setdefault("foo", "unrelated value")

...but does not report an error with:

    key: Literal["foo"]
    t.setdefault(key, "unrelated value")

This diff should make mypy report an error in both cases.

Resolves python#6262.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Jun 8, 2019
This pull request hacks on supports for union math when using Unions of
Literals to index into tuples, NamedTuples, and TypedDicts.

It also fixes a bug I apparently introduced. Currently, mypy correctly
reports an error with this code:

    class Test(TypedDict):
        foo: int

    t: Test

    # Error: int can't be assigned a str value
    t.setdefault("foo", "unrelated value")

...but does not report an error with:

    key: Literal["foo"]
    t.setdefault(key, "unrelated value")

This diff should make mypy report an error in both cases.

Resolves python#6262.
Michael0x2a added a commit to Michael0x2a/mypy that referenced this issue Jul 4, 2019
This pull request hacks on supports for union math when using Unions of
Literals to index into tuples, NamedTuples, and TypedDicts.

It also fixes a bug I apparently introduced. Currently, mypy correctly
reports an error with this code:

    class Test(TypedDict):
        foo: int

    t: Test

    # Error: int can't be assigned a str value
    t.setdefault("foo", "unrelated value")

...but does not report an error with:

    key: Literal["foo"]
    t.setdefault(key, "unrelated value")

This diff should make mypy report an error in both cases.

Resolves python#6262.
Michael0x2a added a commit that referenced this issue Jul 9, 2019
This pull request hacks on supports for union math when using Unions of
Literals to index into tuples, NamedTuples, and TypedDicts.

It also fixes a bug I apparently introduced. Currently, mypy correctly
reports an error with this code:

    class Test(TypedDict):
        foo: int

    t: Test

    # Error: int can't be assigned a str value
    t.setdefault("foo", "unrelated value")

...but does not report an error with:

    key: Literal["foo"]
    t.setdefault(key, "unrelated value")

This diff should make mypy report an error in both cases.

Resolves #6262.
@b0g3r
Copy link

b0g3r commented Oct 4, 2019

I have a similar problem, but I try to use a variable as a key:

from mypy_extensions import TypedDict
from typing_extensions import Literal, Final


class MyDict(TypedDict):
    field_name: int

d: MyDict
d = {'field_name': 1}

name_in_var = 'field_name'
d = {name_in_var: 1}

name_in_literal2: Literal['field_name'] = 'field_name'
d = {name_in_literal2: 1}

name_in_final: Final = 'field_name'
d = {name_in_final: 1}

And then get errors:

Dima Boger, [04.10.19 21:51]
test.py:13: error: Expected TypedDict key to be string literal
test.py:16: error: Expected TypedDict key to be string literal
test.py:19: error: Expected TypedDict key to be string literal
test.py:22: error: Expected TypedDict key to be string literal

@Michael0x2a It is expected behavior or bug linked to this issue?

@JukkaL
Copy link
Collaborator

JukkaL commented Oct 7, 2019

@b0g3r I created the follow-up issue #7644 about your problem.

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