Skip to content

Commit 72135b3

Browse files
derek73claude
andcommitted
Update AGENTS.md from simplify-session learnings
- Curated sub-set invariants are pinned with import-time asserts in the config module (prefixes.py), not invariant tests -- the old guidance contradicted the cleanup that removed those tests as unreachable - Document FlaggedConstantsTestBase/constants_kwargs as the fixture for test classes that parse with a dedicated flagged Constants - Refresh the stale test-count example (~630 methods -> ~1250 results) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent b64a44f commit 72135b3

1 file changed

Lines changed: 4 additions & 2 deletions

File tree

AGENTS.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Branch naming: `fix/issue-NNN-short-description` or `feat/short-description`.
1414
# Alternative: .venv/bin/<tool> if the venv is already active
1515

1616
# Run all tests (includes --doctest-modules, so doctests in nameparser/ are also run;
17-
# the dual-parametrize fixture doubles the count, so ~370 methods → ~740 results)
17+
# the dual-parametrize fixture doubles the count, so ~630 methods → ~1250 results)
1818
uv run pytest # --doctest-modules is set in pyproject.toml, so doctests run automatically
1919

2020
# Run a single test file / class / method
@@ -120,7 +120,7 @@ Add a dedicated `copy.deepcopy()` round-trip test for it too (see `test_regexes_
120120

121121
**Before adding a short/common word to `PREFIXES` globally**, test it mid-string against realistic 3-token names, not just check for English-word collisions: Korean/Vietnamese given names put a short syllable in the middle slot (`Park In Hwan`, `Nguyen To Nga`), and Western names put a bare initial there (`John V. Smith`). A word that looks safe ("nobody is named 'to'") can still swallow a real middle name/initial into the last name once it's a global prefix — confirmed regressions for `to`/`in`/`an`/`ten`/`then` and bare `v` this way (PR #191).
122122

123-
**Adding a curated sub-set of an existing config set** (must stay ⊆ its parent, e.g. `FIRST_NAME_TITLES` ⊂ `TITLES`) — define the parent as a *static* union in the config module: `TITLES = FIRST_NAME_TITLES | set([...])`. The sub-set is a plain `SetManager` on `Constants` (like `first_name_titles`), **not** a `_CachedUnionMember` — only `prefixes`/`suffix_acronyms`/`suffix_not_acronyms`/`titles` feed the `_pst` hot-path cache, so a sub-set costs nothing at runtime and stays out of `is_rootname`. The union is import-time only: a runtime `.add()` to the sub-set does **not** propagate to the parent's `SetManager` (same as `first_name_titles`→`titles`), so a caller adding a brand-new word adds it to both. Pin the relationships with invariant tests on the *defaults*: `subset ⊆ parent`, and `∩ == ∅` with any set it logically can't overlap (a sub-set member that's also in `TITLES` is silently inert — title handling consumes it first). Do **not** test `titles ∩ prefixes == ∅` — that overlap is intentional (`st`, `do`).
123+
**Adding a curated sub-set of an existing config set** (must stay ⊆ its parent, e.g. `FIRST_NAME_TITLES` ⊂ `TITLES`) — define the parent as a *static* union in the config module: `TITLES = FIRST_NAME_TITLES | set([...])`. The sub-set is a plain `SetManager` on `Constants` (like `first_name_titles`), **not** a `_CachedUnionMember` — only `prefixes`/`suffix_acronyms`/`suffix_not_acronyms`/`titles` feed the `_pst` hot-path cache, so a sub-set costs nothing at runtime and stays out of `is_rootname`. The union is import-time only: a runtime `.add()` to the sub-set does **not** propagate to the parent's `SetManager` (same as `first_name_titles`→`titles`), so a caller adding a brand-new word adds it to both. Pin the relationships with import-time `assert`s in the config module itself (see the bottom of `prefixes.py`): `subset ⊆ parent`, and `∩ == ∅` with any set it logically can't overlap (a sub-set member that's also in `TITLES` is silently inert — title handling consumes it first). A violated assert fails at import — before any test runs — so don't also duplicate them as tests. Do **not** assert `titles ∩ prefixes == ∅` — that overlap is intentional (`st`, `do`).
124124

125125
**Adding a flag-gated post-parse transform** (reorder/adjust) — add a `Constants` boolean (default `False`), implement a `handle_*()` method, and call it in `post_process()` after `handle_firstnames()` and before `handle_capitalization()`, gated on the flag. Default-off keeps existing parses byte-for-byte unchanged. Two shipped examples: `patronymic_name_order` gates both `handle_east_slavic_patronymic_name_order()` (#85) and `handle_turkic_patronymic_name_order()` (#185) — one flag driving two independent handlers, added in the same `post_process()` slot; `middle_name_as_last` gates `handle_middle_name_as_last()` (#133), which folds `middle_list` into `last_list`.
126126

@@ -175,3 +175,5 @@ A parse-behavior test can still be a disguised constant-content test if it only
175175
**`python_classes = ["*Tests", "*TestCase"]`** in `pyproject.toml` — suffix style (`FooTests`), NOT prefix (`TestFoo`); wrong style silently skips discovery.
176176

177177
Tests run under **pytest** (via `uv run pytest`) and are split one file per concern (`tests/test_titles.py`, `tests/test_suffixes.py`, etc.). `tests/base.py` holds `HumanNameTestBase` — a plain (non-`unittest`) base whose `m()` helper is a custom assert that prints the original name string on failure (plus thin `assert*` shims so the moved test bodies are unchanged). `tests/conftest.py` defines an autouse fixture that runs **every test twice** — once with `empty_attribute_default = ''` and once with `None` — so reported counts are doubled (e.g. 11 methods → 22 results); it also snapshots/restores the scalar `CONSTANTS` config around each test to keep tests order-independent. `TEST_NAMES` (in `tests/test_variations.py`) is a list of name strings permuted into comma-separated variants as a regression check. Tests that should fail use `@pytest.mark.xfail`. When adding a parsing case, add it to the relevant `tests/test_*.py` file and consider adding the base form to `TEST_NAMES`.
178+
179+
Test classes that parse with a dedicated flagged `Constants` (e.g. `patronymic_name_order=True`) subclass `FlaggedConstantsTestBase` (`tests/base.py`) and set `constants_kwargs = {...}` — don't hand-write per-class `setup_method`/`hn()` fixture pairs.

0 commit comments

Comments
 (0)