WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 861e60d

Browse files
committed
General cleanup. Reverse the class order to allowing pickling to work a bit more natively.
Make the testing a bit smarter to auto skip CFrozenList tests if they don't apply.
1 parent 1e048f4 commit 861e60d

File tree

3 files changed

+37
-25
lines changed

3 files changed

+37
-25
lines changed

frozenlist/__init__.py

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414

1515
@total_ordering
16-
class FrozenList(MutableSequence):
16+
class PyFrozenList(MutableSequence):
1717
__slots__ = ("_frozen", "_items")
1818
__class_getitem__ = classmethod(types.GenericAlias)
1919

@@ -92,22 +92,18 @@ def __deepcopy__(self, memo: dict[int, object]):
9292

9393
def __reduce__(self):
9494
return (
95-
_reconstruct_pyfrozenlist,
96-
(self._items, self._frozen),
95+
self.__class__,
96+
(self._items,),
97+
{"_frozen": self._frozen},
9798
)
9899

100+
def __setstate__(self, state: dict[str, object]):
101+
self._frozen = state["_frozen"]
99102

100-
# Store a reference to the pure Python implementation before it's potentially replaced
101-
PyFrozenList = FrozenList
102103

103-
104-
def _reconstruct_pyfrozenlist(items: list[object], frozen: bool) -> PyFrozenList:
105-
"""Helper function to reconstruct the pure Python FrozenList during unpickling.
106-
This function is needed since otherwise the class renaming confuses pickle."""
107-
fl = PyFrozenList(items)
108-
if frozen:
109-
fl.freeze()
110-
return fl
104+
# Rename the pure Python implementation. The C extension (if available) will
105+
# override this name.
106+
FrozenList = PyFrozenList
111107

112108

113109
if not NO_EXTENSIONS:

frozenlist/_frozenlist.pyx

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ cdef class FrozenList:
127127
cdef FrozenList new_list
128128
obj_id = id(self)
129129

130-
# Return existing copy if already processed (circular reference)
131-
if obj_id in memo:
132-
return memo[obj_id]
133-
134130
# Create new instance and register immediately
135131
new_list = self.__class__([])
136132
memo[obj_id] = new_list

tests/test_frozenlist.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@
99

1010
from frozenlist import FrozenList, PyFrozenList
1111

12+
try:
13+
from frozenlist import CFrozenList
14+
15+
HAS_CFROZENLIST = True
16+
except ImportError:
17+
HAS_CFROZENLIST = False
18+
1219

1320
class FrozenListMixin:
1421
FrozenList = NotImplemented
@@ -414,33 +421,46 @@ def test_picklability_forward_compatible(self, freeze: bool) -> None:
414421

415422
# If this test breaks, we've changed the frozenlist data structure in an incompatible way
416423
# with previous pickled binaries.
417-
if self.FrozenList is FrozenList:
424+
if self.FrozenList is PyFrozenList:
418425
if freeze:
419426
assert (
420427
pickled
421-
== b"cfrozenlist._frozenlist\nFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI01\nsb."
428+
== b"cfrozenlist\nPyFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI01\nsb."
422429
)
423430
else:
424431
assert (
425432
pickled
426-
== b"cfrozenlist._frozenlist\nFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI00\nsb."
433+
== b"cfrozenlist\nPyFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI00\nsb."
427434
)
428-
elif self.FrozenList is PyFrozenList:
435+
elif self.FrozenList is FrozenList:
429436
if freeze:
430437
assert (
431438
pickled
432-
== b"cfrozenlist\n_reconstruct_pyfrozenlist\np0\n((lp1\nI1\naI2\naI01\ntp2\nRp3\n."
439+
== b"cfrozenlist._frozenlist\nFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI01\nsb."
433440
)
434441
else:
435442
assert (
436443
pickled
437-
== b"cfrozenlist\n_reconstruct_pyfrozenlist\np0\n((lp1\nI1\naI2\naI00\ntp2\nRp3\n."
444+
== b"cfrozenlist._frozenlist\nFrozenList\np0\n((lp1\nI1\naI2\natp2\nRp3\n(dp4\nV_frozen\np5\nI00\nsb."
438445
)
446+
else:
447+
pytest.fail("Unknown FrozenList implementation.")
439448

440449

441-
class TestFrozenList(FrozenListMixin):
442-
FrozenList = FrozenList # type: ignore[assignment] # FIXME
450+
if HAS_CFROZENLIST:
451+
# If we don't have CFrozenList, skip adding the test class specifically for it.
452+
class TestFrozenList(FrozenListMixin):
453+
FrozenList = CFrozenList # type: ignore[assignment] # FIXME
443454

444455

445456
class TestFrozenListPy(FrozenListMixin):
457+
# All implementations will at least have the Python version.
446458
FrozenList = PyFrozenList # type: ignore[assignment] # FIXME
459+
460+
461+
def test_frozenlist_aliasing() -> None:
462+
"""Test that FrozenList name points to the C extension if available, else to PyFrozenList."""
463+
if HAS_CFROZENLIST:
464+
assert FrozenList is CFrozenList
465+
else:
466+
assert FrozenList is PyFrozenList

0 commit comments

Comments
 (0)