Fix shared-CONSTANTS state leaks in doctests, wire up doctest CI#213
Merged
Conversation
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
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
CONSTANTSsingleton (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) BRICKENexample wrongly showing capitalized outputas_dict()returningNoneinstead of''for empty fields"Sir Bob Andrew Dole".initials()returning'S. B. A. D.'instead of'B. A. D.'(becauseCONSTANTS.titleshad been cleared and never restored, so "Sir" leaked intofirst_list)SetManager.__repr__printed a plain Pythonset, 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.customize.rst: an emoji example showedrepr(hn)output but was written as if it werestr(hn);CONSTANTS.titles.clear()was documented as producing no output, butclear()returnsself(chainable) and so printsSetManager(set()).Changes
nameparser/config/__init__.py: resetCONSTANTSat the end of each docstring demo;SetManager.__repr__now sorts elements so its output is deterministic across processes.docs/usage.rst: resetCONSTANTS.capitalize_name/force_mixed_case_capitalizationafter their respective demo blocks.docs/customize.rst: switched the "Hon" removal / clear-titles demo to a localConstants()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 callstr(hn); updated theSetManagerellipsis examples to match the now-sorted repr..github/workflows/python-package.yml: addedsphinx-build -b doctest docs dist/doctestandpython -m doctest README.rstso 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 acrossusage.rst,customize.rst, andparser.py's own docstrings)python -m doctest README.rst— 10/10 passedSetManager.__repr__produces identical output across separate process invocations (previously varied per run)🤖 Generated with Claude Code