Skip to content

Chore/docstrings and overrides#139

Open
jc-macdonald wants to merge 5 commits into
mainfrom
chore/docstrings-and-overrides
Open

Chore/docstrings and overrides#139
jc-macdonald wants to merge 5 commits into
mainfrom
chore/docstrings-and-overrides

Conversation

@jc-macdonald
Copy link
Copy Markdown
Collaborator

This pull request adds comprehensive docstrings to internal functions and classes throughout the src/op_system package, significantly improving code readability and maintainability. The new docstrings clarify the purpose, arguments, return values, and exceptions for many utility functions, error classes, and IR (intermediate representation) handling routines. Additionally, an example usage was added to the compile_spec function.

The most important changes are:

Documentation improvements for internal APIs:

Example usage addition:

  • Added an example usage section to the compile_spec function docstring in src/op_system/__init__.py to illustrate its invocation and output.

These improvements make the codebase more accessible to new contributors and facilitate easier debugging and extension.

Add Google-style docstrings to private functions, classes, and methods
across compile.py, _ir.py, _ir_lower.py, _ir_templates.py, _axes.py,
_vectorize.py, _errors.py, _normalize_ir.py, _normalize.py, _symbols.py,
_templates.py, and _typing.py. No behavioral changes.
Add Examples sections with executable >>> blocks to compile_spec,
compile_rhs, normalize_rhs, and normalize_expr_rhs.
Add the missing Returns: and Raises: sections required by ruff DOC2xx/
DOC5xx rules across the docstrings introduced earlier on this branch.
Drop a few inaccurate Raises: claims on helpers that propagate via
`_invalid()`. Also remove a stale FURB140/D102 noqa override by using
itertools.starmap and adding a real EvalFn.__call__ docstring.
Extract small helpers from three functions so each falls under ruff's
default cyclomatic-complexity threshold and the noqa: C901 directives
can be removed:

- _resolve_continuous_range_filter: extract _trapezoidal_weights_or_raise.
- lower_subscript_to_buffer: extract _validate_wildcard_subscript_axes.
- _build_aliases_ir_from_raw: extract _parse_alias_body_to_ir and
  _populate_alias_parsed_maps (with a small _AliasExpansionContext
  NamedTuple so the helper stays under PLR0913).

No behavior change; full suite remains at 396 passing.
@jc-macdonald jc-macdonald self-assigned this May 20, 2026
Copy link
Copy Markdown
Collaborator

@TimothyWillard TimothyWillard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've seen this tuple[list[Any], int] (coords, size) type in a few places. Probably for a follow up but I think it could make sense to convert this to a named tuple/dataclass that is a generic over the list type. Especially since the size is a property of the coords.

Also I've noticed quite a few RST linking directives (e.g. :class:, :meth:, etc.). This project uses MkDocs for the documentation, not sphinx, so these will just be rendered as text. See http://127.0.0.1:8000/op_system/api-reference/compile/#op_system.compile.CompiledRhs.__setstate__ when viewing the documentation locally via just serve. There's mkdocs-autoref for linking, not sure if that's setup for this project or not.

Otherwise looks good, documentation improvements are always great. I think there's still room to add more examples to private helpers that will serve both as documentation and as doctests.

Comment thread src/op_system/_axes.py
@@ -64,6 +78,18 @@ def _normalize_axis_name(ax_map: Mapping[str, Any], *, idx: int, seen: set[str])


def _normalize_axis_type(ax_map: Mapping[str, Any], *, idx: int) -> str:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def _normalize_axis_type(ax_map: Mapping[str, Any], *, idx: int) -> str:
def _normalize_axis_type(ax_map: Mapping[str, Any], *, idx: int) -> Literal["categorical", "continuous", "ordinal"]:

Per the return type. May also make sense to convert this to a StrEnum in the future depending on use.

Comment thread src/op_system/_ir.py
@@ -705,6 +866,15 @@ def _expr_precedence(expr: Expr) -> int:


def _wrap(text: str, *, need: bool) -> str:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: usually when there's a boolean kwarg there's a correct default, I'm guessing maybe _wrap(text: str, *, need: bool = True) -> str based on the logic.

Comment thread src/op_system/__init__.py
Comment on lines +88 to +97

Examples:
>>> import numpy as np
>>> compiled = compile_spec({
... "kind": "expr",
... "state": ["x"],
... "equations": {"x": "-x"},
... })
>>> compiled.eval_fn(0.0, np.array([1.0]))
array([-1.])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really nice, the doctest provides a clear example that is great for users/developers to quickly get an idea of what the function does either before/after reading the docstring itself.

parsed_maps: Pair ``(reduce_parsed, full_parsed)`` of output maps
populated with reduce-form and point-expanded IRs.
"""
from op_system._ir_expand import expand_reduce_pointwise # noqa: PLC0415
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this to avoid a circular import? Usually I think of imports inside of a function as a code smell unless it's to guard against optional functionality which does not apply here.

Comment on lines +587 to +593
def _populate_alias_parsed_maps(
raw_name: str,
canonical_name: str,
ir_raw: Expr,
ctx: _AliasExpansionContext,
parsed_maps: tuple[dict[str, Expr], dict[str, Expr]],
) -> None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this perhaps make more sense as a method of _AliasExpansionContext rather than as a standalone function?

Comment thread src/op_system/compile.py
Comment on lines +856 to +867
Examples:
>>> import numpy as np
>>> from op_system.specs import normalize_rhs
>>> rhs = normalize_rhs({
... "kind": "expr",
... "state": ["x"],
... "equations": {"x": "2.0 * x"},
... })
>>> compiled = compile_rhs(rhs)
>>> y = np.array([3.0])
>>> compiled.eval_fn(0.0, y)
array([6.])
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woo! Doctests are great!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants