From 248423b07e12efaab88330b5af793b7b1b4f2722 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Mon, 29 Jun 2026 03:31:36 -0700 Subject: [PATCH 1/2] test: pin suffixes_prefixes_titles cache performance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This library is used to parse large batches of names, making the _pst cache on suffixes_prefixes_titles load-bearing for throughput. Add a timeit-based test that asserts 10 000 repeated calls complete in under 10 ms — well within what a single uncached union build would take — so accidental cache removal surfaces immediately as a test failure. Co-Authored-By: Claude Sonnet 4.6 --- tests/test_constants.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/test_constants.py b/tests/test_constants.py index 0e8ddbd..463ea14 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -1,5 +1,6 @@ import copy import pickle +import timeit from nameparser import HumanName from nameparser.config import Constants, RegexTupleManager, SetManager, TupleManager @@ -232,3 +233,32 @@ def test_unpickle_legacy_state_with_property_key(self) -> None: # The real customization is recovered and the property key is ignored. self.assertIn('legacytitle', restored.titles) + + +class SuffixesPrefixesTitlesPerformanceTests(HumanNameTestBase): + """Guard against accidental cache removal on suffixes_prefixes_titles. + + This library is commonly used to parse large batches of names, so + suffixes_prefixes_titles must remain cached. Without the cache, each call + rebuilds the union from ~700 strings (~50-100 µs); with it, repeated access + is ~1000x faster. This test asserts that 10 000 repeated calls complete + well within the time a single uncached union build would take. + """ + + def test_repeated_access_is_cached(self) -> None: + c = Constants() + # Prime the cache with one access. + _ = c.suffixes_prefixes_titles + + n = 10_000 + elapsed = timeit.timeit(lambda: c.suffixes_prefixes_titles, number=n) + + # One uncached union build over ~700 strings takes ~50-100 µs on any + # modern machine. If caching is broken, 10 000 calls would take + # seconds; with caching they finish in well under 10 ms total. + limit = 0.010 # 10 ms = 1 µs/call average + assert elapsed < limit, ( + f"suffixes_prefixes_titles appears uncached: {n} calls took " + f"{elapsed * 1000:.1f} ms (limit {limit * 1000:.0f} ms). " + "Was _pst caching removed?" + ) From 93ac812d44148fd0fce0125fd082be71ff313439 Mon Sep 17 00:00:00 2001 From: Derek Gulbranson Date: Mon, 29 Jun 2026 03:36:24 -0700 Subject: [PATCH 2/2] test: add identity assertion to cache performance test Co-Authored-By: Claude Sonnet 4.6 --- tests/test_constants.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/test_constants.py b/tests/test_constants.py index 463ea14..56565b2 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -247,8 +247,9 @@ class SuffixesPrefixesTitlesPerformanceTests(HumanNameTestBase): def test_repeated_access_is_cached(self) -> None: c = Constants() - # Prime the cache with one access. - _ = c.suffixes_prefixes_titles + first = c.suffixes_prefixes_titles + second = c.suffixes_prefixes_titles + assert first is second, "suffixes_prefixes_titles should return the same cached object on repeated access" n = 10_000 elapsed = timeit.timeit(lambda: c.suffixes_prefixes_titles, number=n)