Code Style and Docstring Guide¶
This page documents the code style and docstring conventions used in the Pipeline codebase.
Note: For historical reasons, these rules are not retroactively enforced across the entire codebase. They serve as recommendations and guidelines — please follow them when writing new code or modifying existing code.
GitHub Copilot: The repository includes a
.github/copilot-instructions.mdfile that encodes these same conventions as custom instructions for GitHub Copilot. When using Copilot inside this repository, it will automatically apply the style rules described on this page (type annotation syntax, docstring format, logging style, etc.) to any generated or refactored code.
References¶
Formatting Rules¶
These settings are enforced by ruff (configured in pyproject.toml):
Setting |
Value |
|---|---|
Line length |
120 characters |
Indentation |
4 spaces |
String quotes |
Single quotes ( |
Docstring code block line length |
140 characters |
Type Annotations¶
The codebase targets Python 3.12+. Use modern type syntax throughout:
Avoid |
Use instead |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
All function arguments and return values must have type annotations.
Logging¶
Use lazy %-style formatting — never f-strings — so that the string is only evaluated if the message is actually emitted:
# Bad
logger.info(f'Processing {len(data)} items')
# Good
logger.info('Processing %s items', len(data))
Docstrings¶
Format¶
Use Google-style docstrings (PEP 257 compatible), as parsed by the Napoleon Sphinx extension.
Type information¶
Do not repeat type information in Args or Returns descriptions — it is already captured in the function signature annotations:
# Bad (redundant types in docstring)
def fetch_data(ids: list[int | str]) -> dict:
"""Fetch data.
Args:
ids (list[int | str]): List of IDs.
Returns:
dict: The result.
"""
# Good
def fetch_data(ids: list[int | str]) -> dict:
"""Fetch data.
Args:
ids: List of IDs.
Returns:
The result.
"""
Referring to code symbols¶
Use single backticks for references to functions, classes, methods, and modules in the description body. Sphinx/Napoleon renders these as cross-references:
"""Process data using advanced algorithms.
This function calls `numpy.mean` and `scipy.optimize.minimize`
internally. It is similar to `pandas.DataFrame.apply` but
optimized for numerical arrays.
See Also:
`calculate_stats`: Related function for statistical analysis.
`preprocess_data`: Use this to prepare data before calling this function.
"""
Referring to values and literals¶
Use double backticks (RST inline code) for literal values, option strings, and filenames:
"""Set the ``hm_phaseup`` parameter to ``'snr'`` or ``'manual'``."""
Use italics for file paths or variable names mentioned in a narrative context:
"""The *hm_phaseup* parameter controls the phase-up heuristics."""
Reserve bold for warnings or strong emphasis only:
"""Changing this parameter is **not recommended** for most users."""
Parameters with options and defaults¶
Document options and defaults as sub-items under the parameter description. Use double backticks for each option value:
def run(parallel: str | bool | None = None):
"""Run the task.
Args:
parallel: Process multiple MeasurementSets in parallel using the
casampi parallelization framework.
Options: ``'automatic'``, ``'true'``, ``'false'``, ``True``, ``False``
Default: ``None`` (equivalent to ``False``)
"""
Math¶
For inline math use :math::
"""The condition is :math:`A = \\pi r^2`."""
For display (block) math use the .. math:: directive:
"""
Check whether the S/N condition is satisfied.
The condition is:
.. math::
\\frac{\\text{Peak S/N}}{\\text{dividing\\_factor}} \\times \\mathrm{RMS} < 5.0
"""
Examples section¶
Examples is a first-class Google-style section. Use it for doctestable code:
def add(a: int, b: int) -> int:
"""Add two integers.
Args:
a: The first integer.
b: The second integer.
Returns:
The sum of the two integers.
Examples:
>>> add(2, 3)
5
>>> add(-1, 1)
0
"""
return a + b
Complete example¶
type Vector = list[float]
def fetch_data(ids: list[int | str]) -> dict:
"""Fetch data from the flux service.
Args:
ids: List of source IDs to query.
Returns:
Mapping of ID to flux measurement result.
"""
logger.info('Fetching %s items', len(ids))
return {}
def first[T](items: list[T]) -> T:
"""Return the first element of a list.
Args:
items: Non-empty list of items.
Returns:
The first element.
"""
return items[0]