Repository navigation
Cache the local corpora's word index and read their records lazily - #836
Merged
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #836 +/- ##
=======================================
Coverage 99.05% 99.05%
=======================================
Files 47 47
Lines 4659 4659
=======================================
Hits 4615 4615
Misses 44 44 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
tools/name_usage.py rebuilt each local corpus's word index on every run: 5.8s of the FEC corpus's 7s, and 1.6s of ClinicalTrials.gov's. The index is now cached as wordindex.json beside each corpus, keyed on the records' sha256 and on fold_fingerprint(): a hash of the code objects that turn the records into an index (_FOLD_CODE and corpus_build.jsonl_lines), the constants they read, WordIndex's fields, the Unicode database and the interpreter. It hashes the running code rather than the source on disk, so an edit made while a run is under way cannot store an old fold under a new key, and a test holds _FOLD_CODE to everything those functions call and read. JSON rather than pickle, so the cache cannot run code; WordIndex holds plain dicts, built or cached alike, read with .get. A cached file is used only when its key matches and every count is an int; anything else is rebuilt, with a line on stderr. Local.records is read from raw.jsonl on first use, so a single-word lookup answered from the cache parses no records. Damage found then raises CorpusDamaged, a ValueError of its own: name_usage catches it (and OSError) per corpus, so a damaged corpus fails its own row while a bug in a lookup still raises, and tally exits naming the fetch. Both test modules now point the cache at a scratch folder, so no test can write an index into the developer's real cache. Measured 2026-10-22, a single-word name_usage --no-wikidata run: 2.5s with both corpora cached, 12.5s before, 14.8s on the run that builds the caches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
derek73
force-pushed
the
feat/local-corpus-index-cache
branch
from
October 23, 2026 00:08
8de820d to
11aecff
Compare
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.
What
tools/name_usage.pyrebuilt each local corpus's word index on every run: 5.8 s of the FEC corpus's 7 s (after #834), and 1.6 s of ClinicalTrials.gov's. This PR does two things:wordindex.jsonbeside each corpus in~/.cache/nameparser-tools.Local.recordslazily, fromraw.jsonlon first use, so a single-word lookup answered from the cache parses no records.Measured 2026-10-22, a single-word
name_usage.py --no-wikidatarun, with output byte-identical to the pre-cache run:Ph. D.), which still scans every nameHow the cache stays honest
A stale index gives wrong counts that look right, so the key is computed, not versioned by hand. It combines:
meta.json, so a refetch rebuilds.fold_fingerprint(), a hash over:_FOLD_CODE(word_key,_strippable,_keyed,_names,word_index) and ofcorpus_build.jsonl_lines. It hashes the code that is running, not the source on disk, so an edit made during a long run cannot store an old fold under a new key. Line numbers are left out, so moving code doesn't trigger a rebuild._TOKEN_SPLIT,_JOINERS, with sets sorted so the key is the same in every process);WordIndex's field names;unicodedata.unidata_versionand the interpreter version.test_the_fold_lists_everything_its_functions_call_and_readwalks the global names the fold's functions use and fails on any that isn't listed.Other choices:
WordIndexholds plain dicts, built or cached alike, read with.get(key, 0). RebuildingCounters on load had cost 0.37 s of 0.61 s.Errors
CorpusDamaged, a subclass ofValueError, so existing callers still catch it.name_usageguards each corpus's lookup but catches onlyCorpusDamagedandOSError. A damaged corpus fails its own row, while a bug in a lookup still raises.tallyexits naming the fetch, asrequire()does.Review notes
tally's damage path.load_localsturned out to be redundant once each lookup was guarded (its control passed), so it was removed.🤖 Generated with Claude Code