Repository navigation
Remove the v1 compatibility layer for 3.0 - #937
Merged
Merged
Conversation
3.0 removes HumanName (#357), so every test that guards a parsing or rendering reading through it now asserts the same reading through the core: parse() with first/last read as given/family, capitalized(), initials(spec, delimiter=, separator=) and render(), and a Lexicon or Policy where a test configured Constants. No expected value changed. Tests that guard only the facade itself (setters, *_list views, Constants and its managers, pickling, string_format and the other stored render defaults) are deleted with it in the next commits. The v2 modules lose their facade halves the same way, keeping each core assertion. tests/base.py's helpers follow: ParsedNameTestBase (was HumanNameTestBase) and FlaggedPolicyTestBase with policy_kwargs (was FlaggedConstantsTestBase with constants_kwargs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
3.0 removes HumanName (#357), so snapshot.py stops recording a row's `facade` key and re-records snapshot.jsonl, which loses the three it held (the `Ph. D.` initials). load() sets a `facade` key aside, so a check against a snapshot recorded before 3.0 -- `--since v2.8.0`, an old local snapshot -- compares the rest rather than failing. compare.py's worker reads a 2.x baseline on the 2.0 surface alone and a 1.x baseline through that release's HumanName, which it still has; the tree is read on parse() either way. Against 1.4.0 that moves the count from 1,751 to 1,749, measured 2026-10-28 on master and on this branch: the two `Ph. D.` names whose initials the facade wrote `J. P D.`, where 1.4.0 and parse() both write `J. P. D.`. tools/perf/call_count.py measures parse() alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deletes what 2.8.0 warned about (#925, #935): HumanName (nameparser/_facade.py) and nameparser.parser; nameparser.config's Constants, CONSTANTS, SetManager, TupleManager and RegexTupleManager (nameparser/_config_shim.py); nameparser.util; the five 1.x vocabulary names 2.2 retired (config/_deprecated.py's bridge, the prefixes.py and bound_first_names.py modules, FIRST_NAME_TITLES and SUFFIX_NOT_ACRONYMS); config/_titles_2_6_0.py, kept only for the facade's translation; the pickle-migration shims; and the deprecation warnings with their filterwarnings entries and tests/removals.py. The vocabulary data modules stay in nameparser.config, whose __init__ is now a docstring, and the core API is unchanged. Tests: the five facade-only v2 modules go (test_facade, test_facade_cases, test_config_shim, test_deprecations, test_config_aliases) after their core-guarding tests moved into test_parser, test_render and test_contracts in the port commit; the shared-CONSTANTS isolation fixture goes with CONSTANTS; the facade's call budget and timing rows leave test_benchmark; test_layering drops the facade's ALLOWED entries and now holds that the removed names and modules stay gone; the star-import test asserts a data module binds exactly its live constants. rules/R2 and rules/R3 stop naming _facade.py as an implementer. Closes #357 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
migrate.rst becomes "Migrating to 3.0", for 1.x code and for 2.x code that kept using HumanName: what 3.0 removes and the replacement for each, how to find the sites (2.8 under -W error::DeprecationWarning, and a search for CONSTANTS, whose reads 2.8 did not warn on), and the attribute and config maps as 1.x/2.x -> 3.0. Every doctest that used HumanName asserts the same reading through parse(). The renamed-word- lists bridge table goes, as #357 asks; the 2.2.0 release-log entry stays the record of that mapping. usage.rst, customize.rst, modules.rst (the data modules' autodoc stays, under "Default vocabulary"), concepts.rst, conf.py's doctest setup, CONTRIBUTING.md and the README lose their HumanName material; the README leads with the 3.0 removal. One release-log bullet under 3.0.0. Root AGENTS.md drops the facade layer and shim-translation bullets and the v1 gotchas (HumanName.C, TupleManager's dunder guard, the delimiter sentinels, Constants attribute docstrings, the two-tier config, the debug-logging snippet for a logger the core never had), and describes the ported test suite. docs/design: mechanisms.md retires FACADE-CONTRACT and CONFIG-SHIM-SNAPSHOT and drops the facade from the entries that named it as a live site; rules/R3, P8 and R4 stop describing the facade's initials view; decisions/3-0-reevaluations records the removal and rewrites its Standing bullets, and M1, N1, P7, P8, R3, R4, R5, S9, comparison-surface, differential-ledger and parse-cost each gain a 2026-10-28 #357 entry for the Standing bullets the removal moves. tests/v2/rules_budget.json is re-recorded for the three rules that got shorter (P8, R3, R4). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Docs: migrate.rst names the three imports 2.8 left quiet (nameparser.util and the two 1.x word-list modules) beside the CONSTANTS read, and gains initials() and initials_list() rows; the release-log bullet names the two module paths and says 2.8.0 warned at construction; the README stops claiming the map covers every attribute. Three unresolved :meth: targets for Lexicon.default become literals. docs/design: the facade's overtaken entries are marked SUPERSEDED (or superseded in part) by the 2026-10-28 #357 entries under edit kind 1, rather than listed under Not standing, and each #357 entry names what it supersedes; 3-0-reevaluations' removal entry names both parts of the earlier #357 entry it reverses and notes the acceptance-grep rewording; the two `Ph. D.` names are named, one a CLDR rendering. AGENTS.md loses three stale phrases (the alias bridge, HumanName output, _CORE_ONLY_IDS). Tests: pin the folded family's particle views under middle_as_family and the initials separator inside a multi-word group, the two core readings whose only tests had gone through the facade; say why the compare.py worker's v1 arm runs only against a wheel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
migrate.rst's "Finding the sites" said three imports had nothing after them to warn; any use of their names did warn on 2.8.0. It now says what 2.8 left quiet -- a CONSTANTS read and an import whose name is never used or is used without construction (a subclass, isinstance, an annotation), Constants included -- and lists the names to search for. 3-0-reevaluations' note on its reworded parenthesis said "corrected", which edit kind 2 reserves for factual errors; it now says the wording was accurate and names the edit as outside the four kinds. The folded-family particle test's comment says the reading is general, not the fold's, and that rules/R2's wording does not describe it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comments that still described the 1.x layer as present: the mask error's shim re-raise in _lexicon, the config modules' pointer to the deleted prefixes.py note and their 1.x-parser and v1-spelling sentences, surnames.py's per-construction copies, pyproject's strict_equality reason, nameparser/AGENTS.md's config shim, the period-abbreviation gotcha's C.titles, and the case table's notes on a facade runner that no longer runs. Tests: replace() splits on whitespace runs (a blank value clears the field, a doubled space makes no empty token), reached until now only through the facade's setters; the star-import check covers all five config modules with an __all__; the case-only control is re-taken on the core alone (64 repairs). build_corpus.py read only HumanName(...) calls, so over the ported tests it returned 183 names without a warning; it now reads parse() and the helpers that wrap it. call_count.py says its --modules tables profiled HumanName before 3.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
build_corpus.py reads HumanName(...) alone at a --ref again, so the pinned recipe reproduces corpus.jsonl byte for byte: at 2d5d8c2 hn() already wrapped HumanName, and reading it there added 55 names. The working tree is read by parse() and its helpers, 566 names. The config modules' __all__ notes said a star import would bind `_compiled`; a star import skips underscore names, so they now say what __all__ guards (a public import). Three case notes still counted "one per runner" in the present tense and are dated to 2.x. The replace() test splits a tab and a newline too, so a filtered split(" ") fails it, and pyproject's list names _version. AGENTS.md records the build_corpus miss beside the test-deletion gotcha: a tool reading test source by its syntax breaks when a port rewrites the calls. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
decisions/3-0-reevaluations' 2026-10-28 #357 entry quotes its alias example as written again: a dated decisions entry records what was true when it was written and may name removed things, so #357's acceptance grep exempts docs/design/decisions/, and the note about the rewording goes. The grep still covers every live doc, rules/ and mechanisms.md included. migrate.rst described family_base as the surname with its LEADING particles split off; the core drops every particle, which is the reading kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The last_base and last_prefixes rows mapped them to family_base and family_particles as equivalents, but they part when a particle sits inside the surname: da Silva do Amaral gives base 'Silva Amaral' and particles 'da do', where HumanName split off only the leading 'da'. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AGENTS.md's Pickling bullet described the ADDED_IN widening and then said Lexicon keeps its own copy of the guard, which read as if Lexicon honored the marker. It does not: Lexicon.__setstate__ requires every field, so a new Lexicon field breaks older Lexicon, Parser and locale-pack pickles. Whether the guard should learn the marker stays an open 3.0 question. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Lexicon's __setstate__ re-runs __post_init__ and refuses a state holding an entry that is not already normalized; only the shared _guarded_setstate leaves values unchecked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
This PR deletes the 1.x compatibility layer that 2.8.0 deprecated (#925, #935). It could be the first 3.0 alpha. Each kind of change is its own commit: the test port, the tools, the code, then the docs, each with its suite passing on its own. Four more commits fold in two review rounds, each followed by a review of its own fixes, and the last two settle the questions answered in review (below).
What goes
HumanName(nameparser/_facade.py),nameparser.parser, andHumanNameinnameparser.__all__.nameparser.config'sConstants,CONSTANTS,SetManager,TupleManagerandRegexTupleManager(nameparser/_config_shim.py).config/__init__.pyis now a docstring only.nameparser.util.config/_deprecated.py, theprefixes.pyandbound_first_names.pymodules,FIRST_NAME_TITLESandSUFFIX_NOT_ACRONYMS.config/_titles_2_6_0.py, which only the facade read (Keep the titles 2.6.0 listed in v1's Constants().titles (#752) #904).filterwarningsentries, andtests/removals.py.What stays
nameparser.config, with__all__now listing only their live constants.tests/v2/test_layering.pynow checks that the removed names and modules stay gone. TheALLOWEDtable drops the facade's entries._lexiconstill imports only the config data modules.Tests: sorted by the code they exercise
Collected tests drop from 32,931 on master to 30,696.
parse()/ coretests/test_*.pytest_facade,test_facade_cases,test_config_shim,test_deprecations,test_config_aliasestest_parser,test_renderandtest_contractstest_render,test_properties,test_locales,test_types,test_lexicon,test_benchmark, the tools tests)test_layeringalso gains 16 rows that hold the removed names and modules gone.The 1.x suite. A ported test keeps its assertion, with
first/lastread asgiven/family. Where a test configuredConstants, it now builds aLexiconorPolicy. No expected value changed, and both xfails (#490) still fail underparse().Deleted as facade-only: setters,
*_listviews, string equality,len/iteration,string_formatand the other stored render defaults,Constantsand its managers, pickling, and the deprecation warnings.tests/base.pyrenames its helpers:ParsedNameTestBase, andFlaggedPolicyTestBasewithpolicy_kwargs.TEST_NAMESnow compares all seven fields across the comma variants onparse(), and picks the same five suffix names it did through the facade.test_facade_cases.pyran thecases.pyrows through the facade.test_cases.pyruns every row through the core, so nothing is lost.Recorded counts in
test_properties.pythat included the facade's arm (INV7's 7,860 and 8,054, and a few smaller controls) are dated, so they cannot be re-taken without the old tree. They are labelled as counted with the facade's half. The live controls still fail with the facade gone. Without it they read case-only substitution 64 (127 before), NFD initials 204 (408) and NFD repair 1,089 (2,629).The facade's initials fallback for a spliced field gave
j. s.where the core'sreplace()theninitials()givesj. e. s.. It was facade-only, so it went with the facade. rules/R3 and decisions/R3 described it, and are amended.Tools
snapshot.pystops recording thefacadekey. The re-record drops it from the three rows that had it, thePh. D.initials.load()sets afacadekey aside, so--since v2.8.0and old local snapshots compare cleanly.--since v2.8.0reads "matches the snapshot".compare.pyreads a 2.x baseline on the 2.0 surface, and a 1.x baseline through that release's ownHumanName. The tree is read onparse()either way.--baseline 2.8.0reads 0 of 6,533 entries differently.--baseline 1.4.0reads 1,749 of 5,719 differently, against 1,751 on master (measured 2026-10-28). The two that dropped arePh. D., Johnand one CLDR rendering. For the merged element, 1.4.0 andparse()both writeP. D.where the facade wroteP D..tools/perf/call_count.pymeasuresparse()alone. It reads 305 on 3.11, inside the band around 307. Its docstring now says the--modulestables recorded before 3.0 profiledHumanName.build_corpus.pyread onlyHumanName(...)calls, so over the ported tests it returned 183 names with no warning. The working tree is now read byparse()and the helpers wrapping it (566 names). A--refis still read byHumanNamealone, so the pinned recipe reproducescorpus.jsonlbyte for byte.Docs
migrate.rstis now "Migrating to 3.0". It covers what 3.0 removes and the replacement for each, how to find the sites, and the attribute and config maps as 1.x/2.x → 3.0.-W error::DeprecationWarning, plus a search for what 2.8 left quiet: reads ofCONSTANTS, and imports whose names are never used or are used without construction (a subclass,isinstance, an annotation).HumanNamenow asserts the same reading throughparse().HumanNamesections are removed fromusage.rst,customize.rst,modules.rst(the data modules' autodoc stays, under "Default vocabulary"),concepts.rstandCONTRIBUTING.md.AGENTS.md: the facade bullets and the v1 Gotchas are gone (the facade layer, the shim TRANSLATES,HumanName.C,TupleManager, the delimiter sentinels,Constantsattribute docstrings, the two-tier config, the debug-logging snippet for a logger the core never had). The test conventions now describe the ported suite. The Pickling bullet now says thatLexicon's copy of the guard admits no field added later (noADDED_IN), so adding aLexiconfield breaks olderLexicon,Parserand locale-pack pickles; whether it should learn the marker is left open. The same bullet's "values are NOT re-validated" now names the shared guard only:Lexicon's__setstate__re-runs__post_init__and refuses entries that are not already normalized.rules_budget.jsonis re-recorded for the three rules that got shorter.Checks
Run locally on the final tree:
-n0 -m serial: 41 passed. Two fewer than before, the facade's budget and timing rowsuv run --python 3.15 pytest: 30,624 passedsphinx-build -b doctestand-b html: cleanpython -m doctest README.rstandreadme_renderer: cleantools/vocab/build.py --check: current#357's acceptance:
grep -rn "PREFIXES\|NON_FIRST_NAME_PREFIXES\|BOUND_FIRST_NAMES\|FIRST_NAME_TITLES\|SUFFIX_NOT_ACRONYMS" nameparser/ docs/ AGENTS.md --exclude-dir=decisionshits onlydocs/release_log.rst. To get there, migrate.rst's bridge table went; the 2.2.0 release-log entry still maps the names.docs/design/decisions/, and only that folder: a dated decisions entry records what was true when it was written and may name removed things, while the grep exists to keep live docs from teaching them.rules/andmechanisms.mdstay covered.FIRST_NAME_TITLESappended todocs/usage.rstwas reported, then removed.from nameparser.config.prefixes import PREFIXESraisesModuleNotFoundError, andfrom nameparser.config.titles import FIRST_NAME_TITLESraisesImportError.tests/v2/test_layering.py::test_the_1x_imports_failruns both, plusSUFFIX_NOT_ACRONYMSandHumanName.DeprecationWarningremains innameparser/config/.Review
The first round had three reviewers: code and tests, design docs, and user docs and claims. Its fixes are commit 5, and a review of that commit gave commit 6.
The second round had four: code and project rules, test coverage, stale comments across the whole tree, and the comparison tools. Its fixes are commit 7, and a review of that commit gave commit 8. It found no defect in live code. It found:
cases.py;replace()splitting on whitespace runs, now intest_types.py;__all__;build_corpus.pymiss above, now also recorded in AGENTS.md;The comparison-tools reviewer showed each path reports a real difference (
--since v2.7.027,--baseline 2.7.021, the 1.4.0 arm against the real wheel 1,749), and that a missing key raises rather than comparesNone == None.The user-docs reviewer checked claims by running them:
HumanNameandConstantspickles fail to load withModuleNotFoundError, and a 2.8.0ParsedNamepickle loads.Answered in review
family_baseis the family without its particles, every one of them (da Silva do Amaral, Miguelgives baseSilva Amaral).test_particle_views_after_foldpins it, anddocs/migrate.rst'sfamily_baserow now says so (it said "leading particles split off", already wrong on master). Thefamily_baseandfamily_particlesrows also record where they part fromHumanName'slast_baseandlast_prefixes, which split off only the leading particles ('Silva do Amaral','da', measured on the 2.8.0 wheel). rules/R2 still says "leading" and is amended to match the code in the separate 3.0 design PR. The test's comment quotes R2's current wording, so whichever of the two PRs merges second updates that quote, and the citation test fails on it until then.docs/design/decisions/(see Checks).Closes #357
🤖 Generated with Claude Code