nameparser 2.7.0__tar.gz → 2.8.1__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.
Files changed (241) hide show
  1. {nameparser-2.7.0/nameparser.egg-info → nameparser-2.8.1}/PKG-INFO +31 -17
  2. {nameparser-2.7.0 → nameparser-2.8.1}/README.rst +30 -16
  3. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_config_shim.py +168 -36
  4. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_facade.py +48 -3
  5. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_lexicon.py +177 -14
  6. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_post_rules.py +1 -1
  7. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_vocab.py +6 -2
  8. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_version.py +5 -5
  9. nameparser-2.8.1/nameparser/config/__init__.py +79 -0
  10. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/_compiled.py +97 -8
  11. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/_deprecated.py +84 -5
  12. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/bound_given_names.py +15 -0
  13. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/capitalization.py +20 -0
  14. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/conjunctions.py +20 -0
  15. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/given_names.py +15 -0
  16. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/maiden_markers.py +20 -0
  17. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/particles.py +16 -0
  18. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/regexes.py +26 -0
  19. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/suffixes.py +14 -2
  20. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/titles.py +20 -3
  21. nameparser-2.8.1/nameparser/util.py +46 -0
  22. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/en.toml +37 -17
  23. {nameparser-2.7.0 → nameparser-2.8.1/nameparser.egg-info}/PKG-INFO +31 -17
  24. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser.egg-info/SOURCES.txt +5 -0
  25. {nameparser-2.7.0 → nameparser-2.8.1}/pyproject.toml +14 -0
  26. nameparser-2.8.1/tests/removals.py +31 -0
  27. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_constants.py +9 -3
  28. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_first_name.py +7 -3
  29. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_python_api.py +11 -8
  30. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/cases.py +182 -7
  31. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_cases.py +10 -4
  32. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_config_aliases.py +26 -4
  33. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_config_shim.py +6 -1
  34. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_contracts.py +7 -1
  35. nameparser-2.8.1/tests/v2/test_deprecations.py +460 -0
  36. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_facade.py +3 -0
  37. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_lexicon.py +5 -0
  38. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_local_agreement.py +82 -6
  39. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_local_corpora.py +147 -7
  40. nameparser-2.8.1/tests/v2/test_local_orcid.py +561 -0
  41. nameparser-2.8.1/tests/v2/test_local_patentsview.py +366 -0
  42. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_measure.py +5 -2
  43. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_name_usage_tool.py +100 -0
  44. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_properties.py +1 -1
  45. nameparser-2.8.1/tests/v2/test_removals_2_8_1.py +435 -0
  46. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_render.py +4 -0
  47. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_word_report.py +65 -65
  48. nameparser-2.7.0/nameparser/config/__init__.py +0 -43
  49. nameparser-2.7.0/nameparser/util.py +0 -14
  50. {nameparser-2.7.0 → nameparser-2.8.1}/AUTHORS +0 -0
  51. {nameparser-2.7.0 → nameparser-2.8.1}/LICENSE +0 -0
  52. {nameparser-2.7.0 → nameparser-2.8.1}/MANIFEST.in +0 -0
  53. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/__init__.py +0 -0
  54. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/__main__.py +0 -0
  55. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_locale.py +0 -0
  56. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_parser.py +0 -0
  57. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/__init__.py +0 -0
  58. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_assemble.py +0 -0
  59. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_assign.py +0 -0
  60. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_classify.py +0 -0
  61. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_comma.py +0 -0
  62. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_extract.py +0 -0
  63. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_group.py +0 -0
  64. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_pieces.py +0 -0
  65. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_script_segment.py +0 -0
  66. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_segment.py +0 -0
  67. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_state.py +0 -0
  68. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_pipeline/_tokenize.py +0 -0
  69. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_policy.py +0 -0
  70. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_render.py +0 -0
  71. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/_types.py +0 -0
  72. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/_invariants.py +0 -0
  73. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/_titles_2_6_0.py +0 -0
  74. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/bound_first_names.py +0 -0
  75. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/prefixes.py +0 -0
  76. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/config/surnames.py +0 -0
  77. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/locales/__init__.py +0 -0
  78. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/locales/ja.py +0 -0
  79. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/locales/ru.py +0 -0
  80. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/locales/tr_az.py +0 -0
  81. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/locales/zh.py +0 -0
  82. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/parser.py +0 -0
  83. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/py.typed +0 -0
  84. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ak.toml +0 -0
  85. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/am.toml +0 -0
  86. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ar.toml +0 -0
  87. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/as.toml +0 -0
  88. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/be.toml +0 -0
  89. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/bg.toml +0 -0
  90. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/bin.toml +0 -0
  91. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/bn.toml +0 -0
  92. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/bo.toml +0 -0
  93. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/bs.toml +0 -0
  94. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ca.toml +0 -0
  95. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/cs.toml +0 -0
  96. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/da.toml +0 -0
  97. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/de.toml +0 -0
  98. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/el.toml +0 -0
  99. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/es.toml +0 -0
  100. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/et.toml +0 -0
  101. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/fa.toml +0 -0
  102. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ff.toml +0 -0
  103. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/fi.toml +0 -0
  104. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/fil.toml +0 -0
  105. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/fr.toml +0 -0
  106. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ga.toml +0 -0
  107. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/gd.toml +0 -0
  108. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/gu.toml +0 -0
  109. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ha.toml +0 -0
  110. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/he.toml +0 -0
  111. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/hi.toml +0 -0
  112. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/hr.toml +0 -0
  113. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/hu.toml +0 -0
  114. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/hy.toml +0 -0
  115. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/id.toml +0 -0
  116. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/is.toml +0 -0
  117. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/it.toml +0 -0
  118. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ja.toml +0 -0
  119. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ka.toml +0 -0
  120. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/kk.toml +0 -0
  121. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/km.toml +0 -0
  122. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/kn.toml +0 -0
  123. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ko.toml +0 -0
  124. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/kok.toml +0 -0
  125. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/lo.toml +0 -0
  126. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/lt.toml +0 -0
  127. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/lv.toml +0 -0
  128. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/mi.toml +0 -0
  129. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/mk.toml +0 -0
  130. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ml.toml +0 -0
  131. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/mn.toml +0 -0
  132. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/mr.toml +0 -0
  133. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ms.toml +0 -0
  134. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/mul.toml +0 -0
  135. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/my.toml +0 -0
  136. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/nb.toml +0 -0
  137. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ne.toml +0 -0
  138. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/nl.toml +0 -0
  139. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/nn.toml +0 -0
  140. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/or.toml +0 -0
  141. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/pa.toml +0 -0
  142. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/pl.toml +0 -0
  143. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/pt-BR.toml +0 -0
  144. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/pt.toml +0 -0
  145. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ro.toml +0 -0
  146. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ru.toml +0 -0
  147. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sd.toml +0 -0
  148. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/shn.toml +0 -0
  149. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/si.toml +0 -0
  150. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sk.toml +0 -0
  151. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sl.toml +0 -0
  152. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sr.toml +0 -0
  153. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sv.toml +0 -0
  154. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/sw.toml +0 -0
  155. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ta.toml +0 -0
  156. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/te.toml +0 -0
  157. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/th.toml +0 -0
  158. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ti.toml +0 -0
  159. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/tr.toml +0 -0
  160. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/uk.toml +0 -0
  161. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/und.toml +0 -0
  162. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/ur.toml +0 -0
  163. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/vi.toml +0 -0
  164. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/yi.toml +0 -0
  165. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/yo.toml +0 -0
  166. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/zh.toml +0 -0
  167. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser/vocab/zu.toml +0 -0
  168. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser.egg-info/dependency_links.txt +0 -0
  169. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser.egg-info/requires.txt +0 -0
  170. {nameparser-2.7.0 → nameparser-2.8.1}/nameparser.egg-info/top_level.txt +0 -0
  171. {nameparser-2.7.0 → nameparser-2.8.1}/setup.cfg +0 -0
  172. {nameparser-2.7.0 → nameparser-2.8.1}/tests/__init__.py +0 -0
  173. {nameparser-2.7.0 → nameparser-2.8.1}/tests/base.py +0 -0
  174. {nameparser-2.7.0 → nameparser-2.8.1}/tests/conftest.py +0 -0
  175. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_bound_given_names.py +0 -0
  176. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_brute_force.py +0 -0
  177. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_capitalization.py +0 -0
  178. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_comma_variants.py +0 -0
  179. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_conjunctions.py +0 -0
  180. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_east_slavic_patronymic_order.py +0 -0
  181. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_initials.py +0 -0
  182. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_middle_name_as_last.py +0 -0
  183. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_nicknames.py +0 -0
  184. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_output_format.py +0 -0
  185. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_particles.py +0 -0
  186. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_suffixes.py +0 -0
  187. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_titles.py +0 -0
  188. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_turkic_patronymic_order.py +0 -0
  189. {nameparser-2.7.0 → nameparser-2.8.1}/tests/test_variations.py +0 -0
  190. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/__init__.py +0 -0
  191. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/_differential_fixtures.py +0 -0
  192. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/conftest.py +0 -0
  193. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/design_docs.py +0 -0
  194. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/__init__.py +0 -0
  195. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_assemble.py +0 -0
  196. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_assign.py +0 -0
  197. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_classify.py +0 -0
  198. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_comma.py +0 -0
  199. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_extract.py +0 -0
  200. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_group.py +0 -0
  201. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_pieces.py +0 -0
  202. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_post_rules.py +0 -0
  203. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_script_segment.py +0 -0
  204. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_segment.py +0 -0
  205. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_state.py +0 -0
  206. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_tokenize.py +0 -0
  207. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/pipeline/test_vocab.py +0 -0
  208. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/rules_budget.py +0 -0
  209. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/rules_doc.py +0 -0
  210. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/rules_skeleton.py +0 -0
  211. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_benchmark.py +0 -0
  212. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_cldr_agreement.py +0 -0
  213. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_cldr_corpus.py +0 -0
  214. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_cli.py +0 -0
  215. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_corpora.py +0 -0
  216. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_corpus_build.py +0 -0
  217. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_design_docs.py +0 -0
  218. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_differential.py +0 -0
  219. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_doc_citations.py +0 -0
  220. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_doc_spellings.py +0 -0
  221. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_facade_cases.py +0 -0
  222. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_gnd_corpus.py +0 -0
  223. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_layering.py +0 -0
  224. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_local_jrc.py +0 -0
  225. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_locale.py +0 -0
  226. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_locales.py +0 -0
  227. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_order_correspondence.py +0 -0
  228. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_parser.py +0 -0
  229. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_policy.py +0 -0
  230. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_regex_sync.py +0 -0
  231. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_reprs.py +0 -0
  232. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_rules_budget.py +0 -0
  233. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_rules_doc.py +0 -0
  234. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_rules_doc_grammar.py +0 -0
  235. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_rules_skeleton.py +0 -0
  236. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_snapshot.py +0 -0
  237. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_types.py +0 -0
  238. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_vocab.py +0 -0
  239. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_wikidata_corpus.py +0 -0
  240. {nameparser-2.7.0 → nameparser-2.8.1}/tests/v2/test_wikidata_native_corpus.py +0 -0
  241. {nameparser-2.7.0 → nameparser-2.8.1}/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.7.0
3
+ Version: 2.8.1
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,27 +35,39 @@ 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.7 is out.** It is the first release working towards
39
- the new language and vocabulary model described in the `vocabulary
40
- model RFC <https://github.com/derek73/python-nameparser/blob/master/docs/design/vocabulary-model-rfc.md>`__.
41
- It introduces more nuanced handling of titles and particles
42
- (``Chief Justice John Roberts`` reads the title ``Chief Justice``,
43
- while ``Justice Smith`` keeps the given name ``Justice``), adjusts the
44
- default vocabulary to better align with example name corpora, and
45
- surfaces alternative name readings in the published API. The `release log
38
+ 📣 **nameparser 2.8 is out, the last 2.x feature release.**
39
+
40
+ ⚠️ **2.8.1 adds three more DeprecationWarnings** for things 3.0 changes:
41
+ configuring a ``Lexicon`` through its set fields
42
+ (``Lexicon.default().add(titles={"dean"})``), reading the vocabulary
43
+ constants in ``nameparser.config`` (``TITLES`` and the rest, all but
44
+ ``surnames``), and ``nameparser.config.regexes``. A test run that turns
45
+ warnings into errors (``-W error``, or pytest's ``filterwarnings =
46
+ error``) fails where your code does any of these; see the `migration
47
+ guide <https://nameparser.readthedocs.io/en/stable/migrate.html#deprecated-in-2-8-1>`__.
48
+
49
+ ⚠️ **HumanName is deprecated, and 3.0 removes it.** From 2.8 the 1.x
50
+ compatibility layer — ``HumanName``, ``Constants`` and the shared
51
+ ``CONSTANTS`` — emits a ``DeprecationWarning`` where your code
52
+ constructs it, loads it from a pickle, or changes the shared
53
+ ``CONSTANTS``. It keeps working through 2.x; ``parse()`` is the
54
+ replacement, and `Coming from 1.x`_ below says where to start. After
55
+ 2.8 the 2.x line takes fixes only, and new work goes into 3.0.
56
+
57
+ 2.8 also carries on 2.7's reading of titles that are also given names:
58
+ a title only inside a title phrase, so ``Queen Latifah`` keeps the
59
+ given name ``Queen`` while ``Her Majesty Queen Elizabeth`` reads the
60
+ title. The `release log
46
61
  <https://nameparser.readthedocs.io/en/latest/release_log.html>`__ has
47
- the details.
62
+ the details. Please `open an
63
+ issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
64
+ that parses wrong.
48
65
 
49
66
  Chinese, Japanese and Korean names written in their own scripts are read
50
67
  family-first, unspaced Korean names are split against the census surname
51
68
  list, and CJK honorifics are recognized. See `East Asian names
52
69
  <https://nameparser.readthedocs.io/en/latest/usage.html#east-asian-names>`__.
53
70
 
54
- Existing ``HumanName`` code from 1.x keeps working through 2.x, and most
55
- of it needs no changes; see `Coming from 1.x`_ below. Please `open an
56
- issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
57
- that parses wrong.
58
-
59
71
  Installation
60
72
  ------------
61
73
 
@@ -127,8 +139,10 @@ Learn more
127
139
  Coming from 1.x
128
140
  ----------------
129
141
 
130
- ``HumanName`` and ``CONSTANTS`` keep working in 2.0 — same imports, same
131
- attributes, same mutation API. What 2.0 removes is the batch of
142
+ ``HumanName`` and ``CONSTANTS`` keep working through 2.x — same imports,
143
+ same attributes, same mutation API — and warn from 2.8 on, since 3.0
144
+ removes them. Run your tests under ``python -W error::DeprecationWarning``
145
+ to find the sites; a read of ``CONSTANTS`` does not warn. What 2.0 removes is the batch of
132
146
  deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
133
147
  1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
134
148
  Two things that check will not catch: four removals 1.4 never warned
@@ -7,27 +7,39 @@ 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.7 is out.** It is the first release working towards
11
- the new language and vocabulary model described in the `vocabulary
12
- model RFC <https://github.com/derek73/python-nameparser/blob/master/docs/design/vocabulary-model-rfc.md>`__.
13
- It introduces more nuanced handling of titles and particles
14
- (``Chief Justice John Roberts`` reads the title ``Chief Justice``,
15
- while ``Justice Smith`` keeps the given name ``Justice``), adjusts the
16
- default vocabulary to better align with example name corpora, and
17
- surfaces alternative name readings in the published API. The `release log
10
+ 📣 **nameparser 2.8 is out, the last 2.x feature release.**
11
+
12
+ ⚠️ **2.8.1 adds three more DeprecationWarnings** for things 3.0 changes:
13
+ configuring a ``Lexicon`` through its set fields
14
+ (``Lexicon.default().add(titles={"dean"})``), reading the vocabulary
15
+ constants in ``nameparser.config`` (``TITLES`` and the rest, all but
16
+ ``surnames``), and ``nameparser.config.regexes``. A test run that turns
17
+ warnings into errors (``-W error``, or pytest's ``filterwarnings =
18
+ error``) fails where your code does any of these; see the `migration
19
+ guide <https://nameparser.readthedocs.io/en/stable/migrate.html#deprecated-in-2-8-1>`__.
20
+
21
+ ⚠️ **HumanName is deprecated, and 3.0 removes it.** From 2.8 the 1.x
22
+ compatibility layer — ``HumanName``, ``Constants`` and the shared
23
+ ``CONSTANTS`` — emits a ``DeprecationWarning`` where your code
24
+ constructs it, loads it from a pickle, or changes the shared
25
+ ``CONSTANTS``. It keeps working through 2.x; ``parse()`` is the
26
+ replacement, and `Coming from 1.x`_ below says where to start. After
27
+ 2.8 the 2.x line takes fixes only, and new work goes into 3.0.
28
+
29
+ 2.8 also carries on 2.7's reading of titles that are also given names:
30
+ a title only inside a title phrase, so ``Queen Latifah`` keeps the
31
+ given name ``Queen`` while ``Her Majesty Queen Elizabeth`` reads the
32
+ title. The `release log
18
33
  <https://nameparser.readthedocs.io/en/latest/release_log.html>`__ has
19
- the details.
34
+ the details. Please `open an
35
+ issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
36
+ that parses wrong.
20
37
 
21
38
  Chinese, Japanese and Korean names written in their own scripts are read
22
39
  family-first, unspaced Korean names are split against the census surname
23
40
  list, and CJK honorifics are recognized. See `East Asian names
24
41
  <https://nameparser.readthedocs.io/en/latest/usage.html#east-asian-names>`__.
25
42
 
26
- Existing ``HumanName`` code from 1.x keeps working through 2.x, and most
27
- of it needs no changes; see `Coming from 1.x`_ below. Please `open an
28
- issue <https://github.com/derek73/python-nameparser/issues>`__ for anything
29
- that parses wrong.
30
-
31
43
  Installation
32
44
  ------------
33
45
 
@@ -99,8 +111,10 @@ Learn more
99
111
  Coming from 1.x
100
112
  ----------------
101
113
 
102
- ``HumanName`` and ``CONSTANTS`` keep working in 2.0 — same imports, same
103
- attributes, same mutation API. What 2.0 removes is the batch of
114
+ ``HumanName`` and ``CONSTANTS`` keep working through 2.x — same imports,
115
+ same attributes, same mutation API — and warn from 2.8 on, since 3.0
116
+ removes them. Run your tests under ``python -W error::DeprecationWarning``
117
+ to find the sites; a read of ``CONSTANTS`` does not warn. What 2.0 removes is the batch of
104
118
  deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
105
119
  1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
106
120
  Two things that check will not catch: four removals 1.4 never warned
@@ -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.
@@ -529,8 +533,8 @@ class _RegexesProxy:
529
533
  def _regexes() -> Mapping[str, object]:
530
534
  # deferred import: see the module docstring's note on why every
531
535
  # nameparser.config.<data module> import in this file is lazy
532
- from nameparser.config.regexes import REGEXES
533
- return REGEXES
536
+ from nameparser.config.regexes import _REGEXES
537
+ return _REGEXES
534
538
 
535
539
  #: dict methods this read-only proxy deliberately does not carry.
536
540
  #: Without this, __getattr__ reports them as missing regexes and
@@ -712,27 +716,80 @@ _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; build a Lexicon/Policy (or a private Constants "
718
- "passed as HumanName(constants=...)) instead. See the migration "
719
- "guide."
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]]:
724
- # v1 data modules stay the single vocabulary source through 2.x
780
+ # the compiled vocabulary, read from _compiled: the public modules'
781
+ # constants warn at a caller's read since 2.8.1 (#1007)
725
782
  # (same rule as Lexicon.default()).
726
- from nameparser.config.bound_given_names import BOUND_GIVEN_NAMES
727
- from nameparser.config.conjunctions import CONJUNCTIONS
728
- from nameparser.config.particles import (
783
+ from nameparser.config._compiled import BOUND_GIVEN_NAMES
784
+ from nameparser.config._compiled import CONJUNCTIONS
785
+ from nameparser.config._compiled import (
729
786
  NON_GIVEN_NAME_PARTICLES, PARTICLES,
730
787
  )
731
- from nameparser.config.suffixes import (
788
+ from nameparser.config._compiled import (
732
789
  SUFFIX_ACRONYMS, SUFFIX_ACRONYMS_AMBIGUOUS, SUFFIX_WORDS,
733
790
  )
734
791
  from nameparser.config._titles_2_6_0 import TITLES_2_6_0
735
- from nameparser.config.titles import (
792
+ from nameparser.config._compiled import (
736
793
  GIVEN_NAME_TITLES, TITLES, TITLES_AMBIGUOUS)
737
794
  return {
738
795
  "prefixes": PARTICLES,
@@ -786,9 +843,11 @@ class Constants:
786
843
 
787
844
  The module-level ``CONSTANTS`` singleton (below) has ``_shared``
788
845
  flipped to ``True``: any mutation reached through it emits
789
- ``DeprecationWarning`` pointing at ``Lexicon``/``Policy`` and
790
- ``HumanName(constants=...)``. A private ``Constants()`` never
791
- warns -- only the shared instance is on the 3.0 removal path.
846
+ ``DeprecationWarning`` pointing at ``Lexicon``/``Policy``. Since 2.8
847
+ constructing a ``Constants``, copying one with ``copy()`` and
848
+ loading one from a pickle warn too, since the whole class goes in
849
+ 3.0; the singleton is built without the warning, so importing
850
+ ``nameparser`` stays quiet.
792
851
  """
793
852
 
794
853
  _shared = False # the CONSTANTS singleton flips this to True
@@ -836,6 +895,41 @@ class Constants:
836
895
  regexes: object = _UNSET_KWARG,
837
896
  patronymic_name_order: bool = False,
838
897
  middle_name_as_last: bool = False,
898
+ ) -> None:
899
+ # every construction warns, at the caller's line; the warnings
900
+ # registry, not a flag here, dedups repeats from one line
901
+ # (decisions/3-0-reevaluations, 2026-10-28)
902
+ warnings.warn(CONSTANTS_DEPRECATION, DeprecationWarning,
903
+ stacklevel=2)
904
+ self._init(
905
+ prefixes=prefixes, suffix_acronyms=suffix_acronyms,
906
+ suffix_not_acronyms=suffix_not_acronyms,
907
+ suffix_acronyms_ambiguous=suffix_acronyms_ambiguous,
908
+ titles=titles, first_name_titles=first_name_titles,
909
+ conjunctions=conjunctions, bound_first_names=bound_first_names,
910
+ non_first_name_prefixes=non_first_name_prefixes,
911
+ capitalization_exceptions=capitalization_exceptions,
912
+ regexes=regexes, patronymic_name_order=patronymic_name_order,
913
+ middle_name_as_last=middle_name_as_last)
914
+
915
+ def _init(
916
+ self,
917
+ *,
918
+ prefixes: Iterable[str] | object = _UNSET_KWARG,
919
+ suffix_acronyms: Iterable[str] | object = _UNSET_KWARG,
920
+ suffix_not_acronyms: Iterable[str] | object = _UNSET_KWARG,
921
+ suffix_acronyms_ambiguous: Iterable[str] | object = _UNSET_KWARG,
922
+ titles: Iterable[str] | object = _UNSET_KWARG,
923
+ first_name_titles: Iterable[str] | object = _UNSET_KWARG,
924
+ conjunctions: Iterable[str] | object = _UNSET_KWARG,
925
+ bound_first_names: Iterable[str] | object = _UNSET_KWARG,
926
+ non_first_name_prefixes: Iterable[str] | object = _UNSET_KWARG,
927
+ capitalization_exceptions:
928
+ Mapping[str, str] | Iterable[tuple[str, str]] | object
929
+ = _UNSET_KWARG,
930
+ regexes: object = _UNSET_KWARG,
931
+ patronymic_name_order: bool = False,
932
+ middle_name_as_last: bool = False,
839
933
  ) -> None:
840
934
  # v1.4 parity constructor kwargs (#238/#242/#244 hardening); the
841
935
  # signature is spelled out rather than **kwargs so an unknown
@@ -878,7 +972,7 @@ class Constants:
878
972
  self, name,
879
973
  SetManager(value, _on_change=self._bump, _field=name)) # type: ignore[arg-type]
880
974
  if capitalization_exceptions is _UNSET_KWARG:
881
- from nameparser.config.capitalization import (
975
+ from nameparser.config._compiled import (
882
976
  CAPITALIZATION_EXCEPTIONS,
883
977
  )
884
978
  capitalization_exceptions = CAPITALIZATION_EXCEPTIONS
@@ -921,19 +1015,20 @@ class Constants:
921
1015
  """
922
1016
 
923
1017
  def _bump(self) -> None:
924
- # stacklevel=3 is exact for the direct scalar-assignment path
925
- # (user code -> Constants.__setattr__ -> here) and lands one
926
- # frame short -- inside the manager's own add()/remove()/
927
- # __setitem__ -- for the indirect manager-mutation path (user
928
- # code -> manager method -> _changed() -> here), since a
929
- # single warn() call can't be exact for both call depths at
930
- # once. Either way the warning still fires from this module,
931
- # not the manager's true caller, which is enough: only the
932
- # DeprecationWarning's presence/category/message are load-
933
- # bearing (see the specified test), not the reported line.
1018
+ # A fixed stacklevel lands on the caller only for one call depth:
1019
+ # a scalar arrives through __setattr__, a set's add() through
1020
+ # _changed(), a dict's update() and |= through __setitem__ per
1021
+ # key. Walk out of this module instead, as _lexicon's
1022
+ # _warn_dead_entry does, so the warning names the caller's line;
1023
+ # attributed here, Python's default filters hid it.
934
1024
  if self._shared:
1025
+ level = 2
1026
+ frame: FrameType | None = sys._getframe(1)
1027
+ while (frame is not None
1028
+ and frame.f_globals.get("__name__") == __name__):
1029
+ frame, level = frame.f_back, level + 1
935
1030
  warnings.warn(_SHARED_MUTATION_MESSAGE, DeprecationWarning,
936
- stacklevel=3)
1031
+ stacklevel=level)
937
1032
  object.__setattr__(self, "_generation", self._generation + 1)
938
1033
 
939
1034
  def __setattr__(self, name: str, value: object) -> None:
@@ -987,7 +1082,27 @@ class Constants:
987
1082
  v1 (which deepcopied __dict__): attributes OUTSIDE the known
988
1083
  field surface -- e.g. ad-hoc names stashed on the instance --
989
1084
  are not carried by copy() or pickling; only the enumerated
990
- fields survive.""" # #260
1085
+ fields survive. Warns since 2.8, as construction does: a copy
1086
+ is a new private ``Constants``, and ``CONSTANTS.copy()`` builds
1087
+ one without calling the constructor.""" # #260
1088
+ warnings.warn(CONSTANTS_DEPRECATION, DeprecationWarning,
1089
+ stacklevel=2)
1090
+ return self._copy()
1091
+
1092
+ def __copy__(self) -> Constants:
1093
+ new = object.__new__(type(self))
1094
+ _quiet_setstate(new, self.__getstate__(), Constants,
1095
+ CONSTANTS_PICKLE_DEPRECATION)
1096
+ return new
1097
+
1098
+ def __deepcopy__(self, memo: dict[int, object]) -> Constants:
1099
+ new = object.__new__(type(self))
1100
+ memo[id(self)] = new
1101
+ _quiet_setstate(new, copy.deepcopy(self.__getstate__(), memo),
1102
+ Constants, CONSTANTS_PICKLE_DEPRECATION)
1103
+ return new
1104
+
1105
+ def _copy(self) -> Constants:
991
1106
  # An independent instance with its own generation counter and
992
1107
  # its own manager callbacks -- not a shared-state alias like a
993
1108
  # naive attribute-for-attribute copy would produce. v1's copy()
@@ -1050,14 +1165,14 @@ class Constants:
1050
1165
  singleton -- only direct attribute mutation is on the 3.0
1051
1166
  removal path.
1052
1167
  """
1053
- from nameparser.config.conjunctions import CONJUNCTIONS_AMBIGUOUS
1054
- from nameparser.config.given_names import GIVEN_NAME_ABBREVIATIONS
1055
- from nameparser.config.maiden_markers import MAIDEN_MARKERS
1056
- from nameparser.config.suffixes import (
1168
+ from nameparser.config._compiled import CONJUNCTIONS_AMBIGUOUS
1169
+ from nameparser.config._compiled import GIVEN_NAME_ABBREVIATIONS
1170
+ from nameparser.config._compiled import MAIDEN_MARKERS
1171
+ from nameparser.config._compiled import (
1057
1172
  AGNOMENS, GLUED_HONORIFICS, SUFFIX_WORDS_AMBIGUOUS)
1058
1173
  from nameparser.config.surnames import KOREAN_SURNAMES
1059
1174
  from nameparser.config._titles_2_6_0 import TITLES_2_6_0
1060
- from nameparser.config.titles import (
1175
+ from nameparser.config._compiled import (
1061
1176
  AFTER_GIVEN_TITLES, TITLE_MODIFIERS, TITLE_PHRASES, TITLE_STYLES,
1062
1177
  TITLES_AMBIGUOUS)
1063
1178
  # Every set field and every capitalization_exceptions key passes
@@ -1376,7 +1491,22 @@ class Constants:
1376
1491
  # DROPPED (#255: empty is always '' in 2.0).
1377
1492
  state = {k: v for k, v in state.items()
1378
1493
  if k != "empty_attribute_default"}
1379
- self.__init__() # type: ignore[misc] # defaults, then overlay
1494
+ warnings.warn(CONSTANTS_PICKLE_DEPRECATION, DeprecationWarning,
1495
+ stacklevel=2)
1496
+ self._restore(state)
1497
+
1498
+ def _restore(self, state: dict[str, object]) -> None:
1499
+ # defaults, then overlay. A subclass's own __init__ runs here as
1500
+ # it did before 2.8; its super().__init__() would warn that a
1501
+ # Constants was constructed, which a restore is not
1502
+ if type(self).__init__ is Constants.__init__:
1503
+ self._init()
1504
+ else:
1505
+ with warnings.catch_warnings():
1506
+ warnings.filterwarnings(
1507
+ "ignore", message=re.escape(CONSTANTS_DEPRECATION),
1508
+ category=DeprecationWarning)
1509
+ self.__init__() # type: ignore[misc]
1380
1510
  # (managers re-wrapped below so _on_change points at THIS
1381
1511
  # instance, not whatever produced the incoming state)
1382
1512
  managers: dict[str, SetManager] = {}
@@ -1417,5 +1547,7 @@ class Constants:
1417
1547
  object.__setattr__(self, name, state[name])
1418
1548
 
1419
1549
 
1420
- CONSTANTS = Constants()
1550
+ # built past __init__, so importing nameparser never warns
1551
+ CONSTANTS = object.__new__(Constants)
1552
+ CONSTANTS._init()
1421
1553
  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, _cached_parser
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). Deleted with the facade layer in 3.0.
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. See "
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