summaryrefslogtreecommitdiffstats
path: root/contrib/python/frozenlist
diff options
context:
space:
mode:
authorrobot-piglet <[email protected]>2025-08-04 08:37:25 +0300
committerrobot-piglet <[email protected]>2025-08-04 08:47:50 +0300
commitc569c2f61d37fbb5deccf1b0b19b874fc9dfe2b1 (patch)
tree478e75412b64d3ac505a4adaa4691d718f75438d /contrib/python/frozenlist
parent093752a2164d4bbe855bc009b02fde83f567a510 (diff)
Intermediate changes
commit_hash:eff2306ab69f70411903fc1110f59ea6d8b43a2d
Diffstat (limited to 'contrib/python/frozenlist')
-rw-r--r--contrib/python/frozenlist/.dist-info/METADATA83
-rw-r--r--contrib/python/frozenlist/frozenlist/__init__.py2
-rw-r--r--contrib/python/frozenlist/frozenlist/_frozenlist.pyx24
-rw-r--r--contrib/python/frozenlist/tests/test_frozenlist.py124
-rw-r--r--contrib/python/frozenlist/ya.make2
5 files changed, 231 insertions, 4 deletions
diff --git a/contrib/python/frozenlist/.dist-info/METADATA b/contrib/python/frozenlist/.dist-info/METADATA
index 1bfacffc096..2618ac44b34 100644
--- a/contrib/python/frozenlist/.dist-info/METADATA
+++ b/contrib/python/frozenlist/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.4
Name: frozenlist
-Version: 1.6.0
+Version: 1.7.0
Summary: A list-like structure which implements collections.abc.MutableSequence
Home-page: https://github.com/aio-libs/frozenlist
Maintainer: aiohttp team <[email protected]>
@@ -161,6 +161,87 @@ Changelog
.. towncrier release notes start
+v1.7.0
+======
+
+*(2025-06-09)*
+
+
+Features
+--------
+
+- Added deepcopy support to FrozenList -- by `@bdraco <https://github.com/sponsors/bdraco>`__.
+
+ *Related issues and pull requests on GitHub:*
+ `#659 <https://github.com/aio-libs/frozenlist/issues/659>`__.
+
+
+Packaging updates and notes for downstreams
+-------------------------------------------
+
+- Fixed an issue where ``frozenlist`` binary wheels would be built with debugging symbols and line tracing enabled, which significantly impacted performance. Line tracing is now disabled by default and can only be enabled explicitly -- by `@bdraco <https://github.com/sponsors/bdraco>`__.
+
+ This change ensures that production builds are optimized for performance. Developers who need line tracing for debugging purposes can still enable it by:
+
+ 1. Setting the ``FROZENLIST_CYTHON_TRACING`` environment variable
+ 2. Using the ``--config-setting=with-cython-tracing=true`` option with pip
+
+ *Related issues and pull requests on GitHub:*
+ `#660 <https://github.com/aio-libs/frozenlist/issues/660>`__.
+
+- Enabled ``PIP_CONSTRAINT`` environment variable in the build configuration to ensure the pinned Cython version from ``requirements/cython.txt`` is used during wheel builds.
+
+ *Related issues and pull requests on GitHub:*
+ `#661 <https://github.com/aio-libs/frozenlist/issues/661>`__.
+
+
+----
+
+
+v1.6.2
+======
+
+*(2025-06-03)*
+
+
+No significant changes.
+
+
+----
+
+
+v1.6.1
+======
+
+*(2025-06-02)*
+
+
+Bug fixes
+---------
+
+- Correctly use ``cimport`` for including ``PyBool_FromLong`` -- by `@lysnikolaou <https://github.com/sponsors/lysnikolaou>`__.
+
+ *Related issues and pull requests on GitHub:*
+ `#653 <https://github.com/aio-libs/frozenlist/issues/653>`__.
+
+
+Packaging updates and notes for downstreams
+-------------------------------------------
+
+- Exclude ``_frozenlist.cpp`` from bdists/wheels -- by `@musicinmybrain <https://github.com/sponsors/musicinmybrain>`__.
+
+ *Related issues and pull requests on GitHub:*
+ `#649 <https://github.com/aio-libs/frozenlist/issues/649>`__.
+
+- Updated to use Cython 3.1 universally across the build path -- by `@lysnikolaou <https://github.com/sponsors/lysnikolaou>`__.
+
+ *Related issues and pull requests on GitHub:*
+ `#654 <https://github.com/aio-libs/frozenlist/issues/654>`__.
+
+
+----
+
+
v1.6.0
======
diff --git a/contrib/python/frozenlist/frozenlist/__init__.py b/contrib/python/frozenlist/frozenlist/__init__.py
index 97ed28fd5e6..a8019adadcf 100644
--- a/contrib/python/frozenlist/frozenlist/__init__.py
+++ b/contrib/python/frozenlist/frozenlist/__init__.py
@@ -3,7 +3,7 @@ import types
from collections.abc import MutableSequence
from functools import total_ordering
-__version__ = "1.6.0"
+__version__ = "1.7.0"
__all__ = ("FrozenList", "PyFrozenList") # type: Tuple[str, ...]
diff --git a/contrib/python/frozenlist/frozenlist/_frozenlist.pyx b/contrib/python/frozenlist/frozenlist/_frozenlist.pyx
index 39561b75635..a82d8c8ff6c 100644
--- a/contrib/python/frozenlist/frozenlist/_frozenlist.pyx
+++ b/contrib/python/frozenlist/frozenlist/_frozenlist.pyx
@@ -1,9 +1,10 @@
# cython: freethreading_compatible = True
# distutils: language = c++
-from cpython.bool import PyBool_FromLong
+from cpython.bool cimport PyBool_FromLong
from libcpp.atomic cimport atomic
+import copy
import types
from collections.abc import MutableSequence
@@ -122,5 +123,26 @@ cdef class FrozenList:
else:
raise RuntimeError("Cannot hash unfrozen list.")
+ def __deepcopy__(self, memo):
+ cdef FrozenList new_list
+ obj_id = id(self)
+
+ # Return existing copy if already processed (circular reference)
+ if obj_id in memo:
+ return memo[obj_id]
+
+ # Create new instance and register immediately
+ new_list = self.__class__([])
+ memo[obj_id] = new_list
+
+ # Deep copy items
+ new_list._items[:] = [copy.deepcopy(item, memo) for item in self._items]
+
+ # Preserve frozen state
+ if self._frozen.load():
+ new_list.freeze()
+
+ return new_list
+
MutableSequence.register(FrozenList)
diff --git a/contrib/python/frozenlist/tests/test_frozenlist.py b/contrib/python/frozenlist/tests/test_frozenlist.py
index f7429ee6b07..c37f5c0db10 100644
--- a/contrib/python/frozenlist/tests/test_frozenlist.py
+++ b/contrib/python/frozenlist/tests/test_frozenlist.py
@@ -2,6 +2,7 @@
# mypy: disable-error-code="misc"
from collections.abc import MutableSequence
+from copy import deepcopy
import pytest
@@ -248,6 +249,129 @@ class FrozenListMixin:
_list = self.FrozenList([1, 2])
assert _list.count(1) == 1
+ def test_deepcopy_unfrozen(self) -> None:
+ orig = self.FrozenList([1, 2, 3])
+ copied = deepcopy(orig)
+ assert copied == orig
+ assert copied is not orig
+ assert list(copied) == list(orig)
+ assert not copied.frozen
+ # Verify the copy is mutable
+ copied.append(4)
+ assert len(copied) == 4
+ assert len(orig) == 3
+
+ def test_deepcopy_frozen(self) -> None:
+ orig = self.FrozenList([1, 2, 3])
+ orig.freeze()
+ copied = deepcopy(orig)
+ assert copied == orig
+ assert copied is not orig
+ assert list(copied) == list(orig)
+ assert copied.frozen
+ # Verify the copy is also frozen
+ with pytest.raises(RuntimeError):
+ copied.append(4)
+
+ def test_deepcopy_nested(self) -> None:
+ inner = self.FrozenList([1, 2])
+ orig = self.FrozenList([inner, 3])
+ copied = deepcopy(orig)
+ assert copied == orig
+ assert copied[0] is not orig[0]
+ assert isinstance(copied[0], self.FrozenList)
+ # Modify the inner list in the copy
+ copied[0].append(3)
+ assert len(copied[0]) == 3
+ assert len(orig[0]) == 2
+
+ def test_deepcopy_circular(self) -> None:
+ orig = self.FrozenList([1, 2])
+ orig.append(orig) # Create circular reference
+
+ copied = deepcopy(orig)
+
+ # Check structure is preserved
+ assert len(copied) == 3
+ assert copied[0] == 1
+ assert copied[1] == 2
+ assert copied[2] is copied # Circular reference preserved
+
+ # Verify they are different objects
+ assert copied is not orig
+ assert copied[2] is not orig
+
+ # Modify the copy
+ copied.append(3)
+ assert len(copied) == 4
+ assert len(orig) == 3
+
+ def test_deepcopy_circular_frozen(self) -> None:
+ orig = self.FrozenList([1, 2])
+ orig.append(orig) # Create circular reference
+ orig.freeze()
+
+ copied = deepcopy(orig)
+
+ # Check structure is preserved
+ assert len(copied) == 3
+ assert copied[0] == 1
+ assert copied[1] == 2
+ assert copied[2] is copied # Circular reference preserved
+ assert copied.frozen
+
+ # Verify frozen state
+ with pytest.raises(RuntimeError):
+ copied.append(3)
+
+ def test_deepcopy_nested_circular(self) -> None:
+ # Create a complex nested structure with circular references
+ inner1 = self.FrozenList([1, 2])
+ inner2 = self.FrozenList([3, 4])
+ orig = self.FrozenList([inner1, inner2])
+
+ # Add circular references
+ inner1.append(inner2) # inner1 -> inner2
+ inner2.append(orig) # inner2 -> orig (outer list)
+ orig.append(orig) # orig -> orig (self reference)
+
+ copied = deepcopy(orig)
+
+ # Verify structure
+ assert len(copied) == 3
+ assert isinstance(copied[0], self.FrozenList)
+ assert isinstance(copied[1], self.FrozenList)
+ assert copied[2] is copied # Self reference preserved
+
+ # Verify nested circular references
+ assert len(copied[0]) == 3
+ assert copied[0][2] is copied[1] # inner1 -> inner2 preserved
+ assert len(copied[1]) == 3
+ assert copied[1][2] is copied # inner2 -> orig preserved
+
+ # All objects should be new instances
+ assert copied is not orig
+ assert copied[0] is not orig[0]
+ assert copied[1] is not orig[1]
+
+ def test_deepcopy_multiple_references(self) -> None:
+ # Test that multiple references to the same object are preserved
+ shared = self.FrozenList([1, 2])
+ orig = self.FrozenList([shared, shared, 3])
+
+ copied = deepcopy(orig)
+
+ # Both references should point to the same copied object
+ assert copied[0] is copied[1]
+ assert copied[0] is not shared
+ assert isinstance(copied[0], self.FrozenList)
+
+ # Modify through one reference
+ copied[0].append(3)
+ assert len(copied[0]) == 3
+ assert len(copied[1]) == 3 # Should see the change
+ assert len(shared) == 2 # Original unchanged
+
class TestFrozenList(FrozenListMixin):
FrozenList = FrozenList # type: ignore[assignment] # FIXME
diff --git a/contrib/python/frozenlist/ya.make b/contrib/python/frozenlist/ya.make
index adc7b384a5f..d749776980f 100644
--- a/contrib/python/frozenlist/ya.make
+++ b/contrib/python/frozenlist/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(1.6.0)
+VERSION(1.7.0)
LICENSE(Apache-2.0)