Package: src:joblib
Version: 1.5.3-2
User: [email protected]
Usertags: python3.15
Tags: patch, ftbfs, forky, sid

Hi!

While rebuilding the python related packages against the Python 3.15rc1
version we found that joblib fails to build from source [1].
In order to fix the issue, I had to:
- Run the tests in autopkg tests with the conftest file (Fixes #1140861)
- Backport loky's _decode_message function to support Python 3.14+
  (Fixes #1141207).
- Change the condition for using multiprocessing in the random parallel
  example (needs to be forwarded upstream).

I applied these fixes in the sandbox [2] to be able to build the
packages that depend on joblib, please consider applying the patch to
support the upcoming 3.15 version.

Happy hacking,

[1]: https://debusine.debian.net/debian/r-python-python3.15/artifact/4496152/
[2]: https://debusine.debian.net/debian/r-python-python3.15/

--
"Can you imagine what I would do if I could do all I can?" -- Sun Tzu
Saludos /\/\ /\ >< `/
diff -Nru joblib-1.5.3/debian/changelog joblib-1.5.3/debian/changelog
--- joblib-1.5.3/debian/changelog       2026-06-24 18:31:44.000000000 +0200
+++ joblib-1.5.3/debian/changelog       2026-09-02 16:13:04.000000000 +0200
@@ -1,3 +1,11 @@
+joblib (1.5.3-2.1) UNRELEASED; urgency=medium
+
+  * Non-maintainer upload.
+  * Add patch: forkserver-examples, to avoid hanging forkservers in the tests
+  * Backport loky's _decode_message
+
+ -- Maximiliano Curia <[email protected]>  Wed, 02 Sep 2026 16:13:04 +0200
+
 joblib (1.5.3-2) unstable; urgency=medium
 
   * Team upload.
diff -Nru joblib-1.5.3/debian/patches/forkserver-examples 
joblib-1.5.3/debian/patches/forkserver-examples
--- joblib-1.5.3/debian/patches/forkserver-examples     1970-01-01 
01:00:00.000000000 +0100
+++ joblib-1.5.3/debian/patches/forkserver-examples     2026-09-02 
16:13:04.000000000 +0200
@@ -0,0 +1,48 @@
+Description: Only use multiprocessing backend in examples when start method is 
fork
+ In Python 3.14+, multiprocessing defaults to the forkserver start method on
+ POSIX. When using the multiprocessing backend on top-level functions without
+ the fork start method, worker processes cannot deserialize the functions.
+Index: joblib/examples/parallel_random_state.py
+===================================================================
+--- joblib.orig/examples/parallel_random_state.py
++++ joblib/examples/parallel_random_state.py
+@@ -87,7 +87,7 @@ print_vector(random_vector, backend)
+ 
+ import multiprocessing as mp
+ 
+-if mp.get_start_method() != "spawn":
++if mp.get_start_method() == "fork":
+     backend = "multiprocessing"
+     random_vector = Parallel(n_jobs=2, backend=backend)(
+         delayed(stochastic_function)(10) for _ in range(n_vectors)
+@@ -115,7 +115,7 @@ def stochastic_function_seeded(max_value
+ # reset this seed by passing ``None`` at every function call. In this case, we
+ # see that the generated vectors are all different.
+ 
+-if mp.get_start_method() != "spawn":
++if mp.get_start_method() == "fork":
+     random_vector = Parallel(n_jobs=2, backend=backend)(
+         delayed(stochastic_function_seeded)(10, None) for _ in 
range(n_vectors)
+     )
+@@ -133,7 +133,7 @@ if mp.get_start_method() != "spawn":
+ #
+ # .. [1]  https://numpy.org/doc/stable/reference/random/parallel.html
+ 
+-if mp.get_start_method() != "spawn":
++if mp.get_start_method() == "fork":
+     seed = 42
+     random_vector = Parallel(n_jobs=2, backend=backend)(
+         delayed(stochastic_function_seeded)(10, [i, seed]) for i in 
range(n_vectors)
+Index: joblib/examples/serialization_and_wrappers.py
+===================================================================
+--- joblib.orig/examples/serialization_and_wrappers.py
++++ joblib/examples/serialization_and_wrappers.py
+@@ -68,7 +68,7 @@ print(
+ 
+ import multiprocessing as mp
+ 
+-if mp.get_start_method() != "spawn":
++if mp.get_start_method() == "fork":
+ 
+     def func_async(i, *args):
+         return 2 * i
diff -Nru joblib-1.5.3/debian/patches/py315-resource-tracker 
joblib-1.5.3/debian/patches/py315-resource-tracker
--- joblib-1.5.3/debian/patches/py315-resource-tracker  1970-01-01 
01:00:00.000000000 +0100
+++ joblib-1.5.3/debian/patches/py315-resource-tracker  2026-09-02 
16:13:04.000000000 +0200
@@ -0,0 +1,61 @@
+Description: Backport loky's _decode_message to support python 3.15
+Index: joblib/joblib/externals/loky/backend/resource_tracker.py
+===================================================================
+--- joblib.orig/joblib/externals/loky/backend/resource_tracker.py
++++ joblib/joblib/externals/loky/backend/resource_tracker.py
+@@ -38,6 +38,8 @@
+ # resources once all processes connected to the resource tracker have exited.
+ 
+ 
++import base64
++import json
+ import os
+ import shutil
+ import sys
+@@ -254,6 +256,30 @@ unregister = _resource_tracker.unregiste
+ getfd = _resource_tracker.getfd
+ 
+ 
++def _decode_message(line):
++    if line.startswith(b'{'):
++        try:
++            obj = json.loads(line.decode('ascii'))
++        except Exception as e:
++            raise ValueError("malformed resource_tracker message: %r" % 
(line,)) from e
++
++        cmd = obj["cmd"]
++        rtype = obj["rtype"]
++        b64  = obj.get("base64_name", "")
++
++        if not isinstance(cmd, str) or not isinstance(rtype, str) or not 
isinstance(b64, str):
++            raise ValueError("malformed resource_tracker fields: %r" % (obj,))
++
++        try:
++            name = base64.urlsafe_b64decode(b64).decode('utf-8', 
'surrogateescape')
++        except ValueError as e:
++            raise ValueError("malformed resource_tracker base64_name: %r" % 
(b64,)) from e
++    else:
++        cmd, rest = line.strip().decode('ascii').split(':', maxsplit=1)
++        name, rtype = rest.rsplit(':', maxsplit=1)
++    return cmd, rtype, name
++
++
+ def main(fd, verbose=0):
+     """Run resource tracker."""
+     if verbose:
+@@ -284,14 +310,7 @@ def main(fd, verbose=0):
+         with open(fd, "rb") as f:
+             for line in f:
+                 try:
+-                    splitted = line.strip().decode("ascii").split(":")
+-                    # name can potentially contain separator symbols (for
+-                    # instance folders on Windows)
+-                    cmd, name, rtype = (
+-                        splitted[0],
+-                        ":".join(splitted[1:-1]),
+-                        splitted[-1],
+-                    )
++                    cmd, name, rtype = _decode_message(line)
+ 
+                     if rtype not in _CLEANUP_FUNCS:
+                         raise ValueError(
diff -Nru joblib-1.5.3/debian/patches/series joblib-1.5.3/debian/patches/series
--- joblib-1.5.3/debian/patches/series  2026-06-24 16:57:28.000000000 +0200
+++ joblib-1.5.3/debian/patches/series  2026-09-02 16:13:04.000000000 +0200
@@ -4,3 +4,5 @@
 intersphinx-inventory
 deb_test_memory
 privacy
+forkserver-examples
+py315-resource-tracker
diff -Nru joblib-1.5.3/debian/tests/pytest joblib-1.5.3/debian/tests/pytest
--- joblib-1.5.3/debian/tests/pytest    2026-06-24 16:57:28.000000000 +0200
+++ joblib-1.5.3/debian/tests/pytest    2026-09-02 16:13:04.000000000 +0200
@@ -19,5 +19,5 @@
 
 for py in $(py3versions -s); do
        echo "Testing with $py:"
-       $py -m pytest -v -k "${TEST_KEYWORDS}" --pyargs joblib
+       $py -m pytest -v -k "${TEST_KEYWORDS}" -p conftest --pyargs joblib
 done
-- 
debian-science-maintainers mailing list
[email protected]
https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/debian-science-maintainers

Reply via email to