Package: src:yarl
Version: 1.23.0-2
User: [email protected]
Usertags: python3.15

Hi!

While rebuilding packages against Python 3.15 we found that yarl failed
to build from source due to an incompatibility on the way pickle handles
__getstate__. This is already fixed upstream in the 1.24.0 release with
the commit: faaa1fd Fix pickling of URL on Python 3.15 (#1687)

I'm attaching a debdiff that adds this patch to the current version, as
that's what I've pushed to the Python 3.15 sandbox
(https://debusine.debian.net/debian/r-python-python3.15/) in order to be
able to keep building the packages that depend on yarl.

Please consider either applying the upstream fix or pushing the new
upstream release.

Happy hacking,
--
"Nothing ever goes away." -- Commoner's Law of Ecology
Saludos /\/\ /\ >< `/
diff -Nru yarl-1.23.0/debian/changelog yarl-1.23.0/debian/changelog
--- yarl-1.23.0/debian/changelog        2026-07-21 17:47:36.000000000 +0200
+++ yarl-1.23.0/debian/changelog        2026-08-15 23:19:46.000000000 +0200
@@ -1,3 +1,9 @@
+yarl (1.23.0-2.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+
+ -- Maximiliano Curia <[email protected]>  Sat, 15 Aug 2026 23:19:46 +0200
+
 yarl (1.23.0-2) unstable; urgency=medium
 
   * Team upload.
diff -Nru yarl-1.23.0/debian/patches/fix-pickling-of-url-on-python-315.patch 
yarl-1.23.0/debian/patches/fix-pickling-of-url-on-python-315.patch
--- yarl-1.23.0/debian/patches/fix-pickling-of-url-on-python-315.patch  
1970-01-01 01:00:00.000000000 +0100
+++ yarl-1.23.0/debian/patches/fix-pickling-of-url-on-python-315.patch  
2026-08-15 23:19:46.000000000 +0200
@@ -0,0 +1,88 @@
+commit faaa1fdd975220810dffb91adad87d589931d5b8
+Author: aio-libs bot <[email protected]>
+Date:   Sun May 17 06:57:50 2026 -0700
+
+    Fix pickling of URL on Python 3.15 (#1687)
+
+diff --git a/CHANGES/1632.bugfix.rst b/CHANGES/1632.bugfix.rst
+new file mode 100644
+index 0000000..0e857c5
+--- /dev/null
++++ b/CHANGES/1632.bugfix.rst
+@@ -0,0 +1,7 @@
++Fixed pickling of :class:`~yarl.URL` on Python 3.15, where ``SplitResult``
++gained a ``__getstate__`` that requires attributes set by ``__init__``.
++``__getstate__`` now returns the raw 5-tuple instead of a ``SplitResult``
++built via ``tuple.__new__``, so pickling no longer touches ``SplitResult``
++serialization at all. Pickles produced by older yarl releases (which embed
++a ``SplitResult``) continue to load unchanged
++-- by :user:`aiolibsbot`.
+diff --git a/tests/test_pickle.py b/tests/test_pickle.py
+index c3630f6..6939664 100644
+--- a/tests/test_pickle.py
++++ b/tests/test_pickle.py
+@@ -1,4 +1,5 @@
+ import pickle
++from urllib.parse import SplitResult
+ 
+ from yarl import URL
+ 
+@@ -58,3 +59,36 @@ def test_pickle_does_not_pollute_cache() -> None:
+     # for empty args.
+     assert URL().scheme == ""
+     assert URL("").scheme == ""
++
++
++def test_pickle_legacy_splitresult_state() -> None:
++    """Pickles produced by older yarl releases embedded a ``SplitResult``.
++
++    Loading such bytes must still rebuild the URL so users upgrading from
++    pre-fix versions do not lose access to their stored data.
++    """
++    val = ("http", "example.com", "/p", "q=1", "frag")
++    legacy_state = (tuple.__new__(SplitResult, val),)
++    u = URL.__new__(URL)
++    u.__setstate__(legacy_state)
++    assert u._scheme == "http"
++    assert u._netloc == "example.com"
++    assert u._path == "/p"
++    assert u._query == "q=1"
++    assert u._fragment == "frag"
++
++
++def test_pickle_getstate_returns_plain_tuple() -> None:
++    """Regression test for gh-1632.
++
++    Python 3.15 added a ``SplitResult.__getstate__`` that touches instance
++    attributes set by ``__init__``. yarl previously embedded a ``SplitResult``
++    built via ``tuple.__new__``, bypassing init, which made pickling crash.
++    ``__getstate__`` must return a plain ``tuple`` so pickling never invokes
++    ``SplitResult.__getstate__``.
++    """
++    u = URL("http://example.com/path?q=1#frag";)
++    state = u.__getstate__()
++    assert len(state) == 1
++    assert type(state[0]) is tuple
++    assert state[0] == ("http", "example.com", "/path", "q=1", "frag")
+diff --git a/yarl/_url.py b/yarl/_url.py
+index aec8d2b..5a661a4 100644
+--- a/yarl/_url.py
++++ b/yarl/_url.py
+@@ -566,8 +566,15 @@ class URL:
+     def __bool__(self) -> bool:
+         return bool(self._netloc or self._path or self._query or 
self._fragment)
+ 
+-    def __getstate__(self) -> tuple[SplitResult]:
+-        return (tuple.__new__(SplitResult, self._val),)
++    def __getstate__(self) -> tuple[SplitURLType]:
++        # Return a plain tuple rather than a ``SplitResult``. Constructing a
++        # ``SplitResult`` via ``tuple.__new__`` skips its ``__init__`` and on
++        # Python 3.15+ leaves ``_keep_empty`` unset, which breaks pickling: 
the
++        # new ``SplitResult.__getstate__`` indexes a state that ends up as
++        # ``None`` (gh-1632). ``__setstate__`` already unpacks both shapes, so
++        # pickles produced by older yarl releases (which embed a real
++        # ``SplitResult``) still load correctly.
++        return (self._val,)
+ 
+     def __setstate__(
+         self, state: tuple[SplitURLType] | tuple[None, _InternalURLCache]
diff -Nru yarl-1.23.0/debian/patches/series yarl-1.23.0/debian/patches/series
--- yarl-1.23.0/debian/patches/series   2026-07-21 17:34:50.000000000 +0200
+++ yarl-1.23.0/debian/patches/series   2026-08-15 23:19:46.000000000 +0200
@@ -4,3 +4,4 @@
 0004-disable-privacy-breach-links-in-documentation.patch
 0005-drop-towncrier-changelog-generation-for-now.patch
 0006-use-os.path.expandvars-instead-of-external-one.patch
+fix-pickling-of-url-on-python-315.patch

Attachment: signature.asc
Description: PGP signature

Reply via email to