Skip to content

Render views should honor the parser's conjunction/initial tags instead of re-deciding from the word #458

Description

@derek73

The parse decides; the render views honor those decisions and never re-evaluate them. capitalized() breaks that rule — it re-runs the conjunction-versus-initial decision at render time from the word's spelling, rather than reading the tag the parser already set.

# nameparser/_render.py, _cap_word
if (... or (normalized in lex.conjunctions and not _INITIAL.fullmatch(word))):
    return word.lower()

classify has already answered this. Token.tags carries conjunction and initial, both stable API, and initials() already honors them through _SKIP_TAGS. Only case repair asks again.

Two copies that ask different questions

predicate scope
_classify.py:80 is_initial(token.text) shape and repertoire (_in_initialless_script, #320)
_render.py _INITIAL.fullmatch(word) shape only

_render.py says so in its own comment: "the two copies keep identical PATTERNS and divergent PREDICATES; test_regex_sync pins the patterns, which is the promise being kept." 씨. answers yes to the bare pattern and no to is_initial.

The same comment argues the divergence is harmless — no shipped CJK conjunction exists, and CJK is caseless, so both branches return the same string — while noting that this is "a property of the shipped DATA, not an invariant — conjunctions is public, configurable API."

Reading the tag makes the question disappear rather than arguing it is harmless.

Measured: this is a pure refactor

Replacing the re-derivation with a "conjunction" in tags test moves 0 of 1094 differential-corpus names, under both capitalize() and capitalize(force=True).

The plumbing is already in place: #407 threads Token.tags into _cap_word so the particle branch can consult UNJOINED_TAG, and the conjunction branch is the next consumer of the same argument.

It also retires a hand-sync obligation the module currently carries in a comment: "keep in sync with nameparser/_pipeline/_vocab.py by hand." A tag read has nothing to keep in sync.

Scope

This changes where the decision is read, not how it is made. The parser's own conjunction-versus-initial classification is untouched, and no output moves.

Not proposed here

Changing _INITIAL's pattern — test_regex_sync pins it against nameparser/_pipeline/_vocab.py, and REGEXES["initial"] is public v1 API that cannot narrow — or removing e / y from the default conjunction vocabulary.

Found while measuring #407's capitalization behavior.

Metadata

Metadata

Assignees

项目

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions