Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

## Standing

- The rule says what the escape does: quotes escape as brackets do, and a clause of two or more words is not suffix-shaped unless an ASCII period ends it, so `(PhD MBA)` keeps its nickname reading with nothing reported, as 1.4.0 read it — 2026-10-21 #807.
- The rule says what the escape does: quotes escape as brackets do, and a clause of two or more words is not suffix-shaped unless an ASCII period ends it, so `(PhD MSc)` keeps its nickname reading with nothing reported, as 1.4.0 read `(PhD MBA)`, which reports suffix-or-nickname since `mba` was marked ambiguous (decisions/suffix-acronym-collisions, 2026-11-03) — 2026-10-21 #807.

Elsewhere: an ambiguous member alone in the brackets staying a nickname, reported, is decided under decisions/suffix-acronym-collisions (its Standing line ending 2026-09-25 #540; 2026-10-21) and decisions/ma-do's 2026-07-17 entry; a member after the name whose writing settles it reading as the suffix is decisions/S13 (2026-10-26 #810).

## Log

- 2026-10-21 (Derek), #807 — S1 IS NARROWED TO WHAT THE ESCAPE DOES, NOT WIDENED TO WHAT ITS THEN HAD SAID. The rule's Then said suffix-shaped bracketed content reads as if written bare, and #807's review measured two places the parser had never done so: a clause of two or more words is never suffix-shaped unless it ends in a period (`John Smith (PhD MBA)` → nickname 'PhD MBA', nothing reported; `(MBA PhD.)` → suffix), the escape asking its question of the whole clause; and every default nickname pair escapes alike, quotes included (`John Smith "MBA"` → suffix, `"MA"` → nickname, reported). Derek: narrow the rule for both rather than change the parser. 1.4.0 reads `(PhD MBA)` as nickname 'PhD MBA' and the ASCII-quoted `"MBA"` and `'MBA'` as suffix 'MBA' (measured 2026-10-21, the wheel run from a scratch dir), so neither is a 2.x move; the typographic and CJK pairs (`«MBA»`, `“MBA”`, `「MBA」`, `(MBA)`) were no delimiters in 1.4.0, which read each as a family name, and escape alike since 2.x added them. The third gap the review found, `John Smith (M.A)` → nickname where bare `John Smith M.A` → suffix (1.4.0: suffix in both), was left to an issue rather than narrowed. Limits the review measured and the rule now states or leaves: the period is tested on the raw clause, so `(PhD MBA. )` stays a nickname, and an ideographic full stop does not count (`(PhD MBA。)`), as decisions/cjk-full-stops records for one word; under a caller-declared maiden pair the same clauses read as maiden names, the report being a nickname's alone.
- 2026-10-21 (Derek), #807 (its `(PhD MBA)` reporting nothing superseded by decisions/suffix-acronym-collisions' 2026-11-03 entry: `mba` is marked ambiguous, so the run reports suffix-or-nickname, as `(MA PhD)` does) — S1 IS NARROWED TO WHAT THE ESCAPE DOES, NOT WIDENED TO WHAT ITS THEN HAD SAID. The rule's Then said suffix-shaped bracketed content reads as if written bare, and #807's review measured two places the parser had never done so: a clause of two or more words is never suffix-shaped unless it ends in a period (`John Smith (PhD MBA)` → nickname 'PhD MBA', nothing reported; `(MBA PhD.)` → suffix), the escape asking its question of the whole clause; and every default nickname pair escapes alike, quotes included (`John Smith "MBA"` → suffix, `"MA"` → nickname, reported). Derek: narrow the rule for both rather than change the parser. 1.4.0 reads `(PhD MBA)` as nickname 'PhD MBA' and the ASCII-quoted `"MBA"` and `'MBA'` as suffix 'MBA' (measured 2026-10-21, the wheel run from a scratch dir), so neither is a 2.x move; the typographic and CJK pairs (`«MBA»`, `“MBA”`, `「MBA」`, `(MBA)`) were no delimiters in 1.4.0, which read each as a family name, and escape alike since 2.x added them. The third gap the review found, `John Smith (M.A)` → nickname where bare `John Smith M.A` → suffix (1.4.0: suffix in both), was left to an issue rather than narrowed. Limits the review measured and the rule now states or leaves: the period is tested on the raw clause, so `(PhD MBA. )` stays a nickname, and an ideographic full stop does not count (`(PhD MBA。)`), as decisions/cjk-full-stops records for one word; under a caller-declared maiden pair the same clauses read as maiden names, the report being a nickname's alone.
6 changes: 4 additions & 2 deletions docs/design/decisions/suffix-acronym-collisions.md

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions docs/design/decisions/vocabulary-model.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/design/rules/M1-delimited-maiden-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@

**Precedence:**

- **Suffix-shaped content** ("Andrew Perkins (MBA)"): S1 takes it first, and the clause is no maiden name.
- **Suffix-shaped content** ("Andrew Perkins (PhD)"): S1 takes it first, and the clause is no maiden name.
```
"Andrew Perkins (MBA)" maiden-parens → suffix="MBA" · boundary
"Andrew Perkins (PhD)" maiden-parens → suffix="PhD" · boundary
```
- **A pair configured for both maiden and nickname names** reads maiden: this rule wins over N1.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@

- **A clause of two or more words** is not suffix-shaped, whatever it holds, unless an ASCII period stands last before its closer: suffix-shaped is asked of the whole clause, so a run of credentials keeps its brackets or quotes and reads as its pair reads it, a nickname in a nickname pair.
```
"John Smith (PhD MBA)" → nickname="PhD MBA"
"John Smith (PhD MBA)" → ambiguities=()
"John Smith (PhD MSc)" → nickname="PhD MSc"
"John Smith (PhD MSc)" → ambiguities=()
"John Smith (MA PhD)" → ambiguities=("suffix-or-nickname",)
"John Smith (MBA PhD.)" → suffix="MBA PhD." · boundary
```
Expand Down
4 changes: 2 additions & 2 deletions docs/design/vocabulary-model-rfc.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ Status: **the definition decided 2026-10-30 and measured on 2026-10-31; the API

Two consequences were accepted with the definition:

- **`mul.toml` stays as it is, and under file-strict it is one more language's file** (superseded 2026-11-02, #1005: every strict choice reads `mul.toml`, which takes a word that harms no language and would otherwise be duplicated into every language's file, and the degrees `phd`, `msc`, `mba`, `mph`, `bsc` and the salutations `mr`, `mrs` moved there from en.toml; `md`, a leading `Md` abbreviating Muhammad, `ms`, written as South Indian initials, and `mx`, the abbreviation for Mexico, stayed). Its entries each name several languages (`doctor` four, `docent` six, `professor` English, German, Dutch, Portuguese and the Scandinavian languages), or "the European languages" (`dr`, `prof`), or carry no note (the numerals `2` and `i` to `v`, `&`), and `ing`, the Czech and Slovak engineering degree, sits there too.
- **`mul.toml` stays as it is, and under file-strict it is one more language's file** (superseded 2026-11-02, #1005: every strict choice reads `mul.toml`, which takes a word that harms no language and would otherwise be duplicated into every language's file, and the degrees `phd`, `msc`, `mba`, `mph`, `bsc` and the salutations `mr`, `mrs` moved there from en.toml; `md`, a leading `Md` abbreviating Muhammad, `ms`, written as South Indian initials, and `mx`, the abbreviation for Mexico, stayed; `ms` and `miss` moved there whole on 2026-11-03, decisions/vocabulary-model). Its entries each name several languages (`doctor` four, `docent` six, `professor` English, German, Dutch, Portuguese and the Scandinavian languages), or "the European languages" (`dr`, `prof`), or carry no note (the numerals `2` and `i` to `v`, `&`), and `ing`, the Czech and Slovak engineering degree, sits there too.
- **Strict `vi` drops English credentials, accepted in principle** (since #1005 only en.toml's, `MD` among them: `PhD` is mul.toml's, which strict reads). Vietnamese writes its degrees in Vietnamese and before the name (`TS.`, `ThS.`, `GS.`, `PGS.`, `BS.`, stacked as `PGS.TS.`) and has no generational suffix, so English credentials come with English-context writing, where the caller chooses `en` too (since #1005, en.toml's: `Minh Do, RN, MD` reads given `RN`). What this costs is measured below, not assumed.

**What it does, measured** (2026-10-31 on master `b577e9a8`, Python 3.11, the cached local corpora only). The simulation compiles a strict choice through the shipped compiler, `_reading_index.choose` and `compile_readings` over the index rows of the chosen tags and the native-script rows, and applies it to the default lexicon as a choice's delta is applied; a pack's policy patch and fragment apply as `parser_for` applies them. Each ORCID country's capped 20,000 records (12,962 for SK, 17,541 for NP) are scored box by box with `local_agreement.read`, leaving out the records whose given box opens with a title word (`Dr`, `Prof`, `Mr` and their kin; 1,717 for IN, 437 for NP, under 70 elsewhere), since ORCID has no title box and a holder who typed `Dr` into the given box scores a fix whenever `dr` leaves the vocabulary. "choice" is the shipped pack where one carries the language, else a bare choice of the tag; "strict + en" adds en.toml to the strict choice. Fixed and broken are against the default. Re-run on the built code (3j, `parser_for(pack, strict=True)` in place of the simulation) on 2026-10-31, every cell of the table matched.
Expand Down Expand Up @@ -273,7 +273,7 @@ How to read it:
| `pt`, `pt-BR` | `junior`, `jr` en; `del`, `dal`, `di`, `della` es and it; `v`, `i` mul |
| `ne`, `hi` | `dr`, `prof`, `v` mul; `phd`, `md` en; `kc`, `das` (Nepali and Indian surnames: a gain) |

Nine of the ten rows lose a bare `dr` and three `prof` (`Dr.` stays a title by its period; the pt rows' records write neither often enough to rank), and every English-context population the salutations, so a strict choice made for real data is in practice strict of the language and `en`, or needs those words in its own file; this was the mul.toml Open above, which #1005 settled by reading `mul.toml` under strict and moving five degrees and `mr` and `mrs` there (the `dr`, `prof`, `v` and `phd` cells are gone since, `md` staying in en.toml; the rest of each row stands).
Nine of the ten rows lose a bare `dr` and three `prof` (`Dr.` stays a title by its period; the pt rows' records write neither often enough to rank), and every English-context population the salutations, so a strict choice made for real data is in practice strict of the language and `en`, or needs those words in its own file; this was the mul.toml Open above, which #1005 settled by reading `mul.toml` under strict and moving five degrees and `mr` and `mrs` there (the `dr`, `prof`, `v` and `phd` cells are gone since, `md` staying in en.toml), and the 2026-11-03 audit moving `ms` and `miss` (decisions/vocabulary-model; the salutation cells are gone since; the rest of each row stands).

**Files that hold no readings.** hu.toml, kk.toml, kok.toml, vi.toml and zu.toml hold only exclusions (vi.toml's are `ông` and `bà`), so a plain choice of one is refused, changing nothing, while a strict one is accepted (decided 2026-10-31): under strict, a file holding no reading is not inert, every Latin-script reading but `mul.toml`'s (since #1005) leaving, so strict `vi` is the native-script vocabulary and `mul.toml` and nothing else until vi.toml holds readings. 26 further files hold no Latin-script vocabulary reading (am, as, be, bg, el, gu, ja, km, kn, ko, lo, mk, ml, mr, my, ne, or, sd, shn, si, ta, te, th, ti, uk, zh), so strict of one of them is the native-script pool, `mul.toml` (since #1005) and that file's name readings: strict `ko` is the native-script vocabulary and, in Latin letters, `mul.toml`'s words alone (since #1005).

Expand Down
8 changes: 4 additions & 4 deletions docs/locales.rst
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,8 @@ ancestors' as above, plus every word written in a script other than
Latin (the Korean, Japanese and Chinese honorifics, the Cyrillic and
Devanagari titles), which selects itself by its script, and the words
every language writes alike, in the shared ``mul`` file, among them
``Dr``, ``Prof``, ``Mr``, ``Mrs``, the degrees ``PhD``, ``MSc``, ``MBA``,
``MPH`` and ``BSc``, and the numerals. Every other
``Dr``, ``Prof``, ``Mr``, ``Mrs``, ``Ms`` (the salutation and the degree), ``Miss``,
the degrees ``PhD``, ``MSc``, ``MBA``, ``MPH`` and ``BSc``, and the numerals. Every other
language's words leave, and a word none of these holds is read as a
name word:

Expand Down Expand Up @@ -310,9 +310,9 @@ drops from every name:
stay (``Kim Min Jun, PhD, MSc`` keeps both credentials), but the rest
of the English credentials (``Kim Min Jun, MD`` reads given ``MD``,
``MD`` staying English's since a leading ``Md`` abbreviates Muhammad),
a bare ``Ms``, and an immigrant's particle from another language are
a bare ``Mx``, and an immigrant's particle from another language are
read as name words. A shape still reads as it does by default:
``Ms.``, with its period, is a title. Where English context is part
``Mx.``, with its period, is a title. Where English context is part
of the data, choose ``en`` too, which brings back its words and its
costs alike:

Expand Down
1 change: 1 addition & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Release Log
- **Fix a name that opens with a credential word losing its given name before a comma.** ``parse("JP Clancy, MD")`` gives given ``JP``, family ``Clancy``, where 2.4.0 through 2.8.0 gave family ``JP Clancy``; initials that spell a credential (``A.M.``, ``M.S.``), the given name ``Md`` and given names such as ``Cem`` read the same, as they do without the comma. :issue:`1017`
- **Fix a generation word written mid-name taking the family name with it.** ``parse("Guy Andre Junior Francois")`` gives middle ``Andre Junior``, family ``Francois``, as 1.4.0 through 2.3.0 did, where 2.4.0 through 2.8.0 gave family ``Andre``, suffix ``Junior Francois``; a credential behind the generation word (``John Smith Jr. PhD Jones``) and the part after a family comma (``Smith, John Jr. Jones``) still start the credential's run. :issue:`1023`
- **Fix 77 common US credentials ending the family name.** ``parse("Jane Doe MSW")`` gives family ``Doe``, suffix ``MSW``, where 1.4.0 through 2.8.1 gave middle ``Doe``, family ``MSW``; ``MBBS``, ``FNP``, ``BSN`` and the rest read the same with no comma, after a comma in a name written in one case, and ending the given part after a family comma. ``PAC``, ``LAT`` and ``MOT`` are also surnames, so ``Jane Doe Lat`` keeps the family name, now reporting the fork, and a name written in one case with a word to spare loses it, reported the same way (``JANE DOE LAT`` gives suffix ``LAT``). :issue:`993`
- **Fix the surname Mba read as the MBA degree.** ``parse("Chinedu Mba")`` gives family ``Mba``, as 1.4.0 did, where 2.0.0 through 2.8.1 gave suffix ``Mba`` and no family. ``John Smith, MBA`` and ``John Smith MBA`` still read the degree; where a name word can stand, it reads as the name, as ``MA`` does (``Smith, MBA Jane`` gives given ``MBA``), and brackets configured for maiden names read ``(MBA)`` as the maiden name. :issue:`1005`

* 2.8.1 - November 2, 2026

Expand Down
4 changes: 2 additions & 2 deletions docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -911,8 +911,8 @@ parenthesized nicknames that happen to be credentials:

.. doctest::

>>> parse("Andrew Perkins (MBA)").suffix
'MBA'
>>> parse("Andrew Perkins (PhD)").suffix
'PhD'
>>> parse("Andrew Perkins (Ret.)").suffix
'Ret.'

Expand Down
2 changes: 1 addition & 1 deletion nameparser/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,7 @@ class AmbiguityKind(StrEnum):
#: Delimited content is an ambiguous suffix acronym, so it reads
#: plausibly as either a post-nominal or a nickname -- "JEFFREY
#: (JD) BRICKEN" keeps the nickname reading, where the
#: unambiguous "(MBA)" escapes to suffix on vocabulary alone, and
#: unambiguous "(PhD)" escapes to suffix on vocabulary alone, and
#: "Andrew Perkins (JD)" on its capitals, which settle it.
SUFFIX_OR_NICKNAME = "suffix-or-nickname"
#: A trailing word reads plausibly as either a post-nominal or an
Expand Down
1 change: 1 addition & 0 deletions nameparser/config/_compiled.py
Original file line number Diff line number Diff line change
Expand Up @@ -1966,6 +1966,7 @@
'lac',
'lat',
'ma',
'mba',
'meng',
'mot',
'obi',
Expand Down
6 changes: 3 additions & 3 deletions nameparser/config/_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -1136,7 +1136,7 @@
('matriarch', (('en', 'kinship', ()),)),
('mayor', (('en', 'office', ()),)),
('mb', (('en', 'credential', ()),)),
('mba', (('mul', 'credential', ()),)),
('mba', (('mul', 'credential', ()), ('mul', 'family', ()))),
('mbbch', (('en', 'credential', (('cased', 'MBBCh'),)),)),
('mbbs', (('en', 'credential', ()),)),
('mbchb', (('en', 'credential', (('cased', 'MBChB'),)),)),
Expand Down Expand Up @@ -1196,7 +1196,7 @@
('military', (('en', 'modifier', ()),)),
('minister', (('en', 'office', ()),)),
('mirm', (('en', 'credential', ()),)),
('miss', (('en', 'salutation', (('after_given', True),)), ('en', 'family', ()))),
('miss', (('mul', 'salutation', (('after_given', True),)), ('mul', 'family', ()))),
('misses', (('en', 'salutation', (('after_given', True),)),)),
('missionary', (('en', 'occupation', ()),)),
('mister', (('en', 'salutation', ()), ('en', 'family', ()))),
Expand Down Expand Up @@ -1243,7 +1243,7 @@
('mrpharms', (('en', 'credential', (('cased', 'MRPharmS'),)),)),
('mrs', (('mul', 'salutation', (('after_given', True),)),)),
('mrtpi', (('en', 'credential', ()),)),
('ms', (('en', 'salutation', ()), ('en', 'credential', ()))),
('ms', (('mul', 'salutation', ()), ('mul', 'credential', ()))),
('msa', (('en', 'credential', ()),)),
('msc', (('mul', 'credential', (('cased', 'MSc'),)),)),
('mscmsm', (('en', 'credential', ()),)),
Expand Down
Loading
Loading