Repository navigation
fix: preserve Omitted singleton across copy, deepcopy and pickle - #17
Merged
goduni merged 2 commits intoSep 15, 2026
Merged
Conversation
SingletonMeta enforces the singleton via __call__, but copy, deepcopy and pickle recreate the instance through __new__, bypassing the metaclass. This broke equality for any object with an Omitted-valued field after a copy or pickle round-trip. Add __copy__, __deepcopy__ and __reduce__ so Omitted always resolves back to the singleton.
Regression tests for the singleton fix: copy/deepcopy/pickle identity and equality, dataclass equality round-trips, and dataclasses.asdict().
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #17 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 33 33
Lines 1328 1334 +6
=========================================
+ Hits 1328 1334 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
6 of 12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Omittedis a singleton enforced bySingletonMeta.__call__, butcopy.copy,copy.deepcopyandpicklebuild new instances throughcls.__new__(cls), bypassing the metaclass. SinceOmitteddefined no__reduce__or copy hooks, a copied or unpickled sentinel compared unequal to the original:This silently broke equality for any object with an
Omitted-valued field once it round-tripped throughdeepcopy/pickle(Celery, multiprocessing, caches,dataclasses.asdict, ...), even though the objects looked identical viarepr.The fix keeps the singleton invariant across all three paths so
Omittedalways resolves back to the one instance:__copy__/__deepcopy__returnself__reduce__returns(type(self), ()), so unpickling routes back throughSingletonMetaWith the singleton preserved, identity-based equality holds automatically, so no
__eq__/__hash__change is needed. The serializers keep working unchanged since they rely onisinstance.Reported downstream in K1rL3s/maxo#241.
Testing
uv run pytest --cov srcon Python 3.13: 414 passed, 4 skipped, 100% coverage.just lint(ruff check + format) andjust static-analysis(mypy strict) both clean.Type of change
Checklist
just lintshows no errors)just static-analysis