I am trying to figure out how can I provide type hints for a dictionary argument being passed to a function without using Dict[str, str]
as that doesnt provide what the keys will be.
I have tried two approaches so far, one with using typing_extensions
so that I can have compatibility with 3.6, and also with pydantic
, but I cant get the hits to show.
Consider this example code:
from typing_extensions import TypedDict
from pydantic import BaseModel
class Some(TypedDict):
"""keya is some key"""
keya: str
"""another_key is another key"""
another_key: str
def some(a: Some) -> None:
print(a.get('keya'))
return None
some({'keya': 'key', 'another_key': 'nonething'})
As expected, the type hints for the some
function shows the type Some
, but not its keys.
What I am trying to accomplish is 2 things.
As on of the comments pointed out, I can accomplish this with **kwargs
to some extent, but that is not the intention. Setting **kwargs
does not give me type hints either.
I think in this case, it might actually be better to file a feature request/submit a pull request to your editor improving the quality of its type hinting. Similarly, with sphinx, you could submit a pull request that ensures that the docs either properly link to the definition of Some or include a more detailed description within the function signature itself.
After all, the problem you're facing is a limitation of your editor/sphinx, not with Python or type hints, and you might get better long-term results if you tackle the problem at the source.
You may also get better results if you use the "constructor" of Some
instead of passing in a dict literal. At least for me, doing this gets me full key hints for Some
when using PyCharm. Not sure if that'll also be the case for your editor:
some(Some(keya='key', another_key='nonething'))
Note that doing Some(...)
will actually just return a plain old regular dict at runtime, so this shouldn't lead to any difference in behavior.
It could also be worth trying to do:
x: Some = {
"keya": "key",
"another_key": "nonething",
}
some(x)
...to see if your editor might give better hints with that form.
I have somewhat narrowed down to a possible solution using the following code. It meets most of the requirements:
Using the validate_items
function, I can validate that the values are there. Please see the comments on the code snippet and offer suggestions.
from typing_extensions import TypedDict
from typing import Union
class Some(TypedDict):
keya: str
another_key: str
def validate_items(v: dict) -> None:
for key, value in v.items():
assert isinstance(value,str), '{} is required'.format(key)
# Would love to pull the type of a key from the Some class here or
# would love to put the validation in the Some class itself
def some(a: Some={'keya': '', 'another_key': ''}) -> None:
"""[summary]
Args:
a (Some, optional): [description]. Defaults to {'keya': '', 'another_key': ''}.
Returns:
[type]: [description]
"""
validate_items(dict(a))
print(a.get('keya'))
return None
In the screenshot, I can see that mypy is complaining about the None
value which is expected, and in the popup help, we can also see the keys that are required in the dictionary being passed along with the type that is being set to it.
The solution feels quite hacky, and would appreciate any corrections to make it more pythonic.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.