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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions