Skip to content

fix: restore CONSTANTS singleton identity across pickle/deepcopy#170

Merged
derek73 merged 4 commits into
masterfrom
fix/issue-169-singleton-identity
Jun 28, 2026
Merged

fix: restore CONSTANTS singleton identity across pickle/deepcopy#170
derek73 merged 4 commits into
masterfrom
fix/issue-169-singleton-identity

Conversation

@derek73

@derek73 derek73 commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #169.

A default HumanName shares the module-level CONSTANTS singleton as its .C. pickle and copy.deepcopy cannot preserve object identity, so without custom hooks .C was serialized by value — causing has_own_config to flip to True and bloating every serialized default name with a full Constants copy (~1000+ entries).

Fix

Add __getstate__/__setstate__ to HumanName:

  • __getstate__ replaces .C with None as a sentinel when it is the shared CONSTANTS singleton.
  • __setstate__ restores the CONSTANTS reference from that sentinel.

None is a safe sentinel because HumanName.__init__ always replaces a None constants argument with a fresh Constants(), so .C is never legitimately None at rest. Both pickle and copy.deepcopy call these hooks, so one implementation covers both.

Instance-config names (where .C is not CONSTANTS) are unaffected — their own Constants copy continues to round-trip through the existing __dict__ path established in #168.

Tests

  • test_pickle_default_name_preserves_singleton_identityC is CONSTANTS and has_own_config == False after a pickle round-trip.
  • test_deepcopy_default_name_preserves_singleton_identity — same assertions after copy.deepcopy.

Also adds assertIs/assertIsNot shims to HumanNameTestBase (the custom test base class that replaced unittest.TestCase) and updates three existing assertTrue(x is ...) callsites to use them for clearer failure messages.

Full suite: 710 passed, 20 xfailed.


This was prepared with the assistance of AI, under my direction and review.

derek73 and others added 4 commits June 28, 2026 12:11
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
 #169)

A default HumanName shares the module-level CONSTANTS singleton as its .C.
pickle and copy.deepcopy cannot preserve object identity, so without custom
hooks .C was serialized by value — causing has_own_config to flip to True
and bloating every serialized default name with a full Constants copy.

__getstate__ replaces .C with None as a sentinel when it is the shared
singleton; __setstate__ restores the CONSTANTS reference from that sentinel.
None is a safe sentinel because the constructor always replaces a None
constants argument with a fresh Constants().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…verage

- Assert parsed fields (str, first, last) survive pickle/deepcopy round-trips
  alongside the existing singleton-identity checks
- Add test_pickle_instance_config_name_preserves_own_config: pins that
  instance-config names are not collapsed onto CONSTANTS after pickle
- Add test_shallow_copy_default_name_preserves_singleton_identity: documents
  that copy.copy shares the CONSTANTS reference without needing __getstate__

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@derek73

derek73 commented Jun 28, 2026

Copy link
Copy Markdown
Owner Author

Post-review follow-up (3c3c04f): strengthened the test suite based on a comprehensive review of this PR.

What was added:

  • Parsed-field assertions in test_pickle_default_name_preserves_singleton_identity and test_deepcopy_default_name_preserves_singleton_identity — both tests now also assert str(restored) == str(hn), .first, and .last match, so a future __setstate__ refactor that accidentally drops state would be caught immediately rather than only the singleton check failing.

  • test_pickle_instance_config_name_preserves_own_config — closes the one gap in the four-quadrant matrix ({default config, own config} × {pickle, deepcopy}). The deepcopy side already had test_name_instance_deepcopy_isolates_instance_config; pickle now has a counterpart that asserts has_own_config stays True and C is not CONSTANTS after a round-trip.

  • test_shallow_copy_default_name_preserves_singleton_identity — documents that copy.copy preserves CONSTANTS identity by sharing the reference directly (shallow copy copies __dict__ without calling __getstate__/__setstate__), so no hook is needed. Pins the contract so it's visible if that behavior ever changes.

76 tests pass, no regressions.

@derek73 derek73 self-assigned this Jun 28, 2026
@derek73 derek73 merged commit 7686567 into master Jun 28, 2026
8 checks passed
@derek73 derek73 deleted the fix/issue-169-singleton-identity branch June 28, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HumanName loses CONSTANTS singleton identity on pickle/deepcopy (has_own_config flips, pickle bloat)

1 participant