Skip to content

Commit c1de58f

Browse files
derek73claude
andauthored
fix: drop Constants.__setstate__ pre-1.2.1 pickle migration shim (#178)
1.2.1 shipped with a compatibility shim that let pickles written by the old dir()-sweep __getstate__ (which included the read-only suffixes_prefixes_titles property) load without raising AttributeError. That was a one-version bridge; users who persisted pre-1.2.1 blobs can load and re-pickle under 1.2.1 before upgrading to 1.3.0. Remove the shim and its regression test, and add an upgrade note to the release log explaining the migration path. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 1b16917 commit c1de58f

3 files changed

Lines changed: 6 additions & 35 deletions

File tree

docs/release_log.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
Release Log
22
===========
33
* 1.3.0 - Unreleased
4+
5+
**Upgrade note — pickle migration**: ``Constants`` pickles written before
6+
1.2.1 cannot be loaded under 1.3.0+. If you have persisted blobs, upgrade
7+
to 1.2.1 first (which includes a one-version compatibility shim), load and
8+
re-pickle under 1.2.1, then upgrade to 1.3.0.
9+
410
- Add ``suffix_delimiter`` to ``Constants`` and ``HumanName`` for parsing suffixes separated by arbitrary delimiters, e.g. ``"RN - CRNA"`` (#156)
511
- Add ``initials_separator`` to ``Constants`` and ``HumanName`` to control spacing between consecutive initials within a name group (#171)
612
- Fix ``Constants`` customizations, singleton identity, and ``TupleManager`` subclass being lost across ``pickle``/``deepcopy`` round-trips (#167, #168, #169)

nameparser/config/__init__.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -383,16 +383,6 @@ def __setstate__(self, state: Mapping[str, Any]) -> None:
383383
# unpickling.
384384
self._pst = None
385385
for name, value in state.items():
386-
# Migration shim: pickles written before this fix used a dir() sweep
387-
# for __getstate__, so their state carries the read-only
388-
# ``suffixes_prefixes_titles`` property. Skip any such computed
389-
# property rather than raising AttributeError on its missing setter;
390-
# the real config is restored from the other keys. We don't promise
391-
# to read pre-fix blobs forever — this only smooths migration for
392-
# anyone persisting them, and can be dropped a release or two after
393-
# 1.2.1 once they've re-pickled.
394-
if isinstance(getattr(type(self), name, None), property):
395-
continue
396386
setattr(self, name, value)
397387
# Verify each descriptor-backed attr was restored. Without this, a missing
398388
# key surfaces later as AttributeError: 'Constants' object has no attribute

tests/test_constants.py

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -208,31 +208,6 @@ def test_tuplemanager_ignores_dunder_lookups(self) -> None:
208208
# A normal (non-dunder) unknown key still returns the None default.
209209
self.assertEqual(tm.unknown_key, None)
210210

211-
def test_unpickle_legacy_state_with_property_key(self) -> None:
212-
"""Pickles written by older versions must still load.
213-
214-
The previous __getstate__ built its state from a dir() sweep, which
215-
always included the computed `suffixes_prefixes_titles` property (no
216-
customization required). That property has no setter, so __setstate__
217-
must skip such keys instead of raising AttributeError.
218-
219-
Covers the temporary migration shim in __setstate__; remove this test
220-
when that shim is dropped (a release or two after 1.2.1).
221-
"""
222-
c = Constants()
223-
c.titles.add('legacytitle')
224-
# Reproduce the legacy dir()-sweep state dict, which carries the
225-
# read-only `suffixes_prefixes_titles` property alongside the real config.
226-
legacy_state = {
227-
name: getattr(c, name) for name in dir(c) if not name.startswith('_')
228-
}
229-
self.assertIn('suffixes_prefixes_titles', legacy_state)
230-
231-
restored = Constants.__new__(Constants)
232-
restored.__setstate__(legacy_state)
233-
234-
# The real customization is recovered and the property key is ignored.
235-
self.assertIn('legacytitle', restored.titles)
236211

237212
def test_suffixes_prefixes_titles_reflects_add_title(self) -> None:
238213
"""suffixes_prefixes_titles must include titles added after construction."""

0 commit comments

Comments
 (0)