Skip to content

placeholder-docstring (PDF213)

Added in 1.1.0 Never fix By default Module and Fragment

Part of the PDF rule category.

View source · View documentation source · Search issues

Fix is not available.

What it does

Checks whether a complete evaluated docstring value is one of the configured placeholder markers. The default markers are TODO, TBD, FIXME, pass, XXX, HACK, NotImplemented, and ....

Word markers match ASCII case-insensitively after surrounding whitespace is removed. They may have a trailing run of periods, colons, semicolons, exclamation marks, or question marks, but may not contain additional words. The ellipsis marker matches only exact ....

Configured word markers must begin with an ASCII letter and may otherwise contain ASCII letters, digits, hyphens, and underscores. Changing the marker list replaces the defaults rather than extending them.

PDF213 checks primary module, class, function, and method docstrings plus supported attached module, class, and instance attribute docstrings. Matching uses the evaluated docstring value, so escape sequences and implicitly concatenated literals are handled as one value. Findings cover every physical line occupied by the complete literal.

Why is this useful?

A placeholder satisfies Python's docstring syntax without supplying useful documentation. Reporting exact whole-docstring markers identifies unfinished documentation without flagging real prose that happens to mention a task marker.

Ruff compatibility

PDF213 is related to Ruff's D419, which reports empty docstrings. Ruff does not report nonempty placeholder docstrings.

Examples

PDF213 reports a configured marker with terminal punctuation:

docstring-placeholder-markers = ["TODO", "NotImplemented", "..."]
def load():
    """TODO."""
PDF213: Line 2: Docstring is a placeholder

Additional prose prevents a match:

docstring-placeholder-markers = ["TODO", "NotImplemented", "..."]
def load():
    """TODO: Describe retry behavior."""

The marker inventory is configurable and matching preserves conventional configured spelling:

docstring-placeholder-markers = ["WorkInProgress"]
def load():
    """workinprogress!"""
PDF213: Line 2: Docstring is a placeholder

Evaluated concatenated values are matched as one docstring, and the finding covers the complete expression:

docstring-placeholder-markers = ["TODO"]
def load():
    ("TO"
     "DO!")
PDF213: Lines 2-3: Docstring is a placeholder

Supported attached attribute docstrings are checked as well:

docstring-placeholder-markers = ["TODO"]
class Client:
    timeout = 30
    """TODO"""
PDF213: Line 3: Docstring is a placeholder

An empty marker inventory keeps the rule selectable but suppresses all placeholder findings:

docstring-placeholder-markers = []
def load():
    """TODO"""

Options

  • docstring-placeholder-markers: Configure the whole-docstring marker labels recognized as placeholders. An empty list suppresses findings without changing rule selection.