Skip to content

Docstring & Type Hint Guidelines

This page defines the conventions for writing docstrings (see Docstring Guidelines) and using type hints (see Typing Guidelines) in this project. We follow NumPy-style docstrings and use Python type hints as the single source of truth for parameter and return types. Target runtime: Python ≥ 3.11.


1. General Principles

  • Always use Python type hints → types live in the function signature, not duplicated in the docstring.
  • Docstrings focus on:

  • What the function does.

  • Meaning and units of parameters.
  • Return value meaning.
  • State/variables updated (Modifies).
  • Functions called (Calls).
  • Expected errors (Raises).
  • Use NumPy-style sections for readability and doc tool compatibility.

2. Example Function with Full Docstring

Below is an example that demonstrates the recommended style for docstrings and type hints in this project. It shows how to document parameters, returns, modifications, calls, and exceptions.

from pathlib import Path
from typing import Final

import numpy as np
import numpy.typing as npt
import pydicom
from pydicom.dataset import FileDataset

# Example constant with a type hint
EPS: Final[float] = 1e-12


def update_dose_matrix(
    rt_dose: FileDataset,
    new_matrix: npt.NDArray[np.float32],  # shape: (z, y, x), Gy
    normalize: bool = True,
) -> None:
    """
    Update the dose matrix inside an RTDOSE DICOM object.

    Parameters
    ----------
    rt_dose
        DICOM RTDOSE dataset to update.
    new_matrix
        New 3D dose grid ``(z, y, x)`` in **Gy**.
    normalize
        If ``True``, rescale values to match ``DoseGridScaling``.

    Returns
    -------
    None

    Modifies
    --------
    rt_dose.pixel_array
        Replaces the internal dose grid with ``new_matrix``.
    rt_dose.DoseGridScaling
        Updated if ``normalize=True``.

    Calls
    -----
    validate_dose_matrix, rescale_dose

    Raises
    ------
    ValueError
        If ``new_matrix`` has incompatible shape or contains NaNs.
    """
    # (implementation here)
    pass

3. Typing Examples (Python 3.11 syntax)

Use modern forms (| unions, built‑in generics) and concrete library types.

from pathlib import Path
import SimpleITK as sitk
import pydicom
from pydicom.dataset import FileDataset

# Accept both strings and Paths; may return nothing

def load_rtplan(path: str | Path | None = None) -> FileDataset | None:
    ...

# Simple union narrowing

def parse_value(x: int | float) -> float:
    ...

# Tuples with built-in generics

def resample_ct(img: sitk.Image, spacing: tuple[float, float, float]) -> sitk.Image:
    ...

# Collections with built-in generics

def summarize(ds_list: list[FileDataset]) -> dict[str, str]:
    ...

Tip: For arrays, prefer numpy.typing.NDArray with explicit dtypes, e.g. npt.NDArray[np.float32].


4. Docstring Template (NumPy style)

Copy this template when adding new functions.

def function_name(param1: int, param2: str | None = None) -> bool:
    """
    One-sentence summary in the imperative mood.

    Extended description (what, why, and context). Keep types in the signature,
    and focus here on meaning, units, shapes, side effects, and behavior.

    Parameters
    ----------
    param1
        Meaning of param1; units if applicable.
    param2
        Meaning of param2; when ``None`` is allowed and what it means.

    Returns
    -------
    bool
        What ``True``/``False`` indicate.

    Modifies
    --------
    obj.attr
        What object/attribute is modified (if any).

    Calls
    -----
    other_function, helper

    Raises
    ------
    ValueError
        When inputs are invalid (describe conditions).
    RuntimeError
        When an unexpected state is encountered.
    """
    ...

5. Common Pitfalls

  • Don’t duplicate types in the docstring — keep them in the signature.
  • Document shapes and units (e.g., (z, y, x), mm, Gy) in the docstring text.
  • Prefer concrete library types: sitk.Image, pydicom.dataset.FileDataset.
  • Be precise with Path: accept str | Path in public APIs.
  • Use Final for constants and annotate dataclass/attrs fields.