pydoclint

Checking class attributes


Table of Contents


Class attributes are similar to function arguments. They look like this:

class MyPet:
    name: str
    age_in_months: int
    weight_in_kg: float
    is_very_cute_or_not: bool = True

Oftentimes we’d like to also document them in docstrings and have pydoclint check them. It is controlled by the --check-class-attributes option (see https://jsh9.github.io/pydoclint/config_options.html)

However, none of the mainstream docstring styles (Google, numpy, or Sphinx) offers explicit guidelines on documenting class attributes. Therefore, pydoclint adopts the following stance (i.e., how to write docstrings that pass pydoclint’s check)

Here are some examples showing how to document class attributes in different styles:

1. Numpy style

class MyPet:
    """
    A class to hold information of my pet.

    Attributes
    ----------
    name : str
        Name of my pet
    age_in_months : int
        Age of my pet (unit: months)
    weight_in_kg : float
        Weight of my pet (unit: kg)
    is_very_cute_or_not : bool
        Is my pet very cute?  Or just cute?

    Parameters
    ----------
    airtag_id : int
        The ID of the AirTag that I put on my pet
    """
    name: str
    age_in_months: int
    weight_in_kg: float
    is_very_cute_or_not: bool = True

    def __init__(self, airtag_id: int) -> None:
        self.airtag_id = airtag_id

From this example, we can see a few things:

  1. The class attributes should be put in a different docstring section than the argument passed into the class constructor (__init__())
  2. Both the class attributes and the input arguments to __init__() are in the same docstring. (This is assuming the pydoclint option --allow-init-docstring is False)

If --allow-init-docstring is set to True, we can write two separate docstrings like this:

class MyPet:
    """
    A class to hold information of my pet.

    Attributes
    ----------
    name : str
        Name of my pet
    age_in_months : int
        Age of my pet (unit: months)
    weight_in_kg : float
        Weight of my pet (unit: kg)
    is_very_cute_or_not : bool
        Is my pet very cute?  Or just cute?
    """
    name: str
    age_in_months: int
    weight_in_kg: float
    is_very_cute_or_not: bool = True

    def __init__(self, airtag_id: int) -> None:
        """
        Initialize a class object.

        Parameters
        ----------
        airtag_id : int
            The ID of the AirTag that I put on my pet
        """
        self.airtag_id = airtag_id

2. Google style

class MyPet:
    """
    A class to hold information of my pet.

    Attributes:
        name (str): Name of my pet
        age_in_months (int): Age of my pet (unit: months)
        weight_in_kg (float): Weight of my pet (unit: kg)
        is_very_cute_or_not (bool): Is my pet very cute?  Or just cute?

    Args:
        airtag_id (int): The ID of the AirTag that I put on my pet
    """
    name: str
    age_in_months: int
    weight_in_kg: float
    is_very_cute_or_not: bool = True

    def __init__(self, airtag_id: int) -> None:
        self.airtag_id = airtag_id

You can also use two separate docstrings (one for the class and one for __init__(), similar to the Numpy style.)

3. Sphinx style

class MyPet:
    """
    A class to hold information of my pet.

    .. attribute :: name
        :type: str

        Name of my pet

    .. attribute :: age_in_months
        :type: int

        Age of my pet (unit: months)

    .. attribute :: weight_in_keg
        :type: float

        Weight of my pet (unit: kg)

    .. attribute :: is_very_cute_or_not
        :type: bool

        Is my pet very cute?  Or just cute?

    :param airtag_id: The ID of the AirTag that I put on my pet
    :type airtag_id: int
    """
    name: str
    age_in_months: int
    weight_in_kg: float
    is_very_cute_or_not: bool = True

    def __init__(self, airtag_id: int) -> None:
        self.airtag_id = airtag_id

4. Special note: inline docstrings

PEP-257 indicates that string literals located directly after an assign statement may be treated as attribute documentation. As such, we also optionally support inline docstrings for class attributes with the --require-inline-class-var-docs option set to True (it is False by default). When this option is enabled, class attributes must be documented inline, and the class docstring should not include an “Attributes” section.

Attribute type documentation may be specified as the first thing in the docstring followed by a colon. For example:

class MyClass:
    """My class that does things."""

    field1 = 5
    """int: My first field"""

This applies for all 3 styles (numpy, Google, and Sphinx).