简体   繁体   中英

How can i document dictionary keys for a functions argument?

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.

  • Provide key hints when the function argument is a dict (most important)
  • Generate documentation with sphinx so that the keys reflect in the documentation.

Edit

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:

  • mypy type checks passes
  • shows keys
  • documentation also shows keys and types
  • The main caviate to this solution is that mypy thinks the value is optional because of a default value so the solution is not quite complete.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM