Skip to content

Commit 5645fbf

Browse files
derek73claude
andcommitted
Review follow-ups: pin cross-constants semantics, fix inert test token
The custom-constants test used 'chancellor', which is already a default title, so it passed without the self.C parse path ever mattering; use a token that is provably not a default title, with a guard assertion. Pin the operand asymmetry as deliberate: a str operand is reparsed with self.C, a HumanName operand is compared as already parsed. Document the all-empty comparison key for empty/unparsable input in both docstrings (screen with len(name) == 0), with a test, and add a non-ASCII case-insensitivity check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 92cf216 commit 5645fbf

2 files changed

Lines changed: 39 additions & 6 deletions

File tree

nameparser/parser.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ def comparison_key(self) -> tuple[str, ...]:
311311
display settings like ``string_format`` and
312312
``empty_attribute_default``.
313313
314+
Empty or unparsable input yields the all-empty key, so such names
315+
all compare equal and collide in dedup; screen them out with
316+
``len(name) == 0`` first.
317+
314318
.. doctest::
315319
316320
>>> HumanName("Dr. Juan Q. Xavier de la Vega III").comparison_key()
@@ -327,7 +331,10 @@ def matches(self, other: 'str | HumanName') -> bool:
327331
Compare parsed components case-insensitively; the semantic
328332
replacement for the deprecated ``==``. A ``str`` argument is parsed
329333
first, using this instance's configuration, so any written form of
330-
the same name matches:
334+
the same name matches; a ``HumanName`` argument is compared as
335+
already parsed — its own configuration determined its components.
336+
Two empty or unparsable names match each other; check
337+
``len(name) == 0`` to screen them.
331338
332339
.. doctest::
333340

tests/test_python_api.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -357,13 +357,39 @@ def test_matches_humanname_operand(self) -> None:
357357
self.assertFalse(hn.matches(HumanName("Jane Smith")))
358358

359359
def test_matches_parses_str_with_instance_constants(self) -> None:
360+
# the custom title must not be a default one ('chancellor' is!), or
361+
# this passes without the self.C parse path ever mattering
360362
c = Constants()
361-
c.titles.add('chancellor')
362-
hn = HumanName("Chancellor Jane Smith", constants=c)
363+
c.titles.add('zephyrmark')
364+
self.assertNotIn('zephyrmark', CONSTANTS.titles)
365+
hn = HumanName("Zephyrmark Jane Smith", constants=c)
363366
# the str operand is parsed with self.C, so the custom title is
364-
# recognized in the comma form; the shared CONSTANTS would not
365-
# parse 'chancellor' as a title here
366-
self.assertTrue(hn.matches("smith, chancellor jane"))
367+
# recognized in the comma form; parsed with the shared CONSTANTS,
368+
# 'zephyrmark' would land in first/middle and the keys would differ
369+
self.assertTrue(hn.matches("smith, zephyrmark jane"))
370+
371+
def test_matches_humanname_operand_keeps_its_own_parse(self) -> None:
372+
# asymmetry, pinned deliberately: a str operand is reparsed with
373+
# self.C, but a HumanName operand is compared as already parsed --
374+
# its own constants determined its components
375+
c = Constants()
376+
c.titles.add('zephyrmark')
377+
with_title = HumanName("Zephyrmark Jane Smith", constants=c)
378+
default_parse = HumanName("Zephyrmark Jane Smith")
379+
self.assertTrue(with_title.matches("Zephyrmark Jane Smith"))
380+
self.assertFalse(with_title.matches(default_parse))
381+
382+
def test_empty_parses_share_a_comparison_key(self) -> None:
383+
# documented caveat: empty/unparsable input collapses to the
384+
# all-empty key, so such names match each other and collide in
385+
# dedup; screen with len(name) == 0 first
386+
self.assertTrue(HumanName("").matches(HumanName(",")))
387+
self.assertEqual(HumanName("()").comparison_key(),
388+
HumanName("").comparison_key())
389+
390+
def test_matches_non_ascii_case_insensitive(self) -> None:
391+
hn = HumanName("JOSÉ GARCÍA")
392+
self.assertTrue(hn.matches("José García"))
367393

368394
def test_matches_rejects_other_types(self) -> None:
369395
hn = HumanName("John Smith")

0 commit comments

Comments
 (0)