Skip to content

Fix shared-CONSTANTS state leaks in doctests, wire up doctest CI#213

Merged
derek73 merged 1 commit into
masterfrom
fix/doctest-state-leaks-and-ci
Jul 4, 2026
Merged

Fix shared-CONSTANTS state leaks in doctests, wire up doctest CI#213
derek73 merged 1 commit into
masterfrom
fix/doctest-state-leaks-and-ci

Conversation

@derek73

@derek73 derek73 commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary

  • Several doc/docstring examples mutated the shared CONSTANTS singleton (capitalize_name, force_mixed_case_capitalization, empty_attribute_default, titles.clear()) without resetting it afterward. Since Sphinx's doctest groups only isolate local variables (not global state), these mutations leaked forward across the entire doc build in an order-dependent way, causing several previously-undetected doctest failures:
    • JEFFREY (JD) BRICKEN example wrongly showing capitalized output
    • as_dict() returning None instead of '' for empty fields
    • "Sir Bob Andrew Dole".initials() returning 'S. B. A. D.' instead of 'B. A. D.' (because CONSTANTS.titles had been cleared and never restored, so "Sir" leaked into first_list)
  • SetManager.__repr__ printed a plain Python set, whose iteration order depends on per-process string hash randomization — the same code produced different-looking output on every run, making the {'right', ..., 'tax'} ellipsis-style doc examples fundamentally unreproducible.
  • Two smaller doc-only bugs in customize.rst: an emoji example showed repr(hn) output but was written as if it were str(hn); CONSTANTS.titles.clear() was documented as producing no output, but clear() returns self (chainable) and so prints SetManager(set()).

Changes

  • nameparser/config/__init__.py: reset CONSTANTS at the end of each docstring demo; SetManager.__repr__ now sorts elements so its output is deterministic across processes.
  • docs/usage.rst: reset CONSTANTS.capitalize_name / force_mixed_case_capitalization after their respective demo blocks.
  • docs/customize.rst: switched the "Hon" removal / clear-titles demo to a local Constants() instance instead of the shared singleton, since that section isn't actually teaching shared-singleton behavior (the "Module-level Shared Configuration Instance" section further down still correctly uses the shared singleton, since demonstrating that gotcha is its whole point); fixed the emoji example to call str(hn); updated the SetManager ellipsis examples to match the now-sorted repr.
  • .github/workflows/python-package.yml: added sphinx-build -b doctest docs dist/doctest and python -m doctest README.rst so this class of regression is caught automatically going forward, across all 5 Python versions in the CI matrix.

Test plan

  • pytest -q — 1270 passed, 4 skipped, 22 xfailed (unchanged baseline)
  • sphinx-build -b doctest docs ... — 186/186 passed (previously multiple failures across usage.rst, customize.rst, and parser.py's own docstrings)
  • python -m doctest README.rst — 10/10 passed
  • Verified SetManager.__repr__ produces identical output across separate process invocations (previously varied per run)

🤖 Generated with Claude Code

Several docstring/doc examples mutated the shared CONSTANTS singleton
(capitalize_name, force_mixed_case_capitalization, empty_attribute_default,
titles.clear()) without resetting it. Since Sphinx's doctest groups only
isolate local variables, not global state, these leaked forward into later
examples across the whole doc build in an order-dependent way -- causing
wrong capitalization in the nicknames example, as_dict() returning None,
"Sir" leaking into first_list once titles was cleared, and more.

- nameparser/config/__init__.py: reset CONSTANTS after each docstring demo;
  make SetManager.__repr__ sort elements so it's deterministic across
  processes (previously relied on set() iteration order, which varies with
  string hash randomization)
- docs/usage.rst: reset CONSTANTS.capitalize_name /
  force_mixed_case_capitalization after their demo blocks
- docs/customize.rst: switch the "Hon" removal/clear-titles demo to a
  local Constants() instance instead of the shared singleton (it isn't
  actually demonstrating shared-singleton behavior, so there's no need to
  mutate global state); fix the emoji example to call str(hn) instead of
  showing hn's repr; update the SetManager ellipsis examples to match the
  now-sorted repr

All 186 Sphinx doctests and the 10 README.rst doctests now pass (previously
multiple failures across usage.rst, customize.rst, and parser.py's own
docstrings). Wired both into CI (.github/workflows/python-package.yml) so
this doesn't silently regress again.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@derek73 derek73 self-assigned this Jul 4, 2026
@derek73 derek73 added this to the v1.3.0 milestone Jul 4, 2026
@derek73 derek73 added enhancement docs Documentation fixes and updates labels Jul 4, 2026
@derek73 derek73 merged commit e8d4522 into master Jul 4, 2026
8 checks passed
@derek73 derek73 deleted the fix/doctest-state-leaks-and-ci branch July 4, 2026 23:37
derek73 added a commit that referenced this pull request Jul 5, 2026
The Gotchas section said docs/*.rst doctests and README.rst weren't run
by pytest or CI, and that customize.rst had pre-existing failures under
-b doctest (CONSTANTS state leaks, non-deterministic SetManager repr).
Both are now fixed and wired into CI (see #213), so the note was stale.
Replaced it with the actual current behavior and the reset/local-instance
pattern to follow when adding new CONSTANTS-mutating examples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs Documentation fixes and updates enhancement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant