Migrating from HumanName¶
HumanName and CONSTANTS keep working in 2.0 — same imports,
same attributes, same mutation API (name.C.titles.add(...),
name.first = "...", and so on). Upgrading to 2.0 and migrating your
code to the new Parser/Lexicon/
Policy API are two separate decisions — you can do
the former today and the latter whenever it’s convenient. The
compatibility layer (HumanName and nameparser.config) is
removed in 3.0; that release is not scheduled.
The full 1.x documentation remains the canonical reference for
HumanName and stays online at the readthedocs stable build,
currently the 1.4.0 release: https://nameparser.readthedocs.io/en/stable/
This page exists for the other direction: translating a v1 customization or a v1-shaped comparison into the 2.0 API, one row per old name.
Before you upgrade¶
What 2.0 removes is the batch of deprecations 1.3 and 1.4 announced. If
your test suite runs clean on 1.4 under python -W
error::DeprecationWarning, it will run on 2.0 — with four exceptions
that 1.4 never warned about. The first three raise the first time you
hit them; the fourth only warns, so read it carefully:
CONSTANTS.regexes.<name> = ...raisesTypeError. This includesCONSTANTS.regexes.bidi = False, the opt-out 1.3.1 recommended for keeping bidirectional marks; the 2.0 spellings arePolicy(strip_bidi=False)andPolicy(strip_emoji=False)assigning a
*_listattribute (name.first_list = [...]) raisesAttributeError— the lists are read-only snapshots in 2.0positional
Constants(...)construction raisesTypeError; the constructor is keyword-onlya subclass overriding a v1 parsing hook (
pre_process,parse_pieces,is_title, and the rest) gets aDeprecationWarningat construction naming the hooks it overrode, because 2.0 delegates parsing to the core parser and never calls them
One removal changes results without saying anything. HumanName no
longer defines __eq__, so name == "John Smith" is now False
where 1.x returned True. That one did warn on 1.4, but nothing
will tell you on 2.0. If you compare names anywhere, grep for ==
before upgrading and move to matches() — see Comparison.
One step has to happen before you upgrade, because the fix is only
available on the version you’re leaving: a Constants pickle written
by nameparser 1.2.x or earlier must be re-pickled under 1.3 or 1.4.
2.0 refuses to load one, and by then the code that could rewrite it is
gone.
If your suite did not run clean, these are the replacements for the warned removals:
1.4 spelling |
2.0 replacement |
|---|---|
|
Decode first: |
|
|
|
|
|
|
|
|
|
|
|
|
|
Gone; empty fields are always |
Finally, if you want to see the difference on your own data rather than
ours, tools/differential/ in the source repository diffs 1.4 and
2.0 parses over a corpus of names you supply. It is development
tooling, not part of the installed package — see its README.
Attribute map¶
HumanName’s seven fields and their aggregates map onto
ParsedName like this:
|
|
Note |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
New field (added 1.3) |
|
|
Returns the raw |
|
|
Unchanged name; |
|
|
Unchanged name; |
|
|
The surname with leading particles split off |
|
|
The particles |
|
|
A per-call argument now, not stored config — see Customizing the parser |
|
|
Same three knobs, now call-site arguments to
|
|
|
Moves from a |
|
|
|
Side by side:
>>> from nameparser import HumanName, parse, Role
>>> hn = HumanName("Dr. Juan Q. Xavier de la Vega III")
>>> n = parse("Dr. Juan Q. Xavier de la Vega III")
>>> hn.title == n.title, hn.first == n.given, hn.last == n.family
(True, True, True)
>>> hn.first_list == [t.text for t in n.tokens_for(Role.GIVEN)]
True
>>> hn.given_names == n.given_names, hn.surnames == n.surnames
(True, True)
>>> hn.last_base == n.family_base, hn.last_prefixes == n.family_particles
(True, True)
Config map¶
CONSTANTS’ vocabulary sets map onto Lexicon
fields:
|
|
Note |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Flipped — see the warning below |
|
|
|
|
|
|
|
|
Pair-valued; set it via |
And behavior/render scalars map onto Policy (or a
rendering argument, where the 2.0 equivalent isn’t config at all):
|
2.0 equivalent |
Note |
|---|---|---|
|
|
v1’s single flag enabled both detectors at once; pick one rule (or a locale pack, see Locale packs) if you only want one tradition |
|
|
|
|
|
Was a dict of named sentinels; now a plain |
|
|
Same shape change as |
|
|
|
|
|
|
|
|
The stored default is gone; pass |
|
(no equivalent) |
2.0 never capitalizes automatically during |
Every other regexes.* entry (word, spaces, and the rest of
the compiled-pattern proxy) has no 2.0 replacement — parsing behavior
is configured entirely through named Policy fields now, not by
handing the parser a regex.
Warning
non_first_name_prefixes and particles_ambiguous mark
complementary sets, not the same set under a new name.
non_first_name_prefixes lists particles that are never read as
a given name; particles_ambiguous lists the particles that
may be read as one. Translating a customization means flipping
the set: particles_ambiguous = lexicon.particles -
constants.non_first_name_prefixes. Copying
non_first_name_prefixes straight into particles_ambiguous
silently inverts which particles are allowed to double as a given
name.
Comparison¶
HumanName.__eq__/__hash__ were deprecated in 1.3.0 and are gone
in 2.0’s core API; use matches() for “is this the same name?” and
comparison_key() for dedup, dict keys, and sorting — both exist on
HumanName and on ParsedName with the same
behavior:
>>> from nameparser import HumanName, parse
>>> hn = HumanName("de la Vega, Juan")
>>> n = parse("de la Vega, Juan")
>>> hn.matches("Juan de la Vega"), n.matches("Juan de la Vega")
(True, True)
>>> hn.comparison_key() == n.comparison_key()
True
One behavior changed underneath both methods: components now fold with
str.casefold() instead of str.lower(), so more Unicode
case-pairs compare equal than did under 1.4. The change is strictly
more permissive — anything 1.4 matched still matches:
>>> parse("Anna STRASSE").matches("Anna Straße")
True
Behavior changes¶
Beyond the API surface mapped above, a handful of parse outputs
differ between 1.4 and 2.0 for specific input shapes. The full list,
with reasoning, is in the 2.0.0 section of Release Log. These
are the shapes worth grepping your own fixtures for, because a
recognized suffix or title now stays in its own field instead of
landing in first/last:
>>> HumanName("Andrews, M.D.").last, HumanName("Andrews, M.D.").suffix
('Andrews', 'M.D.')
>>> HumanName("Johnson PhD").first, HumanName("Johnson PhD").suffix
('Johnson', 'PhD')
Under 1.4 those read first="M.D."/last="Andrews" and
first="Johnson"/last="PhD" respectively. Two more to check for:
a maiden marker now fills the maiden field rather than being folded
into middle/last ("Jane Smith née Jones"), and with a
custom suffix delimiter configured, a no-space delimiter group renders
whole ("RN/CRNA") where 1.x split it ("RN, CRNA") — the role
assignment is identical, only the rendered string differs.