15

What is the conventional way to express in a docstring the expected types of keyword arguments?

Or is this out of principle something I should not be doing at all? Google is suspiciously un-forthcoming on the subject.

(I am interested in doing this because I find that keeping track of expected types of all variables is very helpful as I code. I use PyCharm, which warns me when arguments have unexpected types, or when custom class attributes may be unresolved etc.)

However, I am finding that sometimes the list of possible keywrord arguments listed as

def foo(bar, parameter_1: int=1, paramter_2: str='', ...etc )

can become long and unreadable..

Consider the following code

class Person:
    def __init__(self, id: int, **kwargs):
        """
        :param id: social security number
        :type id: int
        :param **name: person's first name
        :type **name: str
        :param **age: person's age in years, rounded down
        :type **age: int
        """
        self.data = kwargs


bob = Person(123456568, name='Bob', age=48)
sally = Person(1245654568, name='Sally', age='22')

I would like to use the docstring to state the expected types. And I would like PyCharm to warn me that sally's age has the wrong type. Of course, I don't know if PyCharm even has the capacity to 'understand' that level of detail in the docstring. Nevertheless I'd like to know what the conventional way to do it is.

Other comments and suggestions about kwargs and docstrings also welcome.

Dorian Turba
  • 3,260
  • 3
  • 23
  • 67
levraininjaneer
  • 1,157
  • 2
  • 18
  • 38

1 Answers1

11

Pycharm cannot warns you that your keywords has the wrong type but if you have the documentation panel open you can see the expected type if specified in the docstring. If not, the shortcut is ctr+q with caret at the function name. One time for a popup, two times to pin the documentation panel to the right.

You can alternativly raise an error if the type is incorrect.

After research and a lot of testing, here is everything I found. Take whatever you need :

from typing import TypedDict


class PersonData(TypedDict):
    name: str
    age: int


class Person:
    """
    a person
    """
    _ssn: int
    _data: PersonData

    def __init__(self, ssn: int, *args, **kwargs) -> None:
        """
        Create an instance of Person

        :param ssn: social security number
        :type ssn: int
        :key name: person's first name, should be a str
        :key age: person's age in years, rounded down, should be an int
        :return: __init__ should return None
        :rtype: None
        """
        self._ssn = ssn

        try:
            if not isinstance(kwargs['name'], str):
                name_type = type(kwargs["name"]).__name__
                raise TypeError(f"Person() kwargs['name']: got {name_type} but"
                                " expected type is str")
        except KeyError:
            raise KeyError("Person() missing required keyword argument 'name'")
        self._data['name'] = kwargs['name']

        try:
            age_type = type(kwargs["age"]).__name__

            if not isinstance(kwargs['age'], int):
                raise TypeError(f"Person() kwargs['age']: got {age_type} but "
                                "expected type is int")
        except KeyError:
            raise KeyError("Person() missing required keyword argument 'age'")
        self._data['age'] = kwargs['age']

Instead of key you can use keyword.

This example provide :

  • Fully documented docstring used by PyCharm to generate Documentation
  • Type checking + Raise TypeError
  • Default values (bonus: Warn user that a default value is set)

Person

I suggest you adding @property.getter and @property.setter for accessing _id and _data. And the class attribute _data is overkill, you should replace it with _name and _age as you prefer default value instead of no value. Code here.

Warning : Shadows built-in name 'id'

I suggest ssn for social security number.

Sources: PyCharm 2018.3 Help

Dorian Turba
  • 3,260
  • 3
  • 23
  • 67