Repository navigation
Add the reading index and share the vocabulary compiler (#753, 3a) - #941
Merged
Merged
Conversation
…ge (#753, 3a) tools/vocab/build.py now writes nameparser/config/_index.py, one row per reading with its file's tag, beside _compiled.py, and compiles the latter from the index through nameparser/_reading_index.py, the compiler a choice of languages will share. A test holds that the index compiled with no choice is the committed module. Name readings may be written default = false: they derive no marker in the default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The RFC's status, a decisions entry recording what 3a decided and measured, AGENTS.md's vocabulary and layering notes, the vocab README and mechanisms.md's COMPILED-DATA-COMMITTED entry. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Check 9 keeps reading every given reading: check 11's particle half refuses the off-only shape first, so the docs now credit it. The vocab README's name-reading and derived-marker sections mention default = false; mechanisms.md counts three files; the uncached timing is a range; a test holds that a repointed OUTPUT moves the index too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
compile_pool catches only the compiler's CompileError, so any other exception from compile_readings is an internal error, exit 3, as the build's docstring promises. A test compiles the build's readings as written and as the index keeps them, so a property indexed() drops fails it (each of nine mutations does). A test holds that _reading_index imports nothing internal at module level. The docs say the build writes both modules from the same rows rather than by way of the index, and the lazy load is marked as proposed, awaiting a decision. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No parse reads the index yet: Reading.languages is filled by a follow-up once 3a and 4a both merge. The RFC, the decisions entry and the module's docstrings now say so in the future tense, and the entry says what the lazy load buys before and after that follow-up. 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.
Sub-phase 3a of #753's work order: the reading index, the shared compiler, and
default = falseon name readings. Neutral:_compiled.pyis byte-identical andtests/v2/test_snapshot.pypasses unchanged.What lands
nameparser/config/_index.py(generated bytools/vocab/build.py).(tag, kind, properties).same_ason agivenreading. Counts, notes, exclusions and the statedmay_be_givenstay out.nameparser/_reading_index.py.compile_readings, plusCATEGORY,BEHAVIORALandGATED_WORDS, and the accessors for unwritten values, shared with the build'sReading._lexicon.py, so the build still never imports the package. The build keeps every check. It turns the readings into index rows in memory and writes both generated modules from those rows; it never reads_index.pyback.CompileError(the acronym-or-word backstop) becomes a vocabulary error (exit 2). Any other exception from it is internal (exit 3).tests/v2/test_reading_index.pyholds thatcompile_readings(index()), rendered as the build renders it, is_compiled.pybyte for byte. It also checks that the index is not stale against the TOML.indexed(),to_row,from_row). This is checked over the shipped pool and over a probe that carries every behavioral property plus a given reading'ssame_as. Dropping any one of the nine properties fromindexed()fails the test.Reading.languages(added unfilled by 4a, Add Token.reading, the reading the parse took for each word (3.0, 4a) #942, and filled by a follow-up once both merge):readings_of(text) -> tuple[IndexReading, ...].IndexReading(text, tag, kind, props)is frozen and slotted.kindis the vocabulary's kind (credential,preposition), which is finer thanReadingKind. The mapping between them is that follow-up's.default = falseongivenandfamilyreadings.givenreadings are off is refused, and that question is left open (below).Measured
All figures with bytecode cached, as a wheel install has it; Python 3.11.17, medians of fresh processes.
import nameparser(18–24 ms)readings_ofcallThe import is a little above the 0.45 ms the RFC measured on a flat draft. Writing the index grouped by word is what keeps the first lookup to a single
dict()call: grouping at run time cost about as much as the import itself.For review: decided here, not settled elsewhere
Each is recorded in decisions/vocabulary-model's 2026-10-29 entry.
readings_ofcall, not insideLexicon.default(). This replaces the 2026-10-28 wording. The RFC's runtime section and the decisions entry describe the lazy load.Reading.languages, the first parse will load it. Every parsing caller will then pay once, and only import-only callers are spared.givenreadings are off is refused.may_be_givendescribes is left to the first pack that needs it. None in 3.0 does:nl's prepositions wait with strict.Lexiconor any other pickled type, so the open question ofADDED_INonLexicon's guard does not arise.Docs
defaultrow, name readings, derived markers and whereCATEGORYlives.The design-docs review and a code review both ran; their findings are fixed in the last commit.
Tracing the moved compiler
Plain
git blamegives all ofnameparser/_reading_index.pyto this PR. With copy detection, most of it traces back to #737, #744, #890 and #894, where the code was written intools/vocab/build.py:Checks
All pass:
Refs #753.
🤖 Generated with Claude Code