Skip to content

entry-description-trailing-period (PDF308)

Added in 1.1.0 Sometimes fix Convention Module and Fragment

Part of the PDF rule category.

View source · View documentation source · Search issues

Fix is sometimes available.

Rule is disabled if docstring-convention is none or pep257, and ignored by broad selectors under google.

Rule is incompatible with PDF309.

What it does

Checks that parsed docstring entry descriptions end with a period.

PDF308 checks Google, NumPy, and reStructuredText entries when the active convention parses them. It targets parameter, return, yield, exception, attribute, and method entry descriptions. For entries with multiline descriptions, the target is the final non-empty parsed description line. Protected nested structures such as lists and fenced code blocks are not folded into the entry description target. This protection also applies when the structure is indented inside a reStructuredText field body and therefore remains owned by that field entry.

Empty descriptions, generic reST fields, and reST type-only fields such as :type:, :rtype:, :ytype:, and :vartype: are skipped. Descriptions ending with a backslash are also skipped so path-like examples are not rewritten. The automatic fix inserts a period when punctuation is absent, replaces a safely mapped final semicolon, and replaces a safely mapped final comma when the entry's next nonblank sibling is not recognized structured content. Question marks, exclamation points, colons, Unicode ellipses (\u2026), and commas that may introduce protected entry content are reported but not changed.

Unsafe source mappings are reported but not changed. This includes docstrings whose relevant logical text is formed through evaluated escape sequences and cannot be mapped cleanly back to one source slice.

Why is this useful?

Consistent entry description punctuation makes section bodies read like complete prose.

Ruff compatibility

None.

Examples

Missing periods are inserted at the end of parsed entry descriptions:

docstring-convention = "google"
def connect(timeout):
    """Connect.

    Args:
        timeout: timeout in seconds
    """
def connect(timeout):
    """Connect.

    Args:
        timeout: timeout in seconds.
    """

Google return and exception entry descriptions are checked the same way:

docstring-convention = "google"
def connect(timeout):
    """Connect.

    Returns:
        bool: whether connection succeeded

    Raises:
        TimeoutError: if the connection times out
    """
def connect(timeout):
    """Connect.

    Returns:
        bool: whether connection succeeded.

    Raises:
        TimeoutError: if the connection times out.
    """

For multiline descriptions, only the final non-empty parsed description line receives the inserted period:

docstring-convention = "google"
def connect(timeout):
    """Connect.

    Args:
        timeout:
            timeout in
            seconds
    """
def connect(timeout):
    """Connect.

    Args:
        timeout:
            timeout in
            seconds.
    """

Nested protected structures do not become part of the description target:

docstring-convention = "google"
def connect(mode):
    """Connect.

    Args:
        mode: choose one
            - fast
            - safe
        timeout: timeout in seconds.
    """
def connect(mode):
    """Connect.

    Args:
        mode: choose one.
            - fast
            - safe
        timeout: timeout in seconds.
    """

NumPy and reStructuredText entry descriptions are checked when those conventions are active:

docstring-convention = "numpy"
def connect(timeout):
    """Connect.

    Parameters
    ----------
    timeout : int
        timeout in seconds

    Returns
    -------
    bool
        whether connection succeeded
    """
def connect(timeout):
    """Connect.

    Parameters
    ----------
    timeout : int
        timeout in seconds.

    Returns
    -------
    bool
        whether connection succeeded.
    """
docstring-convention = "rest"
def connect(timeout):
    """Connect.

    :param timeout: timeout in seconds
    :returns: whether connection succeeded
    """
def connect(timeout):
    """Connect.

    :param timeout: timeout in seconds.
    :returns: whether connection succeeded.
    """

Standalone safely mapped commas and semicolons are replaced with periods, while expressive or structural punctuation is reported but not changed:

docstring-convention = "google"
def connect(timeout, retries, backoff, mode):
    """Connect.

    Args:
        timeout: timeout in seconds?
        retries: retry count,
        backoff: backoff seconds;
        mode: selected mode:
    """
def connect(timeout, retries, backoff, mode):
    """Connect.

    Args:
        timeout: timeout in seconds?
        retries: retry count.
        backoff: backoff seconds.
        mode: selected mode:
    """
PDF308: Line 5: Docstring entry description should end with a period
PDF308: Line 8: Docstring entry description should end with a period

A comma before recognized nested content is reported but not changed because it may introduce that content:

docstring-convention = "google"
def connect(mode):
    """Connect.

    Args:
        mode: choose one,
            - fast
            - safe
    """
PDF308: Line 5: Docstring entry description should end with a period

The same protection applies to nested content inside a reStructuredText field body:

docstring-convention = "rest"
def connect(mode):
    """Connect.

    :param mode: choose one,
        - fast
        - safe
    """
PDF308: Line 4: Docstring entry description should end with a period

An escaped terminal comma has no exact one-character source mapping, so the finding remains non-fixable:

docstring-convention = "google"
def connect(timeout):
    """Connect.

    Args:
        timeout: timeout in seconds\x2c
    """
PDF308: Line 5: Docstring entry description should end with a period

Descriptions ending with a backslash are skipped:

docstring-convention = "google"
def connect(path):
    """Connect.

    Args:
        path: base path \\
    """

reST type-only fields, empty descriptions, and generic fields are skipped:

docstring-convention = "rest"
def connect(timeout):
    """Connect.

    :param timeout:
    :type timeout: int
    :meta private: generated
    """

Safely mapped escapes elsewhere in the docstring do not prevent a source-local fix:

docstring-convention = "google"
def connect(timeout):
    """Connect \u2603.

    Args:
        timeout: timeout in seconds
    """
def connect(timeout):
    """Connect \u2603.

    Args:
        timeout: timeout in seconds.
    """

Options

None.