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
1 change: 1 addition & 0 deletions docs/release_log.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
Release Log
===========
* 1.3.0 - Unreleased
- Fix ``IndexError`` in ``initials()``/``initials_list()`` when a ``*_list`` attribute was assigned directly with an element containing unnormalized whitespace (e.g. ``name.middle_list = ['Q R']``), bypassing the parser's whitespace normalization (closes #232)
- Fix ``HumanName`` acting as its own iterator with a stored cursor: breaking out of a loop, iterating in nested loops, or calling ``len(name)`` mid-loop corrupted subsequent iteration; ``iter(name)`` now returns a fresh independent iterator each time. ``next(name)`` on the instance itself (undocumented) now raises ``TypeError`` — call ``next(iter(name))`` instead (closes #225)
- Fix parsing writing back into the ``Constants`` it reads (usually the shared module-level ``CONSTANTS``): pieces derived while parsing a name — period-joined titles/suffixes like ``"Lt.Gov."`` and conjunction-joined pieces like ``"Mr. and Mrs."`` or ``"von und zu"`` — are now tracked per parse instead of being permanently ``add()``-ed to the config, so parse results no longer depend on which names were parsed earlier in the process and parsing no longer mutates shared state across threads
- Remove the vestigial ``unparsable`` attribute: the guard that was meant to set it has been unreachable since 2013 (v0.2.9), so it has reported ``False`` for every parsed name for over a decade; check ``len(name) == 0`` to detect an empty parse
Expand Down
5 changes: 4 additions & 1 deletion nameparser/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,7 +250,10 @@ def _process_initial(self, name_part: str, firstname: bool = False) -> str:
Name parts may include prefixes or conjunctions. This function filters these from the name unless it is
a first name, since first names cannot be conjunctions or prefixes.
"""
parts = name_part.split(" ")
# split() rather than split(" "): *_list attributes assigned directly
# bypass parse_pieces whitespace normalization, and split(" ") yields
# empty strings for repeated spaces (#232)
parts = name_part.split()
initials = []
for part in parts:
if not (self.is_prefix(part) or self.is_conjunction(part)) or firstname:
Expand Down
9 changes: 9 additions & 0 deletions tests/test_initials.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,15 @@ def test_str_default_behavior_unchanged(self) -> None:
hn = HumanName("John Doe")
self.assertEqual(str(hn), "John Doe")

def test_initials_with_doubled_space_in_list_element(self) -> None:
# direct *_list assignment bypasses parse_pieces whitespace
# normalization, so initials must tolerate unnormalized elements
# instead of raising IndexError (#232)
hn = HumanName(first="John")
hn.middle_list = ["Q R"]
self.assertEqual(hn.initials_list(), ["J", "Q R"])
self.assertEqual(hn.initials(), "J. Q R.")

def test_constructor_first(self) -> None:
hn = HumanName(first="TheName")
self.m(hn.first, "TheName", hn)
Expand Down
Loading