agentsclimarketplace

Python documentation standards

Skill CowDogMoo/squad-agents/skills/python-documentation-standards

Python documentation standards — PEP 257 docstrings, PEP 8 comments, type hints, codetags, linter directives, common mistakes, when to refactor instead of document, and a quality checklist. Use when writing or auditing docstrings on a Python package. Also loaded by the python-doc-comments agent as its knowledge base.From its SKILL.md

Install
npx -y skills add CowDogMoo/squad-agents --skill python-documentation-standards

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 4 stars4 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

19.2 KB, as published. Nobody here has run it

Python Documentation Standards

A comprehensive guide to Python documentation following PEP 8, PEP 257, and modern best practices. This document serves as the knowledge base for the python-doc-comments pattern.

Table of Contents

  1. Core Principles
  2. Docstrings (PEP 257)
  3. Comments (PEP 8)
  4. Type Hints
  5. Codetags
  6. Magic Comments
  7. Linter Directives
  8. Common Mistakes
  9. When to Refactor Instead of Document
  10. Quality Checklist

Core Principles

The Golden Rules

PrincipleDescription
Triple double quotesAlways use """ for docstrings
Complete sentencesProper capitalization and punctuation
Explain "why"Code shows "what", comments explain "why"
User focusDocument for users, not implementation
SynchronizeOutdated comments are worse than none
Use sparinglyPrefer clear code over excessive comments

Philosophy

  • Self-documenting code is the first priority
  • Comments should add value, not state the obvious
  • Type hints complement docstrings, not replace them
  • Professional tone in all documentation

Docstrings (PEP 257)

Docstrings become the __doc__ attribute of modules, functions, classes, and methods.

One-Line Docstrings

For simple, obvious cases:

def kos_root():
    """Return the pathname of the KOS root directory."""
    global _kos_root
    return _kos_root

Rules:

  • Closing quotes on the same line
  • Imperative mood: "Return X" not "Returns X"
  • End with a period
  • No blank lines before or after
  • Never restate the function signature — describe the return value's nature instead
  • Use r"""raw triple double quotes""" if backslashes appear in the docstring

Multi-Line Docstrings

For complex documentation:

def complex(real=0.0, imag=0.0):
    """Form a complex number.

    Keyword arguments:
    real -- the real part (default 0.0)
    imag -- the imaginary part (default 0.0)
    """
    if imag == 0.0 and real == 0.0:
        return complex_zero

Structure:

  1. Summary line (fits on one line)
  2. Blank line
  3. Detailed description
  4. Closing quotes on separate line

Module Docstrings

"""A one-line summary of the module, terminated by a period.

Leave a blank line. The rest of this docstring should contain an
overall description of the module. Optionally, it may also contain
a brief description of exported classes and functions.

Typical usage example:

    foo = ClassFoo()
    bar = foo.function_bar()
"""

import os
import sys

Placement:

  • Must be the first statement in the module
  • Comes after magic comments (shebang, encoding)
  • Comes before imports

Function/Method Docstrings (Google Style)

def fetch_bigtable_rows(big_table, keys, other_silly_variable=None):
    """Fetch rows from a Bigtable.

    Retrieve rows pertaining to the given keys from the Table instance
    represented by big_table.

    Args:
        big_table: An open Bigtable Table instance.
        keys: A sequence of strings representing the key of each table
            row to fetch.
        other_silly_variable: Another optional variable, that has a much
            longer name than the other args.

    Returns:
        A dict mapping keys to the corresponding table row data fetched.
        Each row is represented as a tuple of strings. For example:

        {'Serak': ('Rigel VII', 'Preparer'),
         'Zim': ('Irk', 'Invader')}

    Raises:
        IOError: An error occurred accessing the bigtable.Table object.
    """
    pass

Sections:

SectionPurpose
ArgsList each parameter with description
ReturnsDescribe the return value and its type
YieldsFor generators
RaisesDocument exceptions that may be raised

Class Docstrings

class SampleClass:
    """Summary of class here.

    Longer class information and detailed description.

    Attributes:
        likes_spam: A boolean indicating if we like SPAM or not.
        eggs: An integer count of the eggs we have laid.
    """

    def __init__(self, likes_spam=False):
        """Initialize the instance based on spam preference.

        Args:
            likes_spam: Defines if instance exhibits this preference.
        """
        self.likes_spam = likes_spam
        self.eggs = 0

Key Points:

  • Summarize what instances represent
  • List public attributes in Attributes section
  • Document __init__ separately

Docstring Styles Comparison

Google Style (recommended):

def function(arg1: int, arg2: str) -> bool:
    """Summary line.

    Args:
        arg1: Description of arg1.
        arg2: Description of arg2.

    Returns:
        Description of return value.

    Raises:
        ValueError: When validation fails.
    """
    pass

NumPy Style (scientific computing):

def function(arg1: int, arg2: str) -> bool:
    """Summary line.

    Parameters
    ----------
    arg1 : int
        Description of arg1.
    arg2 : str
        Description of arg2.

    Returns
    -------
    bool
        Description of return value.

    Raises
    ------
    ValueError
        When validation fails.
    """
    pass

Sphinx/reStructuredText Style:

def function(arg1: int, arg2: str) -> bool:
    """Summary line.

    :param arg1: Description of arg1
    :type arg1: int
    :param arg2: Description of arg2
    :type arg2: str
    :return: Description of return value
    :rtype: bool
    :raises ValueError: When validation fails
    """
    pass

Important: Do not mix styles within a project. Choose one and be consistent.

Sphinx Integration: For Google or NumPy style docstrings to work with Sphinx documentation, add the sphinx.ext.napoleon extension to your conf.py.


Comments (PEP 8)

Block Comments

Block comments apply to code that follows them.

# Filter out inactive users and sort by registration date.
# This is necessary because the database query doesn't
# guarantee ordering for performance reasons.
active_users = [u for u in users if u.is_active]
return sorted(active_users, key=lambda u: u.registered_at)

Rules:

  • Start with # followed by a single space
  • Indent to the same level as the code
  • Separate paragraphs with a line containing only #

Inline Comments

Inline comments appear on the same line as code. Use sparingly.

# Good: Explains non-obvious reasoning
x = x + 1  # Compensate for border offset in rendering

# Good: Clarifies business logic
discount = 0.9  # 10% discount for premium members

# Bad: States the obvious
x = x + 1  # Increment x

Rules:

  • Separate from code by at least 2 spaces
  • Start with # and a single space
  • Maximum 72 characters recommended
  • Use sparingly - only when adding real value

When Comments Add Value

# Explains business logic
discount = 0.25 if user.is_grandfathered else 0.20

# Warns about gotchas
# Note: This modifies the list in-place
items.sort()

# Documents performance implications
# Using dict lookup O(1) instead of list search O(n)
user_map = {user.id: user for user in users}

# Explains non-obvious algorithms
# Boyer-Moore voting algorithm - O(n) time, O(1) space
candidate = None

Type Hints

Type hints complement docstrings by providing static type information.

Basic Types

def greeting(name: str) -> str:
    """Return a greeting message."""
    return f'Hello {name}'

Complex Types

from typing import List, Dict, Optional, Union

def process_items(
    items: List[str],
    config: Optional[Dict[str, Union[str, int]]] = None
) -> List[Dict[str, str]]:
    """Process items with optional configuration.

    Args:
        items: List of item names to process.
        config: Optional configuration dictionary.

    Returns:
        List of processed item dictionaries.
    """
    pass

Modern Python (3.10+)

def process(items: list[str], config: dict[str, str | int] | None = None) -> list[dict[str, str]]:
    """Process items with optional configuration."""
    pass

Key Points

AspectDescription
Static analysisUsed by mypy, pyright, IDEs
DocumentationHuman-readable, stays in code
RuntimeType hints don't enforce at runtime
CombinationUse both type hints AND docstrings

Codetags

Standardized annotations that flag code requiring attention.

Common Tags

TagPurposeExample
TODOPending tasks# TODO: Add input validation
FIXMECode needing fixes# FIXME: Memory leak in loop
XXXSynonym for FIXME# XXX: This breaks with unicode
BUGKnown defects# BUG: Tracked as JIRA-456
HACKTemporary workarounds# HACK: Works around API bug
NOTEImportant clarifications# NOTE: Requires Python 3.8+

Format with Metadata

# TODO: Refactor this function. <JD d:2026-01-15 p:2>
def legacy_code():
    pass

# FIXME: Memory leak in loop. <AS t:JIRA-789 p:1>
def leaky_function():
    pass

Metadata Fields:

  • <initials> - Owner/author
  • d:date - Due date (ISO 8601)
  • p:0-3 - Priority (0=highest)
  • t:id - Tracker reference

Best Practices

  1. Include ownership (initials or name)
  2. Add context (ticket numbers, due dates)
  3. Be specific about the problem
  4. For serious issues, create tickets in issue tracker
  5. Keep TODOs temporary - fix or move to tracker

Magic Comments

Special comments that provide instructions to the interpreter.

Shebang Line

#!/usr/bin/env python3

Rules:

  • Must be the first line
  • #!/usr/bin/env python3 is portable (uses PATH)
  • Only needed for executable scripts

Encoding Declaration (PEP 263)

# -*- coding: utf-8 -*-

Rules:

  • Must be on first or second line
  • Usually unnecessary (UTF-8 is default in Python 3)
  • Required only for non-UTF-8 encodings

Complete File Header

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Module docstring comes after magic comments.

This is the proper order for file headers in Python.
"""

import os
import sys

Linter Directives

Special comments to control static analysis tools.

Type Checking (mypy, pyright)

# type: ignore
result = some_untyped_function()  # type: ignore

# Specific error
value = process(wrong_type)  # type: ignore[arg-type]

Style Checking (flake8)

# noqa
long_line = "Very long line"  # noqa

# Specific rule
another_long_line = "Long line"  # noqa: E501

# Unused import
from module import unused  # noqa: F401

Linting (pylint)

# pylint: disable=line-too-long
very_long_line = "Intentionally long"

# pylint: disable=broad-except
try:
    risky()
except Exception:  # pylint: disable=broad-except
    handle()

Code Coverage

def debug_function():  # pragma: no cover
    """Only used during development."""
    print("Debug")

if __name__ == "__main__":  # pragma: no cover
    main()

Formatting (black)

# fmt: off
matrix = [
    [1, 0, 0],
    [0, 1, 0],
    [0, 0, 1],
]
# fmt: on

Best Practices for Directives

  1. Be specific - use exact error codes
  2. Add explanations - why ignoring?
  3. Minimize scope - apply to smallest section
  4. Review regularly - suppressed warnings may hide issues

Common Mistakes

Redundant Comments

Bad:

x = x + 1  # Increment x
name = "John"  # Set name to John

Good:

x = x + 1  # Compensate for zero-based indexing

Redundant Docstrings

Bad:

def add(a, b):
    """Add two numbers.

    This function takes two numbers and adds them together.
    It returns the sum of a and b.
    """
    return a + b

Good:

def add(a, b):
    """Return the sum of a and b."""
    return a + b

Commented-Out Code

Bad:

def current():
    # old_way()
    # previous_version()
    return new_way()

Good:

def current():
    return new_way()

Lying Comments

Bad:

# Return the user's full name
def get_username(user):
    return user.email  # Actually returns email!

Mumbling

Comments where the developer is talking to themselves rather than the reader. These add confusion instead of clarity.

Bad:

# I think this works but not sure
result = parse(data)

# This probably needs to be changed later
cache = {}

Apologetic Comments

Comments that apologize for bad code instead of fixing it.

Bad:

# Sorry, this is a mess
# I know this is ugly but it works
# TODO: clean this up someday
def process(data):
    ...

Solution: Clean up the code. If the code needs explanation, refactor it so it doesn't.

Over-Commenting

Bad:

def process_order(order):
    # Validate the order
    if not order.is_valid():
        # Raise exception if invalid
        raise ValueError("Invalid order")

    # Calculate the total
    total = order.calculate_total()

    # Return the final total
    return total

Good:

def process_order(order):
    if not order.is_valid():
        raise ValueError("Invalid order")
    return order.calculate_total()

Missing Type Context

Old way (duplicates type info):

def process_user(user):
    """Process a user.

    Args:
        user (dict): User dictionary with 'id', 'name', 'email'

    Returns:
        bool: True if successful
    """
    pass

Modern way (types in signature):

from typing import TypedDict

class User(TypedDict):
    id: int
    name: str
    email: str

def process_user(user: User) -> bool:
    """Process a user and update the database."""
    pass

When to Refactor Instead of Document

Before writing a comment or docstring, ask: Can I make this clearer through code?

Heavy commenting often signals deeper issues. If you need long explanations to justify confusing code, refactor first.

Refactoring Alternatives

Instead of...Try...
# Get the third itemcategory = row[2] or tuple unpacking
# Check if validdef is_valid_email(email):
# Magic number for retryMAX_RETRIES = 3
# Loop over itemsUse descriptive variable names
# Convert to uppercaseThe code is already clear — delete the comment

Five Alternatives to Comments

  1. Use descriptive names — rename functions or variables to clarify intent
  2. Extract unnamed code blocks — create helper functions with meaningful names
  3. Name embedded values — create constants for magic numbers and strings
  4. Apply tuple unpacking — replace index-based access with named variables
  5. Add or improve docstrings — use structured docstrings instead of inline comments

When Documentation Is Valuable

  • Explaining "why" — business rules, edge cases, workarounds
  • Linking to external references — bug tickets, specs, RFCs
  • Warning about non-obvious behavior — side effects, gotchas
  • TODO/FIXME — with ticket numbers for tracking
  • Legal/licensing — copyright notices, license headers
  • Complex algorithms — references to papers or explanations

Tools and Automation

Recommended Tools

ToolPurpose
blackCode formatting
isortImport sorting
mypyType checking
pylintLinting
flake8Style checking
pydocstyleDocstring checking

pyproject.toml Configuration

[tool.black]
line-length = 88

[tool.mypy]
strict = true

[tool.pylint.messages_control]
max-line-length = 88

[tool.pydocstyle]
convention = "google"

Documentation Generators

ToolDescription
SphinxFull documentation suite
MkDocsMarkdown-based docs
pdocAuto-generated API docs

Quality Checklist

Docstrings

  • Triple double quotes (""")
  • All public modules, classes, and functions that need documentation are documented (trivial/self-documenting ones listed as skipped, not documented)
  • One-line format for simple cases
  • Multi-line format with summary, blank line, details
  • Args, Returns, Raises sections for functions
  • Attributes section for classes
  • Imperative mood for one-liners

Comments

  • Block comments indented with code
  • Inline comments used sparingly (2+ spaces)
  • Explain "why" not "what"
  • No obvious or redundant comments
  • Complete sentences with proper grammar
  • Updated when code changes

Type Hints

  • Used for function parameters and returns
  • Complex types imported from typing
  • Complement docstrings, not replace them

Tool Integration

  • Linter directives used sparingly
  • Specific error codes when possible
  • Code formatted consistently

Code Quality

  • Code is self-documenting with clear names
  • No commented-out code
  • TODOs include context and ownership
  • Professional and respectful tone

References


Last updated: 2026-03-17

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.