Skip to content

Commit fc8fda1

Browse files
derek73claude
andauthored
Simplify the 4i choice compile and reading-files code (#754) (#1001)
One strict-choice predicate: _reading_index.strict_kept is the filter strict_pool, _lexicon._chosen_pool and _ReadingFiles.languages each spelled out, and chosen_readings the filter-then-choose that compile_choice and the per-word path share. Lexicon._pool reads through _ReadingFiles.pool(), which holds the same base, log and choice. _compiled_for's nested arms are flattened; _reading_files is sized as _built; _rechosen_masks loads the default's masks only where it reads them; _unwritten reads the unwritten values from ReadingProperties instead of restating them; a __setstate__ comment said no field was marked ADDED_IN. No behaviour or message change. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 4a50013 commit fc8fda1

2 files changed

Lines changed: 49 additions & 34 deletions

File tree

‎nameparser/_lexicon.py‎

Lines changed: 28 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -675,11 +675,12 @@ def _unwritten(kind: str, prop: str) -> object:
675675
"""The value `prop` takes on a `kind` reading that does not write
676676
it, read through _reading_index.ReadingProperties: `acronym` is
677677
true on a credential, `addresses` the family name."""
678+
bare = _index_module().IndexReading("", "", kind, MappingProxyType({}))
678679
if prop == "acronym":
679-
return kind == "credential"
680+
return bare.acronym
680681
if prop == "addresses":
681-
return "family"
682-
return False
682+
return bare.addresses
683+
return bare.flag(prop)
683684

684685

685686
def _prop_value(kind: str, prop: str, value: object) -> object:
@@ -935,8 +936,7 @@ def _chosen_pool(base: object, chosen: frozenset[str], strict: bool) -> Pool:
935936
ri = _index_module()
936937
readings = [r for rs in pool.values() for r in rs]
937938
if strict:
938-
readings = [r for r in readings
939-
if r.tag in chosen or ri.is_native_script(r.text)]
939+
readings = ri.strict_kept(readings, chosen)
940940
out: dict[str, list[Any]] = {}
941941
for r in ri.choose(readings, chosen):
942942
out.setdefault(r.text, []).append(r)
@@ -991,16 +991,13 @@ def _clashes_unchosen(base: object, edits: tuple[_Edit, ...]) -> bool:
991991
def _compiled_for(base: object, edits: tuple[_Edit, ...],
992992
chosen: frozenset[str] = frozenset(),
993993
strict: bool = False) -> Mapping[str, frozenset[str]]:
994-
if not edits:
995-
if not chosen:
996-
if base == "default":
997-
return _default_compiled()
998-
if base == "empty":
999-
return _NO_SETS
1000-
elif base == "default":
1001-
# the shipped index under the choice, compiled once per
1002-
# choice by the reader every pack shares
1003-
return _choice_compiled(chosen, strict)
994+
if not edits and base == "default":
995+
# under a choice, the shipped index compiled once per choice by
996+
# the reader every pack shares
997+
return (_choice_compiled(chosen, strict) if chosen
998+
else _default_compiled())
999+
if not edits and not chosen and base == "empty":
1000+
return _NO_SETS
10041001
return _built(base, edits, chosen, strict)[1]
10051002

10061003

@@ -1032,31 +1029,34 @@ def __init__(self, base: object, edits: tuple[_Edit, ...],
10321029
self._base, self._edits = base, edits
10331030
self._chosen, self._strict = chosen, strict
10341031

1032+
def pool(self) -> Pool:
1033+
"""The lexicon's readings by word (`Lexicon._pool`)."""
1034+
if not self._edits:
1035+
return _chosen_pool(self._base, self._chosen, self._strict)
1036+
return _built(self._base, self._edits, self._chosen,
1037+
self._strict)[0]
1038+
10351039
def languages(self, text: str, kinds: frozenset[str]) -> tuple[str, ...]:
10361040
"""The tags of the files holding a reading of `text` (as the
10371041
vocabulary stores it) of one of `kinds`, on in this lexicon,
10381042
sorted; a caller's own reading names none."""
10391043
ri = _index_module()
10401044
readings: Iterable[Any]
10411045
if self._edits or self._base not in ("default", "empty"):
1042-
readings = _built(self._base, self._edits, self._chosen,
1043-
self._strict)[0].get(text, ())
1046+
readings = self.pool().get(text, ())
10441047
elif self._base == "empty":
10451048
return ()
10461049
elif not self._chosen:
10471050
return cast("tuple[str, ...]", ri.languages_of(text, kinds))
10481051
else:
1049-
readings = ri.readings_of(text)
1050-
if self._strict:
1051-
readings = [r for r in readings if r.tag in self._chosen
1052-
or ri.is_native_script(r.text)]
1053-
readings = ri.choose(readings, self._chosen)
1052+
readings = ri.chosen_readings(ri.readings_of(text), self._chosen,
1053+
self._strict)
10541054
return tuple(sorted({r.tag for r in readings
10551055
if r.tag and r.kind in kinds
10561056
and r.on_by_default}))
10571057

10581058

1059-
@functools.lru_cache(maxsize=64)
1059+
@functools.lru_cache(maxsize=128)
10601060
def _reading_files(base: object, edits: tuple[_Edit, ...],
10611061
chosen: frozenset[str], strict: bool) -> _ReadingFiles:
10621062
# one per configuration, so equal lexicons share assemble's memo
@@ -1192,10 +1192,10 @@ def _rechosen_masks(lexicon: Lexicon, chosen: frozenset[str],
11921192
"""`lexicon`'s masks moved from its own choice's to `chosen`'s: the
11931193
base's choice's moves undone, then the new choice's applied, so a
11941194
chained choice moves them as the union does."""
1195-
default = _index_module().compile_choice(
1196-
frozenset())["CAPITALIZATION_EXCEPTIONS"]
11971195
cap = dict(lexicon.capitalization_exceptions)
11981196
if lexicon.languages:
1197+
default = _index_module().compile_choice(
1198+
frozenset())["CAPITALIZATION_EXCEPTIONS"]
11991199
gone, joined = _choice_masks(lexicon._chosen, lexicon.strict)
12001200
for k in gone:
12011201
cap.setdefault(k, default[k])
@@ -1958,8 +1958,8 @@ def __setstate__(self, state: dict[str, object]) -> None:
19581958
# and a log; a 3.0 one is checked for its layout as
19591959
# _types._guarded_setstate checks the other frozen types', the
19601960
# one skew admitted a field marked `_ADDED_IN` with a default
1961-
# (none yet), and then built through the constructor, which
1962-
# validates every value as for a caller's.
1961+
# (`_languages`, `_strict`), and then built through the
1962+
# constructor, which validates every value as for a caller's.
19631963
if "titles" in state:
19641964
state = _translated_2x(state)
19651965
fields = [f for f in dataclasses.fields(Lexicon) if f.init]
@@ -2165,10 +2165,7 @@ def remove(self, *words: str, kind: str | None = None,
21652165
# -- private helpers --------------------------------------------------
21662166

21672167
def _pool(self) -> Pool:
2168-
if not self._edits:
2169-
return _chosen_pool(self._base, self._chosen, self._strict)
2170-
return _built(self._base, self._edits, self._chosen,
2171-
self._strict)[0]
2168+
return self._files.pool()
21722169

21732170
def _changed(self, op: str,
21742171
entries: Mapping[str, object]) -> dict[str, object]:

‎nameparser/_reading_index.py‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,26 @@ def strict_pool(chosen: frozenset[str]) -> list[IndexReading]:
370370
from, before :func:`choose`: the chosen files' and native-script
371371
vocabulary's, and nothing else, mul.toml's and und.toml's included
372372
(file-strict; decisions/vocabulary-model, 2026-10-30)."""
373-
return [r for r in index() if r.tag in chosen or is_native_script(r.text)]
373+
return strict_kept(index(), chosen)
374+
375+
376+
def strict_kept(readings: Iterable[IndexReading],
377+
chosen: frozenset[str]) -> list[IndexReading]:
378+
"""The readings of `readings` a strict choice of the file tags
379+
`chosen` keeps: the chosen files' and native-script ones."""
380+
return [r for r in readings
381+
if r.tag in chosen or is_native_script(r.text)]
382+
383+
384+
def chosen_readings(readings: Iterable[IndexReading], chosen: frozenset[str],
385+
strict: bool) -> list[IndexReading]:
386+
"""`readings` under the choice of the file tags `chosen`: under
387+
`strict` only the chosen files' and native-script ones (as
388+
:func:`strict_pool` keeps them), then :func:`choose`. What
389+
:func:`compile_choice` compiles, and what a `Lexicon` under a
390+
choice reads a word's readings by."""
391+
return choose(strict_kept(readings, chosen) if strict else readings,
392+
chosen)
374393

375394

376395
@functools.cache
@@ -380,8 +399,7 @@ def compile_choice(chosen: frozenset[str], strict: bool = False) -> Compiled:
380399
a compile costs milliseconds, paid once per choice and only by a
381400
caller who makes one. An empty plain choice compiles the default; a
382401
`strict` one compiles from :func:`strict_pool` alone."""
383-
pool = strict_pool(chosen) if strict else index()
384-
return compile_readings(choose(pool, chosen))
402+
return compile_readings(chosen_readings(index(), chosen, strict))
385403

386404

387405
def strict_ungated(chosen: frozenset[str]) -> frozenset[str]:

0 commit comments

Comments
 (0)