diff --git a/AGENTS.md b/AGENTS.md index b79300dd..11b1d85f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -402,7 +402,7 @@ Every `.. doctest::` block in one `.rst` file shares a single namespace — the Don't use the bare `python3 -m doctest .rst` CLI (no `optionflags`) to check files under `docs/` — it ignores each block's `:options:` directive (e.g. `+NORMALIZE_WHITESPACE`, `+ELLIPSIS`) and reports false-positive whitespace failures that look like real regressions. `uv run sphinx-build -b doctest docs ` is the faithful check for those. `README.rst` has no `:options:` directives (plain `::` blocks, not `.. doctest::`), so the bare `python -m doctest README.rst` CLI is fine there — that's what CI actually runs. -`Constants` class attributes (e.g. `patronymic_name_order`, `middle_name_as_last`) document behavior with a bare string literal placed right after the assignment — Sphinx's attribute-docstring convention. That string never becomes a real `__doc__`, so `--doctest-modules` (which walks `__doc__` attributes) never sees any `.. doctest::` examples inside it — this let a stale example slip through CI once (`middle_name_as_last`, #133). `tests/test_config_attribute_docstrings.py` (#195) closes that gap: it parses `nameparser/config/__init__.py` with `ast` to recover those literals and runs any doctest examples through `doctest.DocTestParser`/`DocTestRunner` explicitly, so `pytest -q` now exercises them too. When adding or editing a `.. doctest::` example in a `Constants` attribute's bare-string docstring, this is the mechanism that actually runs it — don't assume `--doctest-modules` covers it. +**A `Constants` attribute docstring is not a place for a doctest, and nothing runs one there (2.0 note; the rest of this paragraph is v1 history).** v1's `Constants` documented attributes like `patronymic_name_order` with a bare string literal after the assignment, Sphinx's attribute-docstring convention. That string never became a real `__doc__`, so `--doctest-modules` (which walks `__doc__` attributes) never saw a `.. doctest::` inside it, and a stale example once slipped through CI (`middle_name_as_last`, #133); `tests/test_config_attribute_docstrings.py` (#195) recovered those literals with `ast` and ran their examples explicitly. Both halves are gone: since the M11 swap the real `Constants` lives in `nameparser/_config_shim.py` with bare type annotations (`patronymic_name_order: bool`) and no attribute docstrings, and the test was deleted in M12 (`a689e1d8`) because its AST walk found no class in the re-export shim and nothing to run in the real one. If an attribute docstring with an example ever returns, remember that `--doctest-modules` will not see it: put the example in a unit test instead, per the lean-docs rule in the 2.0 conventions above. **`uv run mypy` covers `tests/` too** (`pyproject.toml`'s `[tool.mypy] packages = ["nameparser", "tests"]`, PR #250) — a test that deliberately passes an off-contract value to assert a `TypeError`/`ValueError`, or exercises a documented falsy-disables-the-feature toggle (e.g. `regexes.emoji = False`), needs a `# type: ignore[code]` comment on that line rather than a signature change. Before reaching for an ignore, check whether the "error" is really a source annotation that hasn't caught up with already-supported runtime behavior (e.g. `is_prefix`/`is_conjunction`/`is_suffix` accepting `list[str]`, `add_with_encoding` accepting `bytes`) — widen the annotation instead in that case.