Skip to content

Commit bf32594

Browse files
committed
fix: restore suffix_acronyms_ambiguous wiring lost in a git race
nameparser/config/__init__.py's suffix_acronyms_ambiguous attribute (import, docstring, type hint, constructor param, and __init__ assignment -- all from Task 1, commit 135395b) was accidentally reverted by commit c2efbd8. Root cause: a review subagent was running concurrently in this same shared worktree directory and appears to have checked out an older commit in place (rather than in an isolated copy) to compare pre/post-PR behavior for its "verified against unmodified master" claims; that checkout's staged state got swept into c2efbd8's commit alongside my own staged changes, since `git commit` includes everything staged, not just newly `git add`ed paths. The working tree itself was never wrong -- parser.py's handle_match() has referenced self.C.suffix_acronyms_ambiguous correctly this whole time, and pytest passed after every commit since the corruption, because pytest reads the filesystem, not git history. Only the *committed* nameparser/config/__init__.py (and, transiently, the already-pushed PR branch) lacked the attribute -- a fresh clone of c2efbd8..4e91b7a would have raised AttributeError on any name containing parens/quotes. Verified via `git show HEAD:...` and `git diff 135395b HEAD -- nameparser/config/__init__.py` that this commit is the only remaining gap; suffixes.py, parser.py, and the tests were independently re-added correctly in later commits. Also includes docs/usage.rst and docs/customize.rst updates documenting the new suffix_acronyms_ambiguous behavior and SUFFIX_ACRONYMS_AMBIGUOUS constant.
1 parent 4e91b7a commit bf32594

3 files changed

Lines changed: 49 additions & 1 deletion

File tree

docs/customize.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ Editable attributes of nameparser.config.CONSTANTS
4343
* :py:data:`~nameparser.config.FIRST_NAME_TITLES` - Titles that, when followed by a single name, that name is a first name, e.g. "King David".
4444
* :py:data:`~nameparser.config.SUFFIX_ACRONYMS` - Pieces that come at the end of the name that may or may not have periods separating the letters, e.g. "m.d.".
4545
* :py:data:`~nameparser.config.SUFFIX_NOT_ACRONYMS` - Pieces that come at the end of the name that never have periods separating the letters, e.g. "Jr.".
46+
* :py:data:`~nameparser.config.SUFFIX_ACRONYMS_AMBIGUOUS` - Acronym suffixes from ``SUFFIX_ACRONYMS`` that also plausibly work as a given-name nickname on their own, e.g. "JD", "Ed". When one of these appears alone in parenthesis or quotes (e.g. ``'JEFFREY (JD) BRICKEN'``), it's kept as a nickname rather than reclassified as a suffix, since that's the more common reading in ambiguous, delimiter-only context (see the "Nickname Handling" section in the usage guide).
4647
* :py:data:`~nameparser.config.conjunctions.CONJUNCTIONS` - Connectors like "and" that join the preceding piece to the following piece.
4748
* :py:data:`~nameparser.config.prefixes.PREFIXES` - Connectors like "del" and "bin" that join to the following piece but not the preceding, similar to titles but can appear anywhere in the name.
4849
* :py:data:`~nameparser.config.CAPITALIZATION_EXCEPTIONS` - Dictionary of pieces that do not capitalize the first letter, e.g. "Ph.D".

docs/usage.rst

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,47 @@ available from the nickname attribute.
147147
nickname: 'John'
148148
]>
149149

150+
Exception: content that looks like a suffix (a member of
151+
:py:data:`~nameparser.config.SUFFIX_ACRONYMS` or
152+
:py:data:`~nameparser.config.SUFFIX_NOT_ACRONYMS`, or anything ending in a
153+
period) is treated as a suffix instead of a nickname, since that's usually
154+
what's meant, e.g. a retired military title or a professional designation
155+
written in parenthesis.
156+
157+
.. doctest:: nicknames
158+
:options: +NORMALIZE_WHITESPACE
159+
160+
>>> name = HumanName('Andrew Perkins (MBA)')
161+
>>> name
162+
<HumanName : [
163+
title: ''
164+
first: 'Andrew'
165+
middle: ''
166+
last: 'Perkins'
167+
suffix: 'MBA'
168+
nickname: ''
169+
]>
170+
171+
A few suffix acronyms, listed in
172+
:py:data:`~nameparser.config.SUFFIX_ACRONYMS_AMBIGUOUS`, also work as common
173+
given-name nicknames on their own (e.g. "JD", "Ed"). These stay nicknames
174+
when found alone in parenthesis or quotes, since that's the more common
175+
reading in that ambiguous context:
176+
177+
.. doctest:: nicknames
178+
:options: +NORMALIZE_WHITESPACE
179+
180+
>>> name = HumanName('JEFFREY (JD) BRICKEN')
181+
>>> name
182+
<HumanName : [
183+
title: ''
184+
first: 'JEFFREY'
185+
middle: ''
186+
last: 'BRICKEN'
187+
suffix: ''
188+
nickname: 'JD'
189+
]>
190+
150191
Change the output string with string formatting
151192
-----------------------------------------------
152193

nameparser/config/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
from nameparser.config.conjunctions import CONJUNCTIONS
4343
from nameparser.config.suffixes import SUFFIX_ACRONYMS
4444
from nameparser.config.suffixes import SUFFIX_NOT_ACRONYMS
45+
from nameparser.config.suffixes import SUFFIX_ACRONYMS_AMBIGUOUS
4546
from nameparser.config.titles import TITLES
4647
from nameparser.config.titles import FIRST_NAME_TITLES
4748
from nameparser.config.regexes import EMPTY_REGEX, REGEXES
@@ -236,8 +237,10 @@ class Constants:
236237
:py:attr:`~titles.FIRST_NAME_TITLES` wrapped with :py:class:`SetManager`.
237238
:param set suffix_acronyms:
238239
:py:attr:`~suffixes.SUFFIX_ACRONYMS` wrapped with :py:class:`SetManager`.
239-
:param set suffix_not_acronyms:
240+
:param set suffix_not_acronyms:
240241
:py:attr:`~suffixes.SUFFIX_NOT_ACRONYMS` wrapped with :py:class:`SetManager`.
242+
:param set suffix_acronyms_ambiguous:
243+
:py:attr:`~suffixes.SUFFIX_ACRONYMS_AMBIGUOUS` wrapped with :py:class:`SetManager`.
241244
:param set conjunctions:
242245
:py:attr:`conjunctions` wrapped with :py:class:`SetManager`.
243246
:param set first_name_prefixes:
@@ -257,6 +260,7 @@ class Constants:
257260
first_name_titles: SetManager
258261
conjunctions: SetManager
259262
first_name_prefixes: SetManager
263+
suffix_acronyms_ambiguous: SetManager
260264
capitalization_exceptions: TupleManager[str]
261265
regexes: RegexTupleManager
262266
_pst: Set[str] | None
@@ -388,6 +392,7 @@ def __init__(self,
388392
prefixes: Iterable[str] = PREFIXES,
389393
suffix_acronyms: Iterable[str] = SUFFIX_ACRONYMS,
390394
suffix_not_acronyms: Iterable[str] = SUFFIX_NOT_ACRONYMS,
395+
suffix_acronyms_ambiguous: Iterable[str] = SUFFIX_ACRONYMS_AMBIGUOUS,
391396
titles: Iterable[str] = TITLES,
392397
first_name_titles: Iterable[str] = FIRST_NAME_TITLES,
393398
conjunctions: Iterable[str] = CONJUNCTIONS,
@@ -406,6 +411,7 @@ def __init__(self,
406411
self.first_name_titles = SetManager(first_name_titles)
407412
self.conjunctions = SetManager(conjunctions)
408413
self.first_name_prefixes = SetManager(first_name_prefixes)
414+
self.suffix_acronyms_ambiguous = SetManager(suffix_acronyms_ambiguous)
409415
self.capitalization_exceptions = TupleManager(capitalization_exceptions)
410416
self.regexes = RegexTupleManager(regexes)
411417
self.patronymic_name_order = patronymic_name_order

0 commit comments

Comments
 (0)