Skip to content

Style guide diverges from "Single-Source-of-Truth" regarding function parameter type documentation #664

@JoElfner

Description

@JoElfner

In section https://numpydoc.readthedocs.io/en/latest/format.html#parameters (also applies to Returns, ...) the style guide defines that types should be added to each parameter description.

Nowadays, having a well designed Python typing system, documenting parameter types in docstrings is not only outdated, but will also cause code and documentation to diverge from the key principle of Single-Source-of-Truth.

F.i. the following method:

def my_shiny_method(num_a: float, count: int) -> list[float]:
    """
    Create list containing some dummy numbers.

    Parameters
    ----------
    num_a
        Base number to use for filling list.
    count
        Target list length.

    Returns
    -------
    List filled of length `count` with floats.
    """
    return [num_a / count for i in range(count)]

is fully defined, documented and typed, using the typing syntax as the Single-Source-of-Truth.

Requiring type definitions in the docstrings, f.i.

    """
    Create list containing some dummy numbers.

    Parameters
    ----------
    num_a : float
        Base number to use for filling list.
    count : int
        Target list length.

    Returns
    -------
    list[float]
        List filled of length `count` with floats.
    """

is not only superfluous, but also - in my experience - dangerous, because methods etc. tend to be updated over time. And method interfaces may change. In my experience, method interfaces - even in productive code - change more often than desired. And most developers - especially in productive environments - are pushed for time and thus tend to forget to change the irrelevant part - the duplicate types in the docstrings - resulting in something like the following:

def my_shiny_method(num_a: int, count: int) -> list[float]:
    """
    Create list containing some dummy numbers.

    Parameters
    ----------
    num_a : float
        Base number to use for filling list.
    count : int
        Target list length.

    Returns
    -------
    list[float]
        List filled of length `count` with floats.
    """
    return tuple(num_a / count for i in range(count))

--> Now we have diverging typing information
--> Most users will look at the help(method) to see what a method expects. This is, depending on the user's preference, misleading.

This becomes even more problematic when we look at stuff like Literals, which - in modern Python, should be typed

def foo(order: Literal["C", "F", "A"]) -> None: ...

whereas the style guide recommends something using a completely different syntax (set != Literal --> faulty):

order : {'C', 'F', 'A'}
    Description of `order`.

Proposal

  • Recommend to only use the Python typing system
  • If there is a specific requirement of needing types in docstrings, the type syntax should be aligned with the core Python library

Advantages

  • Single-Source-of-Truth!!!
  • No risk of diverging type descriptions
  • All type definitions may easily be checked by mypy or alike
  • All type definitions may be style checked and reformatted by tools like ruff, black, ... Thus type information is less prone to syntax errors like param: type instead of param : type
  • types from namespaces are resolved correctly
  • One and only one typing syntax
  • Doc generators like sphinx nowadays focus on Python typing anyways: no more ambiguous option handling
  • less typing
  • cleaner and simpler docstrings

Challenge

How to format Returns and Yields sections?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions