-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Looping through literals not typed correctly #9230
Comments
is this a duplicate of #9168 ? edit: no but it's related |
Yes, it's a pretty similar case, I agree... |
The problem with inferring a literal type here is that then code like this could generate a false positive:
This would be more feasible if mypy would allow freely redefining variables with different types. |
Actually, we could maybe infer |
I see the potential issue. But currently even this fails: key: Literal["foo", "bar"]
for key in ("foo", "bar"): # error: Incompatible types in assignment (expression has type "str", variable has type "Union[Literal['foo'], Literal['bar']]")
print(foo[key]) # TypedDict key must be a string literal; expected one of ('foo', 'bar') which makes the issue very hard to work around... |
Why would anyone want to do this? If a variable comes from looping over hard-coded strings, then why would you ever want to change it rather than looping over different hard-coded strings, like this:
I guess the only situation is if you want to use both the lowercase
I guess we should somehow search a big amount of python code to see whether Similarly, mypy disallows |
I have seen this pattern enough times that you needn’t go on a hunt. For example the strings may be keys and the capitalized version will be presented to the user. Etc., etc. |
mypy can already "narrow down" the type of a local variable. For example, if Maybe there should also be a way to "widen up" the type of a local variable? In this case, This wouldn't be great even if it worked...
...because
Edit: simplified last example code |
that actually won't work with modifications in typeshed only:
|
Here is something that worked for me using FooBarType = Literal["foo", "bar"]
for key in get_args(FooBarType):
print(key) This allows you to loop through all the possible |
Sadly, the workaround listed above results in a type of Any for the loop variable. However, you can add a # type: comment to fix this and avoid the troubles that a stray unintented Any can bring: FooBarType = Literal["foo", "bar"]
for key in get_args(FooBarType): # type: FooBarType
print(key) In the above, mypy does not complain because the type of the get_args item is Any. In this modified version, the type is the Literal you just defined, and mypy can check uses against that. |
I was unaware of type comments, and they are soon to be removed, so the appropriate way of doing this would be to write: FooBarType = Literal["foo", "bar"]
key: FooBarType
for key in get_args(FooBarType):
print(key) |
I would like to mention that the from typing import Literal, get_args
FooBarType = Literal["foo", "bar"]
key: FooBarType
for key in get_args(Literal["baz"]):
print(key) But when executed, this of course prints |
Though a bit verbose, here is my suggestion: from typing import Literal
FooBar = Literal["foo", "bar"]
FOO_BARS: tuple[FooBar, ...] = ("foo", "bar")
for key in FOO_BARS:
print(key) |
Just found this thread because I ran into the issue that not even from typing import TypedDict
class FooDict(TypedDict):
foo: int
bar: int
foo = FooDict(foo=3, bar=3)
for key in foo:
print(foo[key]) # TypedDict key must be a string literal; expected one of ("foo", "bar") While the workaround from @JacobBush does indeed work (ty!), it adds extra bloat and I would think this is a pretty common use-case. |
@Jeitan for what it's worth, pyright does not complain about your example. |
@Dr-Irv Huh. Thanks for the tip, although it doesn't particularly help on the system of interest. I wonder what is different between the two. FWIW I got around it by making a Literal type with all the keys, then cast to that inside the loop. |
Preserve the literal type of index expressions a bit longer (until the next assignment) to support TypedDict lookups. ```py from typing import TypedDict class X(TypedDict): hourly: int daily: int def func(x: X) -> None: for var in ("hourly", "daily"): print(x[var]) ``` Closes #9230
Iterating through a fixed
Tuple
of strings("foo", "bar")
makes the loop variable astr
instead ofUnion[Literal["foo"], Literal["bar"]]
. This makes it difficult to loop through indices of aTypedDict
.´https://mypy-play.net/?mypy=latest&python=3.8&gist=17fe6a875f727a01fe3a5c6dca13dba2
The text was updated successfully, but these errors were encountered: