nameparser 2.6.0__tar.gz → 2.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nameparser-2.6.0/nameparser.egg-info → nameparser-2.8.0}/PKG-INFO +22 -14
- {nameparser-2.6.0 → nameparser-2.8.0}/README.rst +21 -13
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/__init__.py +5 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_config_shim.py +244 -27
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_facade.py +48 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_lexicon.py +122 -10
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_assemble.py +36 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_assign.py +490 -86
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_classify.py +154 -34
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_comma.py +142 -52
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_extract.py +4 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_group.py +142 -37
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_pieces.py +405 -99
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_post_rules.py +117 -44
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_segment.py +4 -4
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_state.py +93 -5
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_vocab.py +636 -72
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_policy.py +12 -8
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_render.py +60 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_types.py +189 -30
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_version.py +4 -4
- nameparser-2.8.0/nameparser/config/__init__.py +76 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/_compiled.py +534 -31
- nameparser-2.8.0/nameparser/config/_titles_2_6_0.py +826 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/capitalization.py +2 -1
- nameparser-2.8.0/nameparser/config/given_names.py +18 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/particles.py +8 -7
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/suffixes.py +23 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/titles.py +43 -4
- nameparser-2.8.0/nameparser/util.py +46 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ar.toml +25 -12
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/bn.toml +1 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/cs.toml +1 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/de.toml +14 -9
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/en.toml +201 -104
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/es.toml +12 -10
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/fil.toml +9 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/fr.toml +12 -12
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ga.toml +2 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/gd.toml +1 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/he.toml +3 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/hi.toml +1 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/it.toml +11 -10
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ms.toml +3 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/mul.toml +1 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/nl.toml +23 -20
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/pa.toml +2 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/pl.toml +2 -1
- nameparser-2.8.0/nameparser/vocab/pt-BR.toml +49 -0
- nameparser-2.8.0/nameparser/vocab/pt.toml +101 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sr.toml +1 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sw.toml +1 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/tr.toml +3 -1
- nameparser-2.8.0/nameparser/vocab/und.toml +21 -0
- {nameparser-2.6.0 → nameparser-2.8.0/nameparser.egg-info}/PKG-INFO +22 -14
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser.egg-info/SOURCES.txt +9 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/pyproject.toml +9 -0
- nameparser-2.8.0/tests/removals.py +26 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_conjunctions.py +2 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_constants.py +9 -3
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_first_name.py +18 -5
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_python_api.py +11 -8
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_suffixes.py +49 -34
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_titles.py +4 -4
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/_differential_fixtures.py +35 -5
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/cases.py +2199 -457
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_assemble.py +2 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_assign.py +51 -17
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_classify.py +4 -4
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_comma.py +16 -12
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_group.py +36 -27
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_pieces.py +44 -10
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_post_rules.py +13 -6
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_script_segment.py +14 -11
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_state.py +7 -6
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_vocab.py +311 -19
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/rules_doc.py +5 -4
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_benchmark.py +62 -2
- nameparser-2.8.0/tests/v2/test_cases.py +820 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_config_shim.py +197 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_contracts.py +3 -1
- nameparser-2.8.0/tests/v2/test_deprecations.py +457 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_differential.py +18 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_facade.py +24 -7
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_facade_cases.py +7 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_lexicon.py +22 -8
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_local_agreement.py +255 -9
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_local_corpora.py +551 -19
- nameparser-2.8.0/tests/v2/test_local_orcid.py +561 -0
- nameparser-2.8.0/tests/v2/test_local_patentsview.py +366 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_locales.py +4 -3
- nameparser-2.8.0/tests/v2/test_measure.py +181 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_name_usage_tool.py +107 -5
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_parser.py +156 -34
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_policy.py +1 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_properties.py +293 -21
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_regex_sync.py +24 -2
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_render.py +57 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_reprs.py +6 -1
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_snapshot.py +78 -4
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_types.py +140 -5
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_vocab.py +304 -51
- nameparser-2.8.0/tests/v2/test_word_report.py +309 -0
- nameparser-2.6.0/nameparser/config/__init__.py +0 -43
- nameparser-2.6.0/nameparser/util.py +0 -14
- nameparser-2.6.0/nameparser/vocab/pt.toml +0 -70
- nameparser-2.6.0/nameparser/vocab/und.toml +0 -21
- nameparser-2.6.0/tests/v2/test_cases.py +0 -415
- {nameparser-2.6.0 → nameparser-2.8.0}/AUTHORS +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/LICENSE +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/MANIFEST.in +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/__main__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_locale.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_parser.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/__init__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_script_segment.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/_pipeline/_tokenize.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/_deprecated.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/_invariants.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/bound_first_names.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/bound_given_names.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/conjunctions.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/maiden_markers.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/prefixes.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/regexes.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/config/surnames.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/locales/__init__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/locales/ja.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/locales/ru.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/locales/tr_az.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/locales/zh.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/parser.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/py.typed +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ak.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/am.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/as.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/be.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/bg.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/bin.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/bo.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/bs.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ca.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/da.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/el.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/et.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/fa.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ff.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/fi.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/gu.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ha.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/hr.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/hu.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/hy.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/id.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/is.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ja.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ka.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/kk.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/km.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/kn.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ko.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/kok.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/lo.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/lt.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/lv.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/mi.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/mk.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ml.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/mn.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/mr.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/my.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/nb.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ne.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/nn.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/or.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ro.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ru.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sd.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/shn.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/si.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sk.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sl.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/sv.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ta.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/te.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/th.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ti.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/uk.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/ur.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/vi.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/yi.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/yo.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/zh.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser/vocab/zu.toml +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser.egg-info/dependency_links.txt +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser.egg-info/requires.txt +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/nameparser.egg-info/top_level.txt +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/setup.cfg +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/__init__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/base.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/conftest.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_bound_given_names.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_brute_force.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_capitalization.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_comma_variants.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_east_slavic_patronymic_order.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_initials.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_middle_name_as_last.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_nicknames.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_output_format.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_particles.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_turkic_patronymic_order.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/test_variations.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/__init__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/conftest.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/design_docs.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/__init__.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_extract.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_segment.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/pipeline/test_tokenize.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/rules_budget.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/rules_skeleton.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_cldr_agreement.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_cldr_corpus.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_cli.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_config_aliases.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_corpora.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_corpus_build.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_design_docs.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_doc_citations.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_doc_spellings.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_gnd_corpus.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_layering.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_local_jrc.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_locale.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_order_correspondence.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_rules_budget.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_rules_doc.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_rules_doc_grammar.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_rules_skeleton.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_wikidata_corpus.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_wikidata_native_corpus.py +0 -0
- {nameparser-2.6.0 → nameparser-2.8.0}/tests/v2/test_zh_surnames_tool.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nameparser
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.8.0
|
|
4
4
|
Summary: A simple Python module for parsing human names into their individual components.
|
|
5
5
|
Author-email: Derek Gulbranson <derek73@gmail.com>
|
|
6
6
|
License-Expression: LGPL-2.1-or-later
|
|
@@ -35,24 +35,30 @@ nameparser parses human names into seven fields — title, given, middle,
|
|
|
35
35
|
family, suffix, nickname, maiden. Results are immutable, configuration is
|
|
36
36
|
composable, and locale packs are opt-in.
|
|
37
37
|
|
|
38
|
-
📣 **nameparser 2.
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
📣 **nameparser 2.8 is out, the last 2.x feature release.**
|
|
39
|
+
|
|
40
|
+
⚠️ **HumanName is deprecated, and 3.0 removes it.** From 2.8 the 1.x
|
|
41
|
+
compatibility layer — ``HumanName``, ``Constants`` and the shared
|
|
42
|
+
``CONSTANTS`` — emits a ``DeprecationWarning`` where your code
|
|
43
|
+
constructs it, loads it from a pickle, or changes the shared
|
|
44
|
+
``CONSTANTS``. It keeps working through 2.x; ``parse()`` is the
|
|
45
|
+
replacement, and `Coming from 1.x`_ below says where to start. After
|
|
46
|
+
2.8 the 2.x line takes fixes only, and new work goes into 3.0.
|
|
47
|
+
|
|
48
|
+
2.8 also carries on 2.7's reading of titles that are also given names:
|
|
49
|
+
a title only inside a title phrase, so ``Queen Latifah`` keeps the
|
|
50
|
+
given name ``Queen`` while ``Her Majesty Queen Elizabeth`` reads the
|
|
51
|
+
title. The `release log
|
|
43
52
|
<https://nameparser.readthedocs.io/en/latest/release_log.html>`__ has
|
|
44
|
-
the details.
|
|
53
|
+
the details. Please `open an
|
|
54
|
+
issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
|
|
55
|
+
that parses wrong.
|
|
45
56
|
|
|
46
57
|
Chinese, Japanese and Korean names written in their own scripts are read
|
|
47
58
|
family-first, unspaced Korean names are split against the census surname
|
|
48
59
|
list, and CJK honorifics are recognized. See `East Asian names
|
|
49
60
|
<https://nameparser.readthedocs.io/en/latest/usage.html#east-asian-names>`__.
|
|
50
61
|
|
|
51
|
-
Existing ``HumanName`` code from 1.x keeps working through 2.x, and most
|
|
52
|
-
of it needs no changes; see `Coming from 1.x`_ below. Please `open an
|
|
53
|
-
issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
|
|
54
|
-
that parses wrong.
|
|
55
|
-
|
|
56
62
|
Installation
|
|
57
63
|
------------
|
|
58
64
|
|
|
@@ -124,8 +130,10 @@ Learn more
|
|
|
124
130
|
Coming from 1.x
|
|
125
131
|
----------------
|
|
126
132
|
|
|
127
|
-
``HumanName`` and ``CONSTANTS`` keep working
|
|
128
|
-
attributes, same mutation API
|
|
133
|
+
``HumanName`` and ``CONSTANTS`` keep working through 2.x — same imports,
|
|
134
|
+
same attributes, same mutation API — and warn from 2.8 on, since 3.0
|
|
135
|
+
removes them. Run your tests under ``python -W error::DeprecationWarning``
|
|
136
|
+
to find the sites; a read of ``CONSTANTS`` does not warn. What 2.0 removes is the batch of
|
|
129
137
|
deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
|
|
130
138
|
1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
|
|
131
139
|
Two things that check will not catch: four removals 1.4 never warned
|
|
@@ -7,24 +7,30 @@ nameparser parses human names into seven fields — title, given, middle,
|
|
|
7
7
|
family, suffix, nickname, maiden. Results are immutable, configuration is
|
|
8
8
|
composable, and locale packs are opt-in.
|
|
9
9
|
|
|
10
|
-
📣 **nameparser 2.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
📣 **nameparser 2.8 is out, the last 2.x feature release.**
|
|
11
|
+
|
|
12
|
+
⚠️ **HumanName is deprecated, and 3.0 removes it.** From 2.8 the 1.x
|
|
13
|
+
compatibility layer — ``HumanName``, ``Constants`` and the shared
|
|
14
|
+
``CONSTANTS`` — emits a ``DeprecationWarning`` where your code
|
|
15
|
+
constructs it, loads it from a pickle, or changes the shared
|
|
16
|
+
``CONSTANTS``. It keeps working through 2.x; ``parse()`` is the
|
|
17
|
+
replacement, and `Coming from 1.x`_ below says where to start. After
|
|
18
|
+
2.8 the 2.x line takes fixes only, and new work goes into 3.0.
|
|
19
|
+
|
|
20
|
+
2.8 also carries on 2.7's reading of titles that are also given names:
|
|
21
|
+
a title only inside a title phrase, so ``Queen Latifah`` keeps the
|
|
22
|
+
given name ``Queen`` while ``Her Majesty Queen Elizabeth`` reads the
|
|
23
|
+
title. The `release log
|
|
15
24
|
<https://nameparser.readthedocs.io/en/latest/release_log.html>`__ has
|
|
16
|
-
the details.
|
|
25
|
+
the details. Please `open an
|
|
26
|
+
issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
|
|
27
|
+
that parses wrong.
|
|
17
28
|
|
|
18
29
|
Chinese, Japanese and Korean names written in their own scripts are read
|
|
19
30
|
family-first, unspaced Korean names are split against the census surname
|
|
20
31
|
list, and CJK honorifics are recognized. See `East Asian names
|
|
21
32
|
<https://nameparser.readthedocs.io/en/latest/usage.html#east-asian-names>`__.
|
|
22
33
|
|
|
23
|
-
Existing ``HumanName`` code from 1.x keeps working through 2.x, and most
|
|
24
|
-
of it needs no changes; see `Coming from 1.x`_ below. Please `open an
|
|
25
|
-
issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
|
|
26
|
-
that parses wrong.
|
|
27
|
-
|
|
28
34
|
Installation
|
|
29
35
|
------------
|
|
30
36
|
|
|
@@ -96,8 +102,10 @@ Learn more
|
|
|
96
102
|
Coming from 1.x
|
|
97
103
|
----------------
|
|
98
104
|
|
|
99
|
-
``HumanName`` and ``CONSTANTS`` keep working
|
|
100
|
-
attributes, same mutation API
|
|
105
|
+
``HumanName`` and ``CONSTANTS`` keep working through 2.x — same imports,
|
|
106
|
+
same attributes, same mutation API — and warn from 2.8 on, since 3.0
|
|
107
|
+
removes them. Run your tests under ``python -W error::DeprecationWarning``
|
|
108
|
+
to find the sites; a read of ``CONSTANTS`` does not warn. What 2.0 removes is the batch of
|
|
101
109
|
deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
|
|
102
110
|
1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
|
|
103
111
|
Two things that check will not catch: four removals 1.4 never warned
|
|
@@ -27,6 +27,9 @@ from nameparser._types import (
|
|
|
27
27
|
Ambiguity,
|
|
28
28
|
AmbiguityKind,
|
|
29
29
|
ParsedName,
|
|
30
|
+
Reading,
|
|
31
|
+
ReadingKind,
|
|
32
|
+
ReadingSource,
|
|
30
33
|
Role,
|
|
31
34
|
Segmentation,
|
|
32
35
|
Segmenter,
|
|
@@ -38,7 +41,8 @@ __all__ = [
|
|
|
38
41
|
# v1 (compatibility layer)
|
|
39
42
|
"HumanName",
|
|
40
43
|
# v2 core
|
|
41
|
-
"Span", "Role", "Token", "Ambiguity", "AmbiguityKind", "
|
|
44
|
+
"Span", "Role", "Token", "Ambiguity", "AmbiguityKind", "Reading",
|
|
45
|
+
"ReadingKind", "ReadingSource", "ParsedName",
|
|
42
46
|
"STABLE_TAGS", "Segmentation", "Segmenter",
|
|
43
47
|
"Lexicon", "Policy", "PolicyPatch", "PatronymicRule", "Script", "UNSET",
|
|
44
48
|
"CapsSuffixes",
|
|
@@ -4,7 +4,7 @@ re-exports these names from the swap
|
|
|
4
4
|
commit onward; the whole module is deleted in 3.0 with the facade.
|
|
5
5
|
|
|
6
6
|
Layering: facade layer -- may import anything public; here that's
|
|
7
|
-
``nameparser.util`` for ``lc()``, ``nameparser.config.regexes`` for
|
|
7
|
+
``nameparser.util`` for ``lc()`` (as ``_lc``, the name that does not warn), ``nameparser.config.regexes`` for
|
|
8
8
|
the read-only regexes proxy's underlying compiled patterns, and
|
|
9
9
|
``nameparser._lexicon``/``_policy``/``_parser`` for the ``_snapshot()``
|
|
10
10
|
translation and the shared parser cache.
|
|
@@ -20,12 +20,16 @@ that cycle.
|
|
|
20
20
|
"""
|
|
21
21
|
from __future__ import annotations
|
|
22
22
|
|
|
23
|
+
import copy
|
|
23
24
|
import functools
|
|
25
|
+
import re
|
|
26
|
+
import sys
|
|
24
27
|
import warnings
|
|
25
28
|
from collections.abc import (
|
|
26
29
|
Callable, ItemsView, Iterable, Iterator, KeysView, Mapping, Set,
|
|
27
30
|
ValuesView,
|
|
28
31
|
)
|
|
32
|
+
from types import FrameType
|
|
29
33
|
from typing import NamedTuple, Self
|
|
30
34
|
|
|
31
35
|
from nameparser._lexicon import (
|
|
@@ -33,7 +37,7 @@ from nameparser._lexicon import (
|
|
|
33
37
|
)
|
|
34
38
|
from nameparser._parser import Parser
|
|
35
39
|
from nameparser._policy import PatronymicRule, Policy
|
|
36
|
-
from nameparser.util import lc
|
|
40
|
+
from nameparser.util import _lc as lc
|
|
37
41
|
|
|
38
42
|
|
|
39
43
|
#: The eight multi-word entries the pre-2.0 DEFAULT vocabulary shipped.
|
|
@@ -712,12 +716,64 @@ _UNSET = object()
|
|
|
712
716
|
_UNSET_KWARG = object()
|
|
713
717
|
|
|
714
718
|
|
|
719
|
+
#: The migration guide every 2.8 removal message points at.
|
|
720
|
+
MIGRATION_GUIDE = "https://nameparser.readthedocs.io/en/latest/migrate.html"
|
|
721
|
+
|
|
722
|
+
# The 2.8 removal messages (decisions/3-0-reevaluations, 2026-10-28).
|
|
723
|
+
# Each names code that type-checks and runs, pinned by
|
|
724
|
+
# tests/v2/test_deprecations.py, and each opens with a fixed phrase
|
|
725
|
+
# pyproject's filterwarnings ignores by message.
|
|
715
726
|
_SHARED_MUTATION_MESSAGE = (
|
|
716
727
|
"mutating the shared CONSTANTS singleton is deprecated and will be "
|
|
717
|
-
"removed in 3.0
|
|
718
|
-
"
|
|
719
|
-
"
|
|
728
|
+
"removed in 3.0 with HumanName and Constants; configure a Parser "
|
|
729
|
+
"instead, e.g. Parser(lexicon=Lexicon.default().add(titles={'dean'})). "
|
|
730
|
+
f"See {MIGRATION_GUIDE}"
|
|
731
|
+
)
|
|
732
|
+
CONSTANTS_DEPRECATION = (
|
|
733
|
+
"Constants is deprecated and will be removed in 3.0 with HumanName; "
|
|
734
|
+
"configure a Parser instead, e.g. "
|
|
735
|
+
"Parser(lexicon=Lexicon.default().add(titles={'dean'})). "
|
|
736
|
+
f"See {MIGRATION_GUIDE}"
|
|
737
|
+
)
|
|
738
|
+
CONSTANTS_PICKLE_DEPRECATION = (
|
|
739
|
+
"Constants pickles stop loading in 3.0, when Constants is removed; "
|
|
740
|
+
"pickle a Parser instead, e.g. "
|
|
741
|
+
"Parser(lexicon=Lexicon.default().add(titles={'dean'})). "
|
|
742
|
+
f"See {MIGRATION_GUIDE}"
|
|
720
743
|
)
|
|
744
|
+
#: one message per manager class, keyed by name, for
|
|
745
|
+
#: nameparser.config.__getattr__
|
|
746
|
+
MANAGER_DEPRECATIONS = {
|
|
747
|
+
name: (
|
|
748
|
+
f"nameparser.config.{name} is deprecated and will be removed in "
|
|
749
|
+
f"3.0 with Constants; Lexicon fields take plain sets, e.g. "
|
|
750
|
+
f"Lexicon.default().add(titles={{'dean'}}). See {MIGRATION_GUIDE}"
|
|
751
|
+
)
|
|
752
|
+
for name in ("SetManager", "TupleManager", "RegexTupleManager")
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
|
|
756
|
+
def _quiet_setstate(new: object, state: dict[str, object], base: type,
|
|
757
|
+
message: str) -> None:
|
|
758
|
+
"""Restore a copy through its class's own ``__setstate__``.
|
|
759
|
+
|
|
760
|
+
``copy.copy``/``copy.deepcopy`` reconstruct through ``__setstate__``,
|
|
761
|
+
which since 2.8 warns that a pickle was loaded, and a copy is no
|
|
762
|
+
load. ``base``'s own hook restores privately; a subclass's override
|
|
763
|
+
is called, as it was before 2.8, with only the load warning
|
|
764
|
+
filtered, by message. The filter is taken only then: entering
|
|
765
|
+
``catch_warnings`` clears every module's warnings registry, so on
|
|
766
|
+
every copy it would re-show warnings the caller's filters show once
|
|
767
|
+
per line. A copy of the shared ``CONSTANTS`` stays quiet, as before:
|
|
768
|
+
a ``HumanName`` built on the copy still warns.
|
|
769
|
+
"""
|
|
770
|
+
if type(new).__setstate__ is base.__setstate__: # type: ignore[attr-defined]
|
|
771
|
+
new._restore(state) # type: ignore[attr-defined]
|
|
772
|
+
return
|
|
773
|
+
with warnings.catch_warnings():
|
|
774
|
+
warnings.filterwarnings("ignore", message=re.escape(message),
|
|
775
|
+
category=DeprecationWarning)
|
|
776
|
+
new.__setstate__(state) # type: ignore[attr-defined]
|
|
721
777
|
|
|
722
778
|
|
|
723
779
|
def _default_vocab() -> dict[str, frozenset[str]]:
|
|
@@ -731,13 +787,19 @@ def _default_vocab() -> dict[str, frozenset[str]]:
|
|
|
731
787
|
from nameparser.config.suffixes import (
|
|
732
788
|
SUFFIX_ACRONYMS, SUFFIX_ACRONYMS_AMBIGUOUS, SUFFIX_WORDS,
|
|
733
789
|
)
|
|
734
|
-
from nameparser.config.
|
|
790
|
+
from nameparser.config._titles_2_6_0 import TITLES_2_6_0
|
|
791
|
+
from nameparser.config.titles import (
|
|
792
|
+
GIVEN_NAME_TITLES, TITLES, TITLES_AMBIGUOUS)
|
|
735
793
|
return {
|
|
736
794
|
"prefixes": PARTICLES,
|
|
737
795
|
"suffix_acronyms": SUFFIX_ACRONYMS,
|
|
738
796
|
"suffix_not_acronyms": SUFFIX_WORDS,
|
|
739
797
|
"suffix_acronyms_ambiguous": SUFFIX_ACRONYMS_AMBIGUOUS,
|
|
740
|
-
|
|
798
|
+
# 2.6.0's titles, less any word that is no title now: one a
|
|
799
|
+
# later release made a title only inside a title phrase
|
|
800
|
+
# (rules/H9) stays a v1 title, so remove() and `in` answer as
|
|
801
|
+
# they did; _build_snapshot reads it by the phrase
|
|
802
|
+
"titles": TITLES | (TITLES_2_6_0 & TITLES_AMBIGUOUS),
|
|
741
803
|
"first_name_titles": GIVEN_NAME_TITLES,
|
|
742
804
|
"conjunctions": CONJUNCTIONS,
|
|
743
805
|
"bound_first_names": BOUND_GIVEN_NAMES,
|
|
@@ -780,9 +842,11 @@ class Constants:
|
|
|
780
842
|
|
|
781
843
|
The module-level ``CONSTANTS`` singleton (below) has ``_shared``
|
|
782
844
|
flipped to ``True``: any mutation reached through it emits
|
|
783
|
-
``DeprecationWarning`` pointing at ``Lexicon``/``Policy
|
|
784
|
-
``
|
|
785
|
-
|
|
845
|
+
``DeprecationWarning`` pointing at ``Lexicon``/``Policy``. Since 2.8
|
|
846
|
+
constructing a ``Constants``, copying one with ``copy()`` and
|
|
847
|
+
loading one from a pickle warn too, since the whole class goes in
|
|
848
|
+
3.0; the singleton is built without the warning, so importing
|
|
849
|
+
``nameparser`` stays quiet.
|
|
786
850
|
"""
|
|
787
851
|
|
|
788
852
|
_shared = False # the CONSTANTS singleton flips this to True
|
|
@@ -830,6 +894,41 @@ class Constants:
|
|
|
830
894
|
regexes: object = _UNSET_KWARG,
|
|
831
895
|
patronymic_name_order: bool = False,
|
|
832
896
|
middle_name_as_last: bool = False,
|
|
897
|
+
) -> None:
|
|
898
|
+
# every construction warns, at the caller's line; the warnings
|
|
899
|
+
# registry, not a flag here, dedups repeats from one line
|
|
900
|
+
# (decisions/3-0-reevaluations, 2026-10-28)
|
|
901
|
+
warnings.warn(CONSTANTS_DEPRECATION, DeprecationWarning,
|
|
902
|
+
stacklevel=2)
|
|
903
|
+
self._init(
|
|
904
|
+
prefixes=prefixes, suffix_acronyms=suffix_acronyms,
|
|
905
|
+
suffix_not_acronyms=suffix_not_acronyms,
|
|
906
|
+
suffix_acronyms_ambiguous=suffix_acronyms_ambiguous,
|
|
907
|
+
titles=titles, first_name_titles=first_name_titles,
|
|
908
|
+
conjunctions=conjunctions, bound_first_names=bound_first_names,
|
|
909
|
+
non_first_name_prefixes=non_first_name_prefixes,
|
|
910
|
+
capitalization_exceptions=capitalization_exceptions,
|
|
911
|
+
regexes=regexes, patronymic_name_order=patronymic_name_order,
|
|
912
|
+
middle_name_as_last=middle_name_as_last)
|
|
913
|
+
|
|
914
|
+
def _init(
|
|
915
|
+
self,
|
|
916
|
+
*,
|
|
917
|
+
prefixes: Iterable[str] | object = _UNSET_KWARG,
|
|
918
|
+
suffix_acronyms: Iterable[str] | object = _UNSET_KWARG,
|
|
919
|
+
suffix_not_acronyms: Iterable[str] | object = _UNSET_KWARG,
|
|
920
|
+
suffix_acronyms_ambiguous: Iterable[str] | object = _UNSET_KWARG,
|
|
921
|
+
titles: Iterable[str] | object = _UNSET_KWARG,
|
|
922
|
+
first_name_titles: Iterable[str] | object = _UNSET_KWARG,
|
|
923
|
+
conjunctions: Iterable[str] | object = _UNSET_KWARG,
|
|
924
|
+
bound_first_names: Iterable[str] | object = _UNSET_KWARG,
|
|
925
|
+
non_first_name_prefixes: Iterable[str] | object = _UNSET_KWARG,
|
|
926
|
+
capitalization_exceptions:
|
|
927
|
+
Mapping[str, str] | Iterable[tuple[str, str]] | object
|
|
928
|
+
= _UNSET_KWARG,
|
|
929
|
+
regexes: object = _UNSET_KWARG,
|
|
930
|
+
patronymic_name_order: bool = False,
|
|
931
|
+
middle_name_as_last: bool = False,
|
|
833
932
|
) -> None:
|
|
834
933
|
# v1.4 parity constructor kwargs (#238/#242/#244 hardening); the
|
|
835
934
|
# signature is spelled out rather than **kwargs so an unknown
|
|
@@ -915,19 +1014,20 @@ class Constants:
|
|
|
915
1014
|
"""
|
|
916
1015
|
|
|
917
1016
|
def _bump(self) -> None:
|
|
918
|
-
# stacklevel
|
|
919
|
-
#
|
|
920
|
-
#
|
|
921
|
-
#
|
|
922
|
-
#
|
|
923
|
-
#
|
|
924
|
-
# once. Either way the warning still fires from this module,
|
|
925
|
-
# not the manager's true caller, which is enough: only the
|
|
926
|
-
# DeprecationWarning's presence/category/message are load-
|
|
927
|
-
# bearing (see the specified test), not the reported line.
|
|
1017
|
+
# A fixed stacklevel lands on the caller only for one call depth:
|
|
1018
|
+
# a scalar arrives through __setattr__, a set's add() through
|
|
1019
|
+
# _changed(), a dict's update() and |= through __setitem__ per
|
|
1020
|
+
# key. Walk out of this module instead, as _lexicon's
|
|
1021
|
+
# _warn_dead_entry does, so the warning names the caller's line;
|
|
1022
|
+
# attributed here, Python's default filters hid it.
|
|
928
1023
|
if self._shared:
|
|
1024
|
+
level = 2
|
|
1025
|
+
frame: FrameType | None = sys._getframe(1)
|
|
1026
|
+
while (frame is not None
|
|
1027
|
+
and frame.f_globals.get("__name__") == __name__):
|
|
1028
|
+
frame, level = frame.f_back, level + 1
|
|
929
1029
|
warnings.warn(_SHARED_MUTATION_MESSAGE, DeprecationWarning,
|
|
930
|
-
stacklevel=
|
|
1030
|
+
stacklevel=level)
|
|
931
1031
|
object.__setattr__(self, "_generation", self._generation + 1)
|
|
932
1032
|
|
|
933
1033
|
def __setattr__(self, name: str, value: object) -> None:
|
|
@@ -981,7 +1081,27 @@ class Constants:
|
|
|
981
1081
|
v1 (which deepcopied __dict__): attributes OUTSIDE the known
|
|
982
1082
|
field surface -- e.g. ad-hoc names stashed on the instance --
|
|
983
1083
|
are not carried by copy() or pickling; only the enumerated
|
|
984
|
-
fields survive.
|
|
1084
|
+
fields survive. Warns since 2.8, as construction does: a copy
|
|
1085
|
+
is a new private ``Constants``, and ``CONSTANTS.copy()`` builds
|
|
1086
|
+
one without calling the constructor.""" # #260
|
|
1087
|
+
warnings.warn(CONSTANTS_DEPRECATION, DeprecationWarning,
|
|
1088
|
+
stacklevel=2)
|
|
1089
|
+
return self._copy()
|
|
1090
|
+
|
|
1091
|
+
def __copy__(self) -> Constants:
|
|
1092
|
+
new = object.__new__(type(self))
|
|
1093
|
+
_quiet_setstate(new, self.__getstate__(), Constants,
|
|
1094
|
+
CONSTANTS_PICKLE_DEPRECATION)
|
|
1095
|
+
return new
|
|
1096
|
+
|
|
1097
|
+
def __deepcopy__(self, memo: dict[int, object]) -> Constants:
|
|
1098
|
+
new = object.__new__(type(self))
|
|
1099
|
+
memo[id(self)] = new
|
|
1100
|
+
_quiet_setstate(new, copy.deepcopy(self.__getstate__(), memo),
|
|
1101
|
+
Constants, CONSTANTS_PICKLE_DEPRECATION)
|
|
1102
|
+
return new
|
|
1103
|
+
|
|
1104
|
+
def _copy(self) -> Constants:
|
|
985
1105
|
# An independent instance with its own generation counter and
|
|
986
1106
|
# its own manager callbacks -- not a shared-state alias like a
|
|
987
1107
|
# naive attribute-for-attribute copy would produce. v1's copy()
|
|
@@ -1045,10 +1165,15 @@ class Constants:
|
|
|
1045
1165
|
removal path.
|
|
1046
1166
|
"""
|
|
1047
1167
|
from nameparser.config.conjunctions import CONJUNCTIONS_AMBIGUOUS
|
|
1168
|
+
from nameparser.config.given_names import GIVEN_NAME_ABBREVIATIONS
|
|
1048
1169
|
from nameparser.config.maiden_markers import MAIDEN_MARKERS
|
|
1049
|
-
from nameparser.config.suffixes import
|
|
1170
|
+
from nameparser.config.suffixes import (
|
|
1171
|
+
AGNOMENS, GLUED_HONORIFICS, SUFFIX_WORDS_AMBIGUOUS)
|
|
1050
1172
|
from nameparser.config.surnames import KOREAN_SURNAMES
|
|
1051
|
-
from nameparser.config.
|
|
1173
|
+
from nameparser.config._titles_2_6_0 import TITLES_2_6_0
|
|
1174
|
+
from nameparser.config.titles import (
|
|
1175
|
+
AFTER_GIVEN_TITLES, TITLE_MODIFIERS, TITLE_PHRASES, TITLE_STYLES,
|
|
1176
|
+
TITLES_AMBIGUOUS)
|
|
1052
1177
|
# Every set field and every capitalization_exceptions key passes
|
|
1053
1178
|
# _v1_matchable BEFORE any set algebra below: an entry v1 could
|
|
1054
1179
|
# never match, or one Lexicon folds to empty (#582), is dropped
|
|
@@ -1071,6 +1196,27 @@ class Constants:
|
|
|
1071
1196
|
conjunctions = matchable("conjunctions")
|
|
1072
1197
|
bound = matchable("bound_first_names")
|
|
1073
1198
|
titles = matchable("titles")
|
|
1199
|
+
# A title 2.6.0 listed that a later release made a title only
|
|
1200
|
+
# inside a title phrase (rules/H9) is in v1's default `titles`,
|
|
1201
|
+
# where 2.6.0 had it, so remove(), discard() and `in` answer as
|
|
1202
|
+
# they did (decisions/H9, 2026-10-26). Kept, it is read as the
|
|
1203
|
+
# default reads it, by the phrase; removed, it is no title at
|
|
1204
|
+
# all, as removing it made it in 2.6.0. The one 2.6.0 reading
|
|
1205
|
+
# with no v1 spelling left is the word as a title everywhere:
|
|
1206
|
+
# v1 can say "a title" or "not a title", and "a title" now means
|
|
1207
|
+
# the phrase reading. A word 2.6.0 never listed (`dean`) is not
|
|
1208
|
+
# in `moved`, so adding it is still a title everywhere, the 1.4
|
|
1209
|
+
# recipe the phrase test honours below. Compared folded, as the
|
|
1210
|
+
# two cross-set computations below are (#582), so a spelling
|
|
1211
|
+
# Lexicon folds onto a moved word (`king。`) is read as it is.
|
|
1212
|
+
moved = TITLES_2_6_0 & TITLES_AMBIGUOUS
|
|
1213
|
+
kept_moved = frozenset(w for w in titles if _normalize(w) in moved)
|
|
1214
|
+
phrase_only = ((TITLES_AMBIGUOUS - moved) | kept_moved
|
|
1215
|
+
if titles else frozenset())
|
|
1216
|
+
# ...and the three intersections with the phrase vocabulary read
|
|
1217
|
+
# the same folded spellings, or a folded moved word kept its
|
|
1218
|
+
# phrase reading but lost its modifier one (`wing。`)
|
|
1219
|
+
any_title = frozenset(_normalize(w) for w in titles | phrase_only)
|
|
1074
1220
|
first_name_titles = matchable("first_name_titles")
|
|
1075
1221
|
non_given = matchable("non_first_name_prefixes")
|
|
1076
1222
|
ambiguous_acronyms = matchable("suffix_acronyms_ambiguous") & acronyms
|
|
@@ -1136,7 +1282,7 @@ class Constants:
|
|
|
1136
1282
|
# v1 also had, later, at capitalize().
|
|
1137
1283
|
try:
|
|
1138
1284
|
lexicon = Lexicon(
|
|
1139
|
-
titles=titles,
|
|
1285
|
+
titles=titles - kept_moved,
|
|
1140
1286
|
# TRANSLATE, do not filter. The two versions build the same
|
|
1141
1287
|
# lookup key differently: v1 joins the raw title run and
|
|
1142
1288
|
# then applies lc(), which strips only the whole string's
|
|
@@ -1193,6 +1339,15 @@ class Constants:
|
|
|
1193
1339
|
# through this intersection.
|
|
1194
1340
|
conjunctions_ambiguous=CONJUNCTIONS_AMBIGUOUS & conjunctions,
|
|
1195
1341
|
bound_given_names=bound,
|
|
1342
|
+
# likewise no v1 manager: an abbreviated given name
|
|
1343
|
+
# reading over rules/H2's shape is 2.7 behavior (#789),
|
|
1344
|
+
# so the set rides in the snapshot only, passed whole.
|
|
1345
|
+
# No v1 knob reaches it, and none needs to: a word a v1
|
|
1346
|
+
# caller ADDS to `titles` is a title wherever it stands,
|
|
1347
|
+
# since the leading peel asks the title vocabulary before
|
|
1348
|
+
# it weighs the shape, as it did in 1.4
|
|
1349
|
+
# (`c.titles.add("chas")`)
|
|
1350
|
+
given_name_abbreviations=GIVEN_NAME_ABBREVIATIONS,
|
|
1196
1351
|
# v1 Constants has no manager for these (#274 is 2.0
|
|
1197
1352
|
# behavior); the data module is the only source
|
|
1198
1353
|
maiden_markers=MAIDEN_MARKERS,
|
|
@@ -1216,6 +1371,51 @@ class Constants:
|
|
|
1216
1371
|
# so the intersection is kept for `_snapshot() ==
|
|
1217
1372
|
# Lexicon.default()` legibility, as conjunctions_ambiguous'.
|
|
1218
1373
|
after_given_titles=AFTER_GIVEN_TITLES & titles,
|
|
1374
|
+
# likewise no v1 manager: a suffix word that is also a
|
|
1375
|
+
# name is 2.7 behavior (#752), so it rides in the
|
|
1376
|
+
# snapshot only. Intersect with the word set, as the
|
|
1377
|
+
# tails are: Lexicon enforces the subset, and deleting
|
|
1378
|
+
# the suffix word is the one v1 knob, which turns the
|
|
1379
|
+
# reading off. agnomens is consulted only inside it, so
|
|
1380
|
+
# its intersection is kept for legibility alone.
|
|
1381
|
+
# A v1 caller who added such a word to suffix_acronyms
|
|
1382
|
+
# had it read as a suffix through the acronym branch,
|
|
1383
|
+
# so the word leaves the gate rather than raising at
|
|
1384
|
+
# Lexicon's word-gate check (folded, as the two
|
|
1385
|
+
# cross-set computations above are).
|
|
1386
|
+
suffix_words_ambiguous=frozenset(
|
|
1387
|
+
w for w in SUFFIX_WORDS_AMBIGUOUS & suffix_words
|
|
1388
|
+
if _normalize(w) not in {
|
|
1389
|
+
_normalize(a) for a in acronyms - ambiguous_acronyms}),
|
|
1390
|
+
agnomens=AGNOMENS & SUFFIX_WORDS_AMBIGUOUS & suffix_words,
|
|
1391
|
+
# likewise no v1 manager: the title phrase (rules/H9) is
|
|
1392
|
+
# 2.7 behavior (#752), so its sets ride in the snapshot
|
|
1393
|
+
# only. A title that may be a given name is not in
|
|
1394
|
+
# TITLES, so v1's `titles` holds one only where 2.6.0
|
|
1395
|
+
# listed it (`moved`, above, read by the phrase), and one
|
|
1396
|
+
# 2.6.0 never listed that a v1 caller ADDS to `titles` is
|
|
1397
|
+
# a title wherever it stands, as it was in 1.4
|
|
1398
|
+
# (`c.titles.add("dean")`, the documented recipe): the
|
|
1399
|
+
# phrase test reads a word of titles_ambiguous only where
|
|
1400
|
+
# it is not in titles. The
|
|
1401
|
+
# knob that reaches the other three is deleting a title,
|
|
1402
|
+
# which turns its modifier, style or phrase reading off
|
|
1403
|
+
# with it; Lexicon checks none of them, so the
|
|
1404
|
+
# intersections are kept for legibility, as
|
|
1405
|
+
# after_given_titles' is.
|
|
1406
|
+
# ...save where the caller emptied `titles`, v1's way to
|
|
1407
|
+
# turn title detection off (customize.rst). A caller who
|
|
1408
|
+
# REPLACES the list keeps the phrase reading of the words
|
|
1409
|
+
# 2.6.0 never listed: v1 has no knob for them, and what a
|
|
1410
|
+
# replaced list means for words it never held is not
|
|
1411
|
+
# something it says. A moved word reads by whether the
|
|
1412
|
+
# replaced list holds it, as any v1 title does
|
|
1413
|
+
titles_ambiguous=phrase_only,
|
|
1414
|
+
title_modifiers=TITLE_MODIFIERS & any_title,
|
|
1415
|
+
title_styles=TITLE_STYLES & any_title,
|
|
1416
|
+
title_phrases=frozenset(
|
|
1417
|
+
p for p in TITLE_PHRASES
|
|
1418
|
+
if all(w in any_title for w in p.split(" "))),
|
|
1219
1419
|
# TupleManager is dict[str, object] (v1 parity: values were
|
|
1220
1420
|
# never statically str-typed); every real entry is a str,
|
|
1221
1421
|
# same assumption _DelimiterManager's sentinel lookup makes.
|
|
@@ -1290,7 +1490,22 @@ class Constants:
|
|
|
1290
1490
|
# DROPPED (#255: empty is always '' in 2.0).
|
|
1291
1491
|
state = {k: v for k, v in state.items()
|
|
1292
1492
|
if k != "empty_attribute_default"}
|
|
1293
|
-
|
|
1493
|
+
warnings.warn(CONSTANTS_PICKLE_DEPRECATION, DeprecationWarning,
|
|
1494
|
+
stacklevel=2)
|
|
1495
|
+
self._restore(state)
|
|
1496
|
+
|
|
1497
|
+
def _restore(self, state: dict[str, object]) -> None:
|
|
1498
|
+
# defaults, then overlay. A subclass's own __init__ runs here as
|
|
1499
|
+
# it did before 2.8; its super().__init__() would warn that a
|
|
1500
|
+
# Constants was constructed, which a restore is not
|
|
1501
|
+
if type(self).__init__ is Constants.__init__:
|
|
1502
|
+
self._init()
|
|
1503
|
+
else:
|
|
1504
|
+
with warnings.catch_warnings():
|
|
1505
|
+
warnings.filterwarnings(
|
|
1506
|
+
"ignore", message=re.escape(CONSTANTS_DEPRECATION),
|
|
1507
|
+
category=DeprecationWarning)
|
|
1508
|
+
self.__init__() # type: ignore[misc]
|
|
1294
1509
|
# (managers re-wrapped below so _on_change points at THIS
|
|
1295
1510
|
# instance, not whatever produced the incoming state)
|
|
1296
1511
|
managers: dict[str, SetManager] = {}
|
|
@@ -1331,5 +1546,7 @@ class Constants:
|
|
|
1331
1546
|
object.__setattr__(self, name, state[name])
|
|
1332
1547
|
|
|
1333
1548
|
|
|
1334
|
-
|
|
1549
|
+
# built past __init__, so importing nameparser never warns
|
|
1550
|
+
CONSTANTS = object.__new__(Constants)
|
|
1551
|
+
CONSTANTS._init()
|
|
1335
1552
|
object.__setattr__(CONSTANTS, "_shared", True)
|
|
@@ -7,6 +7,7 @@ Layering: facade layer -- may import anything public plus _render.
|
|
|
7
7
|
"""
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
+
import copy
|
|
10
11
|
import dataclasses
|
|
11
12
|
import warnings
|
|
12
13
|
from collections.abc import Iterator, Mapping
|
|
@@ -29,7 +30,8 @@ from typing import Any
|
|
|
29
30
|
import nameparser.config # noqa: F401
|
|
30
31
|
|
|
31
32
|
import nameparser._render as _render
|
|
32
|
-
from nameparser._config_shim import CONSTANTS, Constants,
|
|
33
|
+
from nameparser._config_shim import (CONSTANTS, MIGRATION_GUIDE, Constants,
|
|
34
|
+
_cached_parser, _quiet_setstate)
|
|
33
35
|
from nameparser._lexicon import _normalize, _spells_an_initial
|
|
34
36
|
from nameparser._parser import Parser
|
|
35
37
|
from nameparser._types import (FOLDED_TAG, UNCLASSIFIED_TAG,
|
|
@@ -60,6 +62,19 @@ _V1_HOOKS = (
|
|
|
60
62
|
# whole module is deleted with the facade layer in 3.0.
|
|
61
63
|
_WARNED_SUBCLASSES: set[type] = set()
|
|
62
64
|
|
|
65
|
+
# The 2.8 removal messages (decisions/3-0-reevaluations, 2026-10-28);
|
|
66
|
+
# the code each offers is pinned by tests/v2/test_deprecations.py.
|
|
67
|
+
HUMANNAME_DEPRECATION = (
|
|
68
|
+
"HumanName is deprecated and will be removed in 3.0; use "
|
|
69
|
+
"nameparser.parse(text), whose fields are given and family where "
|
|
70
|
+
f"HumanName has first and last. See {MIGRATION_GUIDE}"
|
|
71
|
+
)
|
|
72
|
+
HUMANNAME_PICKLE_DEPRECATION = (
|
|
73
|
+
"HumanName pickles stop loading in 3.0, when HumanName is removed; "
|
|
74
|
+
"store parse(text).as_dict() or the original string instead. "
|
|
75
|
+
f"See {MIGRATION_GUIDE}"
|
|
76
|
+
)
|
|
77
|
+
|
|
63
78
|
|
|
64
79
|
def _empty_parsed() -> ParsedName:
|
|
65
80
|
return ParsedName(original="", tokens=(), ambiguities=())
|
|
@@ -71,7 +86,8 @@ class HumanName:
|
|
|
71
86
|
resolved from the bound ``Constants`` shim (dirty-tracked via its
|
|
72
87
|
``_generation``). Keeps every v1 spelling (``first``/``last`` over
|
|
73
88
|
the core ``given``/``family``); the v1 parsing hooks are never
|
|
74
|
-
called (#280).
|
|
89
|
+
called (#280). Deprecated since 2.8, warning at every construction,
|
|
90
|
+
and deleted with the facade layer in 3.0.
|
|
75
91
|
"""
|
|
76
92
|
|
|
77
93
|
def __init__(
|
|
@@ -101,6 +117,12 @@ class HumanName:
|
|
|
101
117
|
raise TypeError(
|
|
102
118
|
f"constants must be a Constants instance, got {constants!r}"
|
|
103
119
|
)
|
|
120
|
+
# every construction warns, at the caller's line (a subclass's
|
|
121
|
+
# super().__init__() is its author's line); never once per
|
|
122
|
+
# process, so a dependency's first HumanName cannot consume the
|
|
123
|
+
# warning meant for the caller's own
|
|
124
|
+
warnings.warn(HUMANNAME_DEPRECATION, DeprecationWarning,
|
|
125
|
+
stacklevel=2)
|
|
104
126
|
self._warn_overridden_hooks()
|
|
105
127
|
self._C = constants
|
|
106
128
|
self._snapshot_gen = -1 # forces first resolve
|
|
@@ -151,7 +173,8 @@ class HumanName:
|
|
|
151
173
|
f"{cls.__name__} overrides v1 parsing hooks "
|
|
152
174
|
f"({', '.join(overridden)}) that the 2.0 facade never "
|
|
153
175
|
f"calls; parsing is delegated to the core Parser. "
|
|
154
|
-
f"Migrate to the Lexicon/Policy API
|
|
176
|
+
f"Migrate to the Lexicon/Policy API; HumanName is "
|
|
177
|
+
f"removed in 3.0. See "
|
|
155
178
|
f"https://github.com/derek73/python-nameparser/issues/280",
|
|
156
179
|
DeprecationWarning, stacklevel=3)
|
|
157
180
|
|
|
@@ -888,6 +911,28 @@ class HumanName:
|
|
|
888
911
|
return state
|
|
889
912
|
|
|
890
913
|
def __setstate__(self, state: dict[str, Any]) -> None:
|
|
914
|
+
# unpickling skips __init__, so the construction warning never
|
|
915
|
+
# reaches a pickle; this one does, at the pickle.loads line
|
|
916
|
+
warnings.warn(HUMANNAME_PICKLE_DEPRECATION, DeprecationWarning,
|
|
917
|
+
stacklevel=2)
|
|
918
|
+
self._restore(state)
|
|
919
|
+
|
|
920
|
+
def __copy__(self) -> HumanName:
|
|
921
|
+
# copy.copy/deepcopy go through the state hooks, a subclass's
|
|
922
|
+
# included, and a copy is no pickle load (_quiet_setstate)
|
|
923
|
+
new = object.__new__(type(self))
|
|
924
|
+
_quiet_setstate(new, self.__getstate__(), HumanName,
|
|
925
|
+
HUMANNAME_PICKLE_DEPRECATION)
|
|
926
|
+
return new
|
|
927
|
+
|
|
928
|
+
def __deepcopy__(self, memo: dict[int, object]) -> HumanName:
|
|
929
|
+
new = object.__new__(type(self))
|
|
930
|
+
memo[id(self)] = new
|
|
931
|
+
_quiet_setstate(new, copy.deepcopy(self.__getstate__(), memo),
|
|
932
|
+
HumanName, HUMANNAME_PICKLE_DEPRECATION)
|
|
933
|
+
return new
|
|
934
|
+
|
|
935
|
+
def _restore(self, state: dict[str, Any]) -> None:
|
|
891
936
|
c = state.get("C")
|
|
892
937
|
self._C = CONSTANTS if c is None else c
|
|
893
938
|
self._snapshot_gen = -1
|