Skip to content

Commit 6dc5261

Browse files
authored
Merge pull request #288 from derek73/v2/core-foundation
nameparser 2.0 implementation
2 parents 7c4f9ac + ac59a5f commit 6dc5261

112 files changed

Lines changed: 17493 additions & 4923 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/python-package.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,22 @@ jobs:
2020
strategy:
2121
fail-fast: false
2222
matrix:
23-
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
23+
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
24+
# 3.15 is pre-release until 2026-10-01 (#259): surface breakage
25+
# without blocking the branch; flip to blocking when it goes final.
26+
continue-on-error: ${{ matrix.python-version == '3.15' }}
27+
env:
28+
# Without this, uv sync honors .python-version (3.11) over the
29+
# matrix interpreter and every job silently tests 3.11.
30+
UV_PYTHON: ${{ matrix.python-version }}
2431

2532
steps:
2633
- uses: actions/checkout@v7
2734
- name: Set up Python ${{ matrix.python-version }}
2835
uses: actions/setup-python@v6
2936
with:
3037
python-version: ${{ matrix.python-version }}
38+
allow-prereleases: true
3139
- name: Install uv
3240
uses: astral-sh/setup-uv@v6
3341
with:

.python-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
3.10
1+
3.11

AGENTS.md

Lines changed: 38 additions & 2 deletions
Large diffs are not rendered by default.

README.rst

Lines changed: 56 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -3,166 +3,73 @@ Name Parser
33

44
|Build Status| |PyPI| |PyPI version| |Documentation| |License| |Downloads| |Codecov|
55

6-
📣 **A nameparser 2.0 release candidate is available for testing** — a new
7-
immutable core API, with full compatibility for existing code through 2.x.
8-
Install it with ``pip install --pre nameparser`` (a plain install still gets
9-
1.x), read the `2.0 docs
10-
<https://nameparser.readthedocs.io/en/v2-core-foundation/>`__, and share
11-
feedback on `the discussion issue
6+
nameparser parses human names into seven fields — title, given, middle,
7+
family, suffix, nickname, maiden. Results are immutable, configuration is
8+
composable, and locale packs are opt-in.
9+
10+
📣 **nameparser 2.0 is out.** Existing ``HumanName`` code keeps working
11+
through 2.x — most 1.x code needs no changes. The `migration guide
12+
<https://nameparser.readthedocs.io/en/latest/migrate.html>`__ has the
13+
field-by-field map, and anything the migration missed can be reported
14+
on `the discussion issue
1215
<https://github.com/derek73/python-nameparser/issues/284>`__.
1316

14-
A simple Python (3.10+) module for parsing human names into their
15-
individual components.
16-
17-
* hn.title
18-
* hn.first
19-
* hn.middle
20-
* hn.last
21-
* hn.suffix
22-
* hn.nickname
23-
* hn.maiden
24-
* hn.surnames *(middle + last)*
25-
* hn.given_names *(first + middle)*
26-
* hn.initials *(first initial of each name part)*
27-
* hn.last_base *(last, minus any prefixes)*
28-
* hn.last_prefixes *(leading last-name particles, e.g. "van der")*
29-
30-
Supported Name Structures
31-
~~~~~~~~~~~~~~~~~~~~~~~~~
32-
33-
The supported name structure is generally "Title First Middle Last Suffix", where all pieces
34-
are optional. Comma-separated format like "Last, First" is also supported.
35-
36-
1. Title Firstname "Nickname" Middle Middle Lastname Suffix
37-
2. Lastname [Suffix], Title Firstname (Nickname) Middle Middle[,] Suffix [, Suffix]
38-
3. Title Firstname M Lastname [Suffix], Suffix [Suffix] [, Suffix]
39-
40-
How It Works
41-
~~~~~~~~~~~~
42-
43-
The parser works in two layers.
44-
45-
A **vocabulary layer** recognizes name pieces by what they are, using
46-
configurable sets of known words: titles ("Dr."), suffixes ("III", "PhD"),
47-
last-name prefixes ("de la"), conjunctions ("y", "&"), and delimited
48-
nicknames ("Doc"). Titles and conjunctions chain together to handle complex
49-
titles like "Asst Secretary of State"; prefixes join forward so "de la Vega"
50-
stays one last name. This layer doesn't care where in the string a word
51-
appears — and it's the layer you customize, by adding or removing entries
52-
in the sets to fit your dataset.
53-
54-
A **positional layer** then assigns everything the vocabulary layer didn't
55-
claim, based purely on where it sits: the first unclaimed word is the first
56-
name, the last one is the last name, and anything between them is a middle
57-
name. There is no semantic understanding — "Dr" is a title when it comes
58-
before a name and a suffix when it comes after ("pre-nominal" and
59-
"post-nominal" would probably be better names) — and no attempt to correct
60-
mistakes in the input.
61-
62-
It attempts the best guess that can be made with a simple, deterministic,
63-
rule-based approach — no statistical models or machine learning; the same
64-
input always parses the same way. The positional layer assumes Western name
65-
order (given name first), so the main use case is English and other
66-
languages that share that structure. It can also try to correct the
67-
capitalization of names that are all upper- or lowercase. It's not perfect,
68-
but it gets you pretty far.
69-
7017
Installation
7118
------------
7219

7320
::
7421

7522
pip install nameparser
7623

77-
If you want to try out the latest code from GitHub you can
78-
install with pip using the command below.
79-
80-
``pip install -e git+https://github.com/derek73/python-nameparser.git``
81-
82-
If you need to handle lists of names, check out
83-
`namesparser <https://github.com/gwu-libraries/namesparser>`_, a
84-
compliment to this module that handles multiple names in a string.
85-
24+
Requires Python 3.11+.
8625

8726
Quick Start Example
88-
-------------------
89-
90-
::
91-
92-
>>> from nameparser import HumanName
93-
>>> name = HumanName("Dr. Juan Q. Xavier de la Vega III (Doc Vega)")
94-
>>> name
95-
<HumanName : [
96-
title: 'Dr.'
97-
first: 'Juan'
98-
middle: 'Q. Xavier'
99-
last: 'de la Vega'
100-
suffix: 'III'
101-
nickname: 'Doc Vega'
102-
maiden: ''
103-
]>
104-
>>> name.last
105-
'de la Vega'
106-
>>> name.as_dict()
107-
{'title': 'Dr.', 'first': 'Juan', 'middle': 'Q. Xavier', 'last': 'de la Vega', 'suffix': 'III', 'nickname': 'Doc Vega', 'maiden': ''}
108-
>>> str(name)
109-
'Dr. Juan Q. Xavier de la Vega III (Doc Vega)'
110-
>>> name.string_format = "{first} {last}"
111-
>>> str(name)
112-
'Juan de la Vega'
113-
114-
115-
Because the positional layer has no semantic understanding, position is
116-
everything:
117-
118-
::
119-
120-
>>> name = HumanName("1 & 2, 3 4 5, Mr.")
121-
>>> name
122-
<HumanName : [
123-
title: ''
124-
first: '3'
125-
middle: '4 5'
126-
last: '1 & 2'
127-
suffix: 'Mr.'
128-
nickname: ''
129-
maiden: ''
130-
]>
131-
132-
Customization
133-
-------------
134-
135-
Your project may need some adjustment for your dataset. Most customization
136-
is vocabulary — `customizing the configured pre-defined sets`_ of titles,
137-
prefixes, etc. that the vocabulary layer matches against. You can also do
138-
your own pre- or post-processing, or subclass the `HumanName` class for
139-
deeper changes. See the `full documentation`_ for more information.
140-
141-
142-
`Full documentation`_
143-
~~~~~~~~~~~~~~~~~~~~~
144-
145-
.. _customizing the configured pre-defined sets: http://nameparser.readthedocs.org/en/latest/customize.html
146-
.. _Full documentation: http://nameparser.readthedocs.org/en/latest/
147-
148-
149-
Contributing
150-
------------
151-
152-
If you come across name piece that you think should be in the default config, you're
153-
probably right. `Start a New Issue`_ and we can get them added.
154-
155-
Please let me know if there are ways this library could be structured to make
156-
it easier for you to use in your projects. Read CONTRIBUTING.md_ for more info
157-
on running the tests and contributing to the project.
158-
159-
**GitHub Project**
160-
161-
https://github.com/derek73/python-nameparser
162-
163-
.. _CONTRIBUTING.md: https://github.com/derek73/python-nameparser/tree/master/CONTRIBUTING.md
164-
.. _Start a New Issue: https://github.com/derek73/python-nameparser/issues
165-
.. _click here to propose changes to the titles: https://github.com/derek73/python-nameparser/edit/master/nameparser/config/titles.py
27+
--------------------
28+
29+
.. code-block:: python
30+
31+
>>> from nameparser import parse
32+
>>> name = parse("Dr. Juan Q. Xavier de la Vega III")
33+
>>> name.given, name.family
34+
('Juan', 'de la Vega')
35+
>>> name.render("{family}, {given}")
36+
'de la Vega, Juan'
37+
38+
Those seven fields are ``title``, ``given``, ``middle``, ``family``,
39+
``suffix``, ``nickname``, and ``maiden`` — plus aggregate views like
40+
``given_names``, ``surnames``, ``family_base``, and ``family_particles``
41+
for combining or splitting them further.
42+
43+
Learn more
44+
----------
45+
46+
* `Using the parser <https://nameparser.readthedocs.io/en/latest/usage.html>`__ — the full tour: input shapes, aggregates, rendering, comparison, ambiguities, tokens
47+
* `Customizing the parser <https://nameparser.readthedocs.io/en/latest/customize.html>`__ — vocabulary, behavior, and presentation
48+
* `Locale packs <https://nameparser.readthedocs.io/en/latest/locales.html>`__ — opt-in bundles for East Slavic patronymics, Turkic markers, and more
49+
* There's also a CLI: ``python -m nameparser --json "Doe, John"``
50+
51+
Coming from 1.x
52+
----------------
53+
54+
``HumanName`` and ``CONSTANTS`` keep working in 2.0 — same imports, same
55+
attributes, same mutation API. What 2.0 removes is the batch of
56+
deprecations 1.3 and 1.4 announced, so if your test suite runs clean on
57+
1.4 under ``python -W error::DeprecationWarning``, you are nearly done.
58+
Two things that check will not catch: four removals 1.4 never warned
59+
about (three raise on contact, the fourth only warns), and one that
60+
changes results silently — ``name == "John Smith"`` is now ``False``.
61+
`Migrating from HumanName <https://nameparser.readthedocs.io/en/latest/migrate.html>`__
62+
covers both, and translates a v1 customization into the new API whenever
63+
that's convenient for you.
64+
65+
See the `release log <https://nameparser.readthedocs.io/en/latest/release_log.html>`__
66+
for the full list of changes in the 2.0 series.
67+
68+
License
69+
-------
70+
71+
LGPL licensed. See `LICENSE <https://github.com/derek73/python-nameparser/blob/master/LICENSE>`__
72+
for details.
16673

16774
.. |Build Status| image:: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml/badge.svg
16875
:target: https://github.com/derek73/python-nameparser/actions/workflows/python-package.yml

0 commit comments

Comments
 (0)