I have code that calls into an API client. The specific API action that I need has a lot of optional arguments. On my side, there are two cases where I call it, each of which uses a different optional argument. The processing on my side is moderately involved but nearly identical between the two cases, so I combine them as follows (simplified):
def call_api(data: list[str]):
keyword, value = ("spam", "foo") if condition(data) else ("eggs", "bar")
kwargs = {keyword: [value]}
api_client.method(**kwargs)
something(other, stuff)
If I call it like this, I get a whole bunch of type checker errors from Pylance claiming that values of type list[str]
are not valid for most of the other optional params to api_client.method
; that's correct, since they expect str
arguments. I could easily solve the problem by splitting the two cases into separate functions, each with the argument name hard-coded, but then I'd be duplicating a bunch of code. So to shut up that type checker, I annotate my code as follows:
def call_api(data: list[str]):
keyword, value = ("spam", "foo") if condition(data) else ("eggs", "bar")
kwargs: dict[typing.Literal["spam", "eggs"], list[str]] = {keyword: [value]}
api_client.method(**kwargs)
Now that type checker knows that the argument name is either "spam" or "eggs", for which values of list[str]
are valid, and it shuts up.
But now mypy
complains:
error: Dict entry 0 has incompatible type "str": "list[str]"; expected "Literal['spam', 'eggs']": "list[str]"
How can I give mypy enough information to recognize that my dict key is always "spam" or "eggs" while (hopefully) not taking away information that Pylance needs to do the same? I'm using Python 3.9, if that makes a difference.
Follow-up
Based on STerliakov@'s suggestion, I changed my code to the following:
def call_api(data: list[str]):
keyword: typing.Literal["spam", "eggs"]
value: str
keyword, value = ("spam", "foo") if condition(data) else ("eggs", "bar")
kwargs: dict[typing.Literal["spam", "eggs"], list[str]] = {keyword: [value]}
api_client.method(**kwargs)
I seem to need the redundant type hint on kwargs
to satisfy Pylance; apparently mypy only cares about the hints on the individual variables and Pylance only cares about the hint on the dict. However, I'm still not out of the woods: something in our build system (the debug spew suggests that it's mypy but I haven't been able to reproduce this using mypy outside of our big complicated wrapper) emits the following error:
Incompatible types in assignment (expression has type "str", variable has type
"Literal['spam', 'eggs']") [assignment]
key, value = ("spam", "foo") if condition(data) else ("eggs", "...
^
However, this is accepted:
def call_api(data: list[str]):
keyword: typing.Literal["spam", "eggs"]
value: str
if condition(data):
keyword, value = "spam", "foo"
else:
keyword, value = "eggs", "bar"
kwargs: dict[typing.Literal["spam", "eggs"], list[str]] = {keyword: [value]}
api_client.method(**kwargs)
What's going on? Those two functions should be completely equivalent, shouldn't they? Or am I looking at a buggy type checker?
发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744172645a4561609.html
评论列表(0条)