diff options
| author | robot-piglet <[email protected]> | 2025-08-04 08:37:25 +0300 |
|---|---|---|
| committer | robot-piglet <[email protected]> | 2025-08-04 08:47:50 +0300 |
| commit | c569c2f61d37fbb5deccf1b0b19b874fc9dfe2b1 (patch) | |
| tree | 478e75412b64d3ac505a4adaa4691d718f75438d /contrib/python/frozenlist | |
| parent | 093752a2164d4bbe855bc009b02fde83f567a510 (diff) | |
Intermediate changes
commit_hash:eff2306ab69f70411903fc1110f59ea6d8b43a2d
Diffstat (limited to 'contrib/python/frozenlist')
| -rw-r--r-- | contrib/python/frozenlist/.dist-info/METADATA | 83 | ||||
| -rw-r--r-- | contrib/python/frozenlist/frozenlist/__init__.py | 2 | ||||
| -rw-r--r-- | contrib/python/frozenlist/frozenlist/_frozenlist.pyx | 24 | ||||
| -rw-r--r-- | contrib/python/frozenlist/tests/test_frozenlist.py | 124 | ||||
| -rw-r--r-- | contrib/python/frozenlist/ya.make | 2 |
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) |
