Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-joblib for openSUSE:Factory 
checked in at 2026-02-26 18:49:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-joblib (Old)
 and      /work/SRC/openSUSE:Factory/.python-joblib.new.29461 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-joblib"

Thu Feb 26 18:49:58 2026 rev:32 rq:1334686 version:1.5.3

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-joblib/python-joblib.changes      
2025-09-11 14:39:29.712189070 +0200
+++ /work/SRC/openSUSE:Factory/.python-joblib.new.29461/python-joblib.changes   
2026-02-26 18:50:00.428909034 +0100
@@ -1,0 +2,16 @@
+Tue Feb 24 09:57:31 UTC 2026 - Daniel Garcia <[email protected]>
+
+- Update to 1.5.3
+  * The ``Memory`` object won't overwrite an already existing
+    ``.gitignore`` file in its cache directory anymore.
+  * Harden the safety checks in ``eval_expr(pre_dispatch)`` to prevent
+    excessive memory allocation and potential crashes by limiting the
+    allowed length of the expression and the maximum numeric value of
+    sub-expressions and not evaluating expressions with non-numeric
+    literals.
+  * Vendor cloudpickle 3.1.2 to fix a pickling problem with
+    interactively defined abstract base classes and type annotations
+    in Python 3.14+.
+- Add fix-tests-numpy-2.4.patch upstream patch gh#joblib/joblib#1770
+
+-------------------------------------------------------------------

Old:
----
  joblib-1.5.2.tar.gz

New:
----
  fix-tests-numpy-2.4.patch
  joblib-1.5.3.tar.gz

----------(New B)----------
  New:    in Python 3.14+.
- Add fix-tests-numpy-2.4.patch upstream patch gh#joblib/joblib#1770
----------(New E)----------

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-joblib.spec ++++++
--- /var/tmp/diff_new_pack.WhiE56/_old  2026-02-26 18:50:01.756964417 +0100
+++ /var/tmp/diff_new_pack.WhiE56/_new  2026-02-26 18:50:01.760964584 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-joblib
 #
-# Copyright (c) 2025 SUSE LLC
+# Copyright (c) 2026 SUSE LLC and contributors
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -18,7 +18,7 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-joblib
-Version:        1.5.2
+Version:        1.5.3
 Release:        0
 Summary:        Module for using Python functions as pipeline jobs
 License:        BSD-3-Clause
@@ -27,6 +27,8 @@
 # PATCH-FIX-OPENSUSE Also avoid a DeprecationWarning when using fork() under
 # multiprocessing
 Patch1:         also-filter-new-fork-warning.patch
+# PATCH-FIX-UPSTREAM fix-tests-numpy-2.4.patch gh#joblib/joblib#1770
+Patch2:         fix-tests-numpy-2.4.patch
 BuildRequires:  %{python_module base >= 3.7}
 BuildRequires:  %{python_module lz4}
 BuildRequires:  %{python_module numpy}

++++++ fix-tests-numpy-2.4.patch ++++++
>From c559b8feace27e24767f4b2cf84025bf1acdc2bd Mon Sep 17 00:00:00 2001
From: Nanored4498 <[email protected]>
Date: Thu, 8 Jan 2026 17:21:11 +0100
Subject: [PATCH 1/8] repare CI

---
 joblib/test/test_numpy_pickle.py | 54 ++++++++++++++++++++++----------
 1 file changed, 37 insertions(+), 17 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index ed320497b..b648f53c3 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -416,6 +416,22 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
                 if (re.search("_0.1.+.pkl$", filename_base) and mmap_mode is 
not None)
                 else 0
             )
+
+            if np.__version__.split(".") >= "2.4.0".split("."):
+                prefix = "joblib_"
+                version_index = filename_base.find(prefix) + len(prefix)
+                joblib_version = filename_base[version_index:]
+
+                def check_version(v):
+                    return joblib_version.startswith(v)
+
+                if check_version("0.9."):
+                    expected_nb_user_warnings += 1
+                    if "compressed" in filename_base:
+                        expected_nb_user_warnings += 2
+                elif check_version("0.10.") or check_version("0.11."):
+                    expected_nb_user_warnings += 4
+
             expected_nb_warnings = (
                 expected_nb_deprecation_warnings + expected_nb_user_warnings
             )
@@ -425,23 +441,27 @@ def _check_pickle(filename, expected_list, 
mmap_mode=None):
                 f"{[w.message for w in warninfo]}"
             )
 
-            deprecation_warnings = [
-                w for w in warninfo if issubclass(w.category, 
DeprecationWarning)
-            ]
-            user_warnings = [w for w in warninfo if issubclass(w.category, 
UserWarning)]
-            for w in deprecation_warnings:
-                assert (
-                    str(w.message)
-                    == "The file '{0}' has been generated with a joblib "
-                    "version less than 0.10. Please regenerate this "
-                    "pickle file.".format(filename)
-                )
-
-            for w in user_warnings:
-                escaped_filename = re.escape(filename)
-                assert re.search(
-                    f"memmapped.+{escaped_filename}.+segmentation fault", 
str(w.message)
-                )
+            for w in warninfo:
+                if issubclass(w.category, DeprecationWarning):
+                    assert (
+                        str(w.message)
+                        == "The file '{0}' has been generated with a joblib "
+                        "version less than 0.10. Please regenerate this "
+                        "pickle file.".format(filename)
+                    )
+                elif issubclass(w.category, 
np.exceptions.VisibleDeprecationWarning):
+                    assert (
+                        str(w.message)
+                        == "dtype(): align should be passed as Python or NumPy 
"
+                        "boolean but got `align=0`. Did you mean to pass a 
tuple "
+                        "to create a subarray type? (Deprecated NumPy 2.4)"
+                    )
+                elif issubclass(w.category, UserWarning):
+                    escaped_filename = re.escape(filename)
+                    assert re.search(
+                        f"memmapped.+{escaped_filename}.+segmentation fault",
+                        str(w.message),
+                    )
 
             for result, expected in zip(result_list, expected_list):
                 if isinstance(expected, np.ndarray):

>From 05f9f53475514af65bc181529624712bb8163502 Mon Sep 17 00:00:00 2001
From: Nanored4498 <[email protected]>
Date: Fri, 9 Jan 2026 10:20:42 +0100
Subject: [PATCH 2/8] Better version check

---
 joblib/test/test_numpy_pickle.py | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index b648f53c3..1f84e6f7b 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -16,6 +16,8 @@
 from contextlib import closing
 from pathlib import Path
 
+from packaging.version import Version
+
 try:
     import lzma
 except ImportError:
@@ -417,7 +419,11 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
                 else 0
             )
 
-            if np.__version__.split(".") >= "2.4.0".split("."):
+            # Account for the VisibleDeprecationWarning raised by
+            # numpy 2.4+ with align been of the wrong type
+            numpyDepreciationWarning = False
+            if Version(np.__version__) >= Version("2.4.0"):
+                numpyDepreciationWarning = True
                 prefix = "joblib_"
                 version_index = filename_base.find(prefix) + len(prefix)
                 joblib_version = filename_base[version_index:]
@@ -429,7 +435,7 @@ def check_version(v):
                     expected_nb_user_warnings += 1
                     if "compressed" in filename_base:
                         expected_nb_user_warnings += 2
-                elif check_version("0.10.") or check_version("0.11."):
+                else:
                     expected_nb_user_warnings += 4
 
             expected_nb_warnings = (
@@ -449,7 +455,9 @@ def check_version(v):
                         "version less than 0.10. Please regenerate this "
                         "pickle file.".format(filename)
                     )
-                elif issubclass(w.category, 
np.exceptions.VisibleDeprecationWarning):
+                elif numpyDepreciationWarning and issubclass(
+                    w.category, np.exceptions.VisibleDeprecationWarning
+                ):
                     assert (
                         str(w.message)
                         == "dtype(): align should be passed as Python or NumPy 
"
@@ -462,6 +470,8 @@ def check_version(v):
                         f"memmapped.+{escaped_filename}.+segmentation fault",
                         str(w.message),
                     )
+                else:
+                    raise Exception(f"No warning of type {w.category} is 
expected")
 
             for result, expected in zip(result_list, expected_list):
                 if isinstance(expected, np.ndarray):

>From e1817d9d9b4ad88d98ad1b3c83fb48db9136eb63 Mon Sep 17 00:00:00 2001
From: Thomas Moreau <[email protected]>
Date: Fri, 9 Jan 2026 11:09:48 +0100
Subject: [PATCH 3/8] CLN clarify numpy deprecation warning handling

---
 joblib/test/test_numpy_pickle.py | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index 1f84e6f7b..bce9e08c6 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -421,9 +421,9 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
 
             # Account for the VisibleDeprecationWarning raised by
             # numpy 2.4+ with align been of the wrong type
-            numpyDepreciationWarning = False
+            check_numpy_depreciation_warning = False
             if Version(np.__version__) >= Version("2.4.0"):
-                numpyDepreciationWarning = True
+                check_numpy_depreciation_warning = True
                 prefix = "joblib_"
                 version_index = filename_base.find(prefix) + len(prefix)
                 joblib_version = filename_base[version_index:]
@@ -455,7 +455,13 @@ def check_version(v):
                         "version less than 0.10. Please regenerate this "
                         "pickle file.".format(filename)
                     )
-                elif numpyDepreciationWarning and issubclass(
+                elif issubclass(w.category, UserWarning):
+                    escaped_filename = re.escape(filename)
+                    assert re.search(
+                        f"memmapped.+{escaped_filename}.+segmentation fault",
+                        str(w.message),
+                    )
+                elif check_numpy_depreciation_warning and issubclass(
                     w.category, np.exceptions.VisibleDeprecationWarning
                 ):
                     assert (
@@ -464,12 +470,6 @@ def check_version(v):
                         "boolean but got `align=0`. Did you mean to pass a 
tuple "
                         "to create a subarray type? (Deprecated NumPy 2.4)"
                     )
-                elif issubclass(w.category, UserWarning):
-                    escaped_filename = re.escape(filename)
-                    assert re.search(
-                        f"memmapped.+{escaped_filename}.+segmentation fault",
-                        str(w.message),
-                    )
                 else:
                     raise Exception(f"No warning of type {w.category} is 
expected")
 

>From 2c513ace44928b05c264a5be0d9e809b5c35a501 Mon Sep 17 00:00:00 2001
From: Thomas Moreau <[email protected]>
Date: Fri, 9 Jan 2026 11:11:13 +0100
Subject: [PATCH 4/8] Update joblib/test/test_numpy_pickle.py

---
 joblib/test/test_numpy_pickle.py | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index bce9e08c6..7e68b9942 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -428,10 +428,7 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
                 version_index = filename_base.find(prefix) + len(prefix)
                 joblib_version = filename_base[version_index:]
 
-                def check_version(v):
-                    return joblib_version.startswith(v)
-
-                if check_version("0.9."):
+                if joblib_version.startswith("0.9."):
                     expected_nb_user_warnings += 1
                     if "compressed" in filename_base:
                         expected_nb_user_warnings += 2

>From 65d1da5c582bf99032481a4d0b65ce7ce0640fba Mon Sep 17 00:00:00 2001
From: Thomas Moreau <[email protected]>
Date: Fri, 9 Jan 2026 11:16:12 +0100
Subject: [PATCH 5/8] Restore UserWarning check in test_numpy_pickle

Reintroduce UserWarning check for segmentation fault.
---
 joblib/test/test_numpy_pickle.py | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index 7e68b9942..3970fe535 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -452,12 +452,6 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
                         "version less than 0.10. Please regenerate this "
                         "pickle file.".format(filename)
                     )
-                elif issubclass(w.category, UserWarning):
-                    escaped_filename = re.escape(filename)
-                    assert re.search(
-                        f"memmapped.+{escaped_filename}.+segmentation fault",
-                        str(w.message),
-                    )
                 elif check_numpy_depreciation_warning and issubclass(
                     w.category, np.exceptions.VisibleDeprecationWarning
                 ):
@@ -467,6 +461,12 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
                         "boolean but got `align=0`. Did you mean to pass a 
tuple "
                         "to create a subarray type? (Deprecated NumPy 2.4)"
                     )
+                elif issubclass(w.category, UserWarning):
+                    escaped_filename = re.escape(filename)
+                    assert re.search(
+                        f"memmapped.+{escaped_filename}.+segmentation fault",
+                        str(w.message),
+                    )
                 else:
                     raise Exception(f"No warning of type {w.category} is 
expected")
 

>From 0979956337eb5f76c08ee4aeafd0597c6c83aefa Mon Sep 17 00:00:00 2001
From: Nanored4498 <[email protected]>
Date: Fri, 9 Jan 2026 16:02:06 +0100
Subject: [PATCH 6/8] now ignore VisibleDeprecationWarning

---
 joblib/test/test_numpy_pickle.py | 62 +++++++++++++-------------------
 1 file changed, 24 insertions(+), 38 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index 3970fe535..cb6a7d878 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -16,8 +16,6 @@
 from contextlib import closing
 from pathlib import Path
 
-from packaging.version import Version
-
 try:
     import lzma
 except ImportError:
@@ -407,68 +405,56 @@ def _check_pickle(filename, expected_list, 
mmap_mode=None):
         try:
             with warnings.catch_warnings(record=True) as warninfo:
                 warnings.simplefilter("always")
+                # Ignore VisibleDeprecationWarning raised by
+                # numpy 2.4+ with align been of the wrong type
+                if hasattr(np, "exceptions") and hasattr(
+                    np.exceptions, "VisibleDeprecationWarning"
+                ):
+                    warnings.filterwarnings(
+                        "ignore", 
category=np.exceptions.VisibleDeprecationWarning
+                    )
                 result_list = numpy_pickle.load(filename, mmap_mode=mmap_mode)
+
             filename_base = os.path.basename(filename)
             expected_nb_deprecation_warnings = (
                 1 if ("_0.9" in filename_base or "_0.8.4" in filename_base) 
else 0
             )
+            deprecation_warnings = []
 
             expected_nb_user_warnings = (
                 3
                 if (re.search("_0.1.+.pkl$", filename_base) and mmap_mode is 
not None)
                 else 0
             )
-
-            # Account for the VisibleDeprecationWarning raised by
-            # numpy 2.4+ with align been of the wrong type
-            check_numpy_depreciation_warning = False
-            if Version(np.__version__) >= Version("2.4.0"):
-                check_numpy_depreciation_warning = True
-                prefix = "joblib_"
-                version_index = filename_base.find(prefix) + len(prefix)
-                joblib_version = filename_base[version_index:]
-
-                if joblib_version.startswith("0.9."):
-                    expected_nb_user_warnings += 1
-                    if "compressed" in filename_base:
-                        expected_nb_user_warnings += 2
-                else:
-                    expected_nb_user_warnings += 4
-
-            expected_nb_warnings = (
-                expected_nb_deprecation_warnings + expected_nb_user_warnings
-            )
-            assert len(warninfo) == expected_nb_warnings, (
-                "Did not get the expected number of warnings. Expected "
-                f"{expected_nb_warnings} but got warnings: "
-                f"{[w.message for w in warninfo]}"
-            )
+            user_warnings = []
 
             for w in warninfo:
                 if issubclass(w.category, DeprecationWarning):
+                    deprecation_warnings.append(w.message)
                     assert (
                         str(w.message)
                         == "The file '{0}' has been generated with a joblib "
                         "version less than 0.10. Please regenerate this "
                         "pickle file.".format(filename)
                     )
-                elif check_numpy_depreciation_warning and issubclass(
-                    w.category, np.exceptions.VisibleDeprecationWarning
-                ):
-                    assert (
-                        str(w.message)
-                        == "dtype(): align should be passed as Python or NumPy 
"
-                        "boolean but got `align=0`. Did you mean to pass a 
tuple "
-                        "to create a subarray type? (Deprecated NumPy 2.4)"
-                    )
                 elif issubclass(w.category, UserWarning):
+                    user_warnings.append(w.message)
                     escaped_filename = re.escape(filename)
                     assert re.search(
                         f"memmapped.+{escaped_filename}.+segmentation fault",
                         str(w.message),
                     )
-                else:
-                    raise Exception(f"No warning of type {w.category} is 
expected")
+
+            assert len(deprecation_warnings) == 
expected_nb_deprecation_warnings, (
+                "Did not get the expected number of deprecation warnings. "
+                f"Expected {expected_nb_deprecation_warnings} "
+                "but got warnings: {deprecation_warnings}"
+            )
+            assert len(user_warnings) == expected_nb_user_warnings, (
+                "Did not get the expected number of user warnings. "
+                f"Expected {expected_nb_user_warnings} "
+                "but got warnings: {user_warnings}"
+            )
 
             for result, expected in zip(result_list, expected_list):
                 if isinstance(expected, np.ndarray):

>From eb4dbaab32e07053eaf4f17055c232992d0e62ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= <[email protected]>
Date: Mon, 12 Jan 2026 07:07:49 +0100
Subject: [PATCH 7/8] Simpler strategy

---
 joblib/test/test_numpy_pickle.py | 66 ++++++++++++++------------------
 1 file changed, 29 insertions(+), 37 deletions(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index cb6a7d878..a6920b035 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -405,57 +405,49 @@ def _check_pickle(filename, expected_list, 
mmap_mode=None):
         try:
             with warnings.catch_warnings(record=True) as warninfo:
                 warnings.simplefilter("always")
-                # Ignore VisibleDeprecationWarning raised by
-                # numpy 2.4+ with align been of the wrong type
-                if hasattr(np, "exceptions") and hasattr(
-                    np.exceptions, "VisibleDeprecationWarning"
-                ):
-                    warnings.filterwarnings(
-                        "ignore", 
category=np.exceptions.VisibleDeprecationWarning
-                    )
+                # Ignore numpy >= 2.4 warning when load old pickle where
+                # align=0 but it should be a Python or Numpy boolean
+                warnings.filterwarnings(
+                    "ignore", message=".+align should be 
passed.+boolean.+align=0"
+                )
                 result_list = numpy_pickle.load(filename, mmap_mode=mmap_mode)
-
             filename_base = os.path.basename(filename)
             expected_nb_deprecation_warnings = (
                 1 if ("_0.9" in filename_base or "_0.8.4" in filename_base) 
else 0
             )
-            deprecation_warnings = []
 
             expected_nb_user_warnings = (
                 3
                 if (re.search("_0.1.+.pkl$", filename_base) and mmap_mode is 
not None)
                 else 0
             )
-            user_warnings = []
-
-            for w in warninfo:
-                if issubclass(w.category, DeprecationWarning):
-                    deprecation_warnings.append(w.message)
-                    assert (
-                        str(w.message)
-                        == "The file '{0}' has been generated with a joblib "
-                        "version less than 0.10. Please regenerate this "
-                        "pickle file.".format(filename)
-                    )
-                elif issubclass(w.category, UserWarning):
-                    user_warnings.append(w.message)
-                    escaped_filename = re.escape(filename)
-                    assert re.search(
-                        f"memmapped.+{escaped_filename}.+segmentation fault",
-                        str(w.message),
-                    )
-
-            assert len(deprecation_warnings) == 
expected_nb_deprecation_warnings, (
-                "Did not get the expected number of deprecation warnings. "
-                f"Expected {expected_nb_deprecation_warnings} "
-                "but got warnings: {deprecation_warnings}"
+            expected_nb_warnings = (
+                expected_nb_deprecation_warnings + expected_nb_user_warnings
             )
-            assert len(user_warnings) == expected_nb_user_warnings, (
-                "Did not get the expected number of user warnings. "
-                f"Expected {expected_nb_user_warnings} "
-                "but got warnings: {user_warnings}"
+            assert len(warninfo) == expected_nb_warnings, (
+                "Did not get the expected number of warnings. Expected "
+                f"{expected_nb_warnings} but got warnings: "
+                f"{[w.message for w in warninfo]}"
             )
 
+            deprecation_warnings = [
+                w for w in warninfo if issubclass(w.category, 
DeprecationWarning)
+            ]
+            user_warnings = [w for w in warninfo if issubclass(w.category, 
UserWarning)]
+            for w in deprecation_warnings:
+                assert (
+                    str(w.message)
+                    == "The file '{0}' has been generated with a joblib "
+                    "version less than 0.10. Please regenerate this "
+                    "pickle file.".format(filename)
+                )
+
+            for w in user_warnings:
+                escaped_filename = re.escape(filename)
+                assert re.search(
+                    f"memmapped.+{escaped_filename}.+segmentation fault", 
str(w.message)
+                )
+
             for result, expected in zip(result_list, expected_list):
                 if isinstance(expected, np.ndarray):
                     expected = _ensure_native_byte_order(expected)

>From afc24f82511b8f536e0344c98a722c73081fedf0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Lo=C3=AFc=20Est=C3=A8ve?= <[email protected]>
Date: Mon, 12 Jan 2026 07:08:42 +0100
Subject: [PATCH 8/8] Tweak wording

---
 joblib/test/test_numpy_pickle.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/joblib/test/test_numpy_pickle.py b/joblib/test/test_numpy_pickle.py
index a6920b035..af4214edc 100644
--- a/joblib/test/test_numpy_pickle.py
+++ b/joblib/test/test_numpy_pickle.py
@@ -405,7 +405,7 @@ def _check_pickle(filename, expected_list, mmap_mode=None):
         try:
             with warnings.catch_warnings(record=True) as warninfo:
                 warnings.simplefilter("always")
-                # Ignore numpy >= 2.4 warning when load old pickle where
+                # Ignore numpy >= 2.4 warning when loading old pickles, where
                 # align=0 but it should be a Python or Numpy boolean
                 warnings.filterwarnings(
                     "ignore", message=".+align should be 
passed.+boolean.+align=0"

++++++ joblib-1.5.2.tar.gz -> joblib-1.5.3.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/PKG-INFO new/joblib-1.5.3/PKG-INFO
--- old/joblib-1.5.2/PKG-INFO   2025-08-27 14:15:21.971439800 +0200
+++ new/joblib-1.5.3/PKG-INFO   2025-12-15 09:41:26.185438900 +0100
@@ -1,9 +1,9 @@
 Metadata-Version: 2.4
 Name: joblib
-Version: 1.5.2
+Version: 1.5.3
 Summary: Lightweight pipelining with Python functions
 Author-email: Gael Varoquaux <[email protected]>
-License: BSD 3-Clause
+License-Expression: BSD-3-Clause
 Project-URL: Homepage, https://joblib.readthedocs.io
 Project-URL: Source, https://github.com/joblib/joblib
 Platform: any
@@ -12,7 +12,6 @@
 Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: Science/Research
 Classifier: Intended Audience :: Education
-Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/doc/conftest.py 
new/joblib-1.5.3/doc/conftest.py
--- old/joblib-1.5.2/doc/conftest.py    2025-08-27 14:15:17.000000000 +0200
+++ new/joblib-1.5.3/doc/conftest.py    2025-12-15 09:41:21.000000000 +0100
@@ -1,16 +1,20 @@
 import faulthandler
 
+import pytest
+
 from joblib.parallel import mp
 from joblib.test.common import np
-from joblib.testing import fixture, skipif
+from joblib.testing import fixture
 
 
 @fixture(scope="module")
-@skipif(np is None or mp is None, "Numpy or Multiprocessing not available")
 def parallel_numpy_fixture(request):
     """Fixture to skip memmapping test if numpy or multiprocessing is not
     installed"""
 
+    if np is None or mp is None:
+        pytest.skip("Numpy or Multiprocessing not available")
+
     def setup(module):
         faulthandler.dump_traceback_later(timeout=300, exit=True)
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib/__init__.py 
new/joblib-1.5.3/joblib/__init__.py
--- old/joblib-1.5.2/joblib/__init__.py 2025-08-27 14:15:17.000000000 +0200
+++ new/joblib-1.5.3/joblib/__init__.py 2025-12-15 09:41:21.000000000 +0100
@@ -106,7 +106,7 @@
 # Dev branch marker is: 'X.Y.dev' or 'X.Y.devN' where N is an integer.
 # 'X.Y.dev0' is the canonical version of 'X.Y.dev'
 #
-__version__ = "1.5.2"
+__version__ = "1.5.3"
 
 
 import os
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib/_store_backends.py 
new/joblib-1.5.3/joblib/_store_backends.py
--- old/joblib-1.5.2/joblib/_store_backends.py  2025-08-27 14:15:17.000000000 
+0200
+++ new/joblib-1.5.3/joblib/_store_backends.py  2025-12-15 09:41:21.000000000 
+0100
@@ -474,9 +474,14 @@
             if os.path.dirname(location) and os.path.basename(location) == 
"joblib"
             else location
         )
-        with open(os.path.join(cache_directory, ".gitignore"), "w") as file:
-            file.write("# Created by joblib automatically.\n")
-            file.write("*\n")
+        gitignore = os.path.join(cache_directory, ".gitignore")
+        if not os.path.exists(gitignore):
+            try:
+                with open(gitignore, "w") as file:
+                    file.write("# Created by joblib automatically.\n")
+                    file.write("*\n")
+            except OSError as e:
+                warnings.warn(f"Unable to write {gitignore}. Exception: {e}.")
 
         # item can be stored compressed for faster I/O
         self.compress = backend_options.get("compress", False)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib/_utils.py 
new/joblib-1.5.3/joblib/_utils.py
--- old/joblib-1.5.2/joblib/_utils.py   2025-08-27 14:15:17.000000000 +0200
+++ new/joblib-1.5.3/joblib/_utils.py   2025-12-15 09:41:21.000000000 +0100
@@ -1,6 +1,7 @@
 # Adapted from https://stackoverflow.com/a/9558001/2536294
 
 import ast
+import functools
 import operator as op
 from dataclasses import dataclass
 
@@ -24,24 +25,60 @@
 
 
 def eval_expr(expr):
-    """
+    """Somewhat safely evaluate an arithmetic expression.
+
     >>> eval_expr('2*6')
     12
     >>> eval_expr('2**6')
     64
     >>> eval_expr('1 + 2*3**(4) / (6 + -7)')
     -161.0
+
+    Raises ValueError if the expression is invalid, too long
+    or its computation involves too large values.
     """
+    # Restrict the length of the expression to avoid potential Python crashes
+    # as per the documentation of ast.parse.
+    max_length = 30
+    if len(expr) > max_length:
+        raise ValueError(
+            f"Expression {expr[:max_length]!r}... is too long. "
+            f"Max length is {max_length}, got {len(expr)}."
+        )
     try:
         return eval_(ast.parse(expr, mode="eval").body)
-    except (TypeError, SyntaxError, KeyError) as e:
+    except (TypeError, SyntaxError, OverflowError, KeyError) as e:
         raise ValueError(
             f"{expr!r} is not a valid or supported arithmetic expression."
         ) from e
 
 
+def limit(max_=None):
+    """Return decorator that limits allowed returned values."""
+
+    def decorator(func):
+        @functools.wraps(func)
+        def wrapper(*args, **kwargs):
+            ret = func(*args, **kwargs)
+            try:
+                mag = abs(ret)
+            except TypeError:
+                pass  # not applicable
+            else:
+                if mag > max_:
+                    raise ValueError(
+                        f"Numeric literal {ret} is too large, max is {max_}."
+                    )
+            return ret
+
+        return wrapper
+
+    return decorator
+
+
+@limit(max_=10**6)
 def eval_(node):
-    if isinstance(node, ast.Constant):  # <constant>
+    if isinstance(node, ast.Constant) and isinstance(node.value, (int, float)):
         return node.value
     elif isinstance(node, ast.BinOp):  # <left> <operator> <right>
         return operators[type(node.op)](eval_(node.left), eval_(node.right))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/joblib-1.5.2/joblib/externals/cloudpickle/__init__.py 
new/joblib-1.5.3/joblib/externals/cloudpickle/__init__.py
--- old/joblib-1.5.2/joblib/externals/cloudpickle/__init__.py   2025-08-27 
14:15:17.000000000 +0200
+++ new/joblib-1.5.3/joblib/externals/cloudpickle/__init__.py   2025-12-15 
09:41:21.000000000 +0100
@@ -3,7 +3,7 @@
 
 __doc__ = cloudpickle.__doc__
 
-__version__ = "3.1.1"
+__version__ = "3.1.2"
 
 __all__ = [  # noqa
     "__version__",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/joblib-1.5.2/joblib/externals/cloudpickle/cloudpickle.py 
new/joblib-1.5.3/joblib/externals/cloudpickle/cloudpickle.py
--- old/joblib-1.5.2/joblib/externals/cloudpickle/cloudpickle.py        
2025-08-27 14:15:17.000000000 +0200
+++ new/joblib-1.5.3/joblib/externals/cloudpickle/cloudpickle.py        
2025-12-15 09:41:21.000000000 +0100
@@ -783,6 +783,12 @@
 
     clsdict.pop("__dict__", None)  # unpicklable property object
 
+    if sys.version_info >= (3, 14):
+        # PEP-649/749: __annotate_func__ contains a closure that references 
the class
+        # dict. We need to exclude it from pickling. Python will recreate it 
when
+        # __annotations__ is accessed at unpickling time.
+        clsdict.pop("__annotate_func__", None)
+
     return (clsdict, {})
 
 
@@ -1190,6 +1196,10 @@
         for subclass in registry:
             obj.register(subclass)
 
+    # PEP-649/749: During pickling, we excluded the __annotate_func__ 
attribute but it
+    # will be created by Python. Subsequently, annotations will be recreated 
when
+    # __annotations__ is accessed.
+
     return obj
 
 
@@ -1301,12 +1311,9 @@
     def dump(self, obj):
         try:
             return super().dump(obj)
-        except RuntimeError as e:
-            if len(e.args) > 0 and "recursion" in e.args[0]:
-                msg = "Could not pickle object as excessively deep recursion 
required."
-                raise pickle.PicklingError(msg) from e
-            else:
-                raise
+        except RecursionError as e:
+            msg = "Could not pickle object as excessively deep recursion 
required."
+            raise pickle.PicklingError(msg) from e
 
     def __init__(self, file, protocol=None, buffer_callback=None):
         if protocol is None:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/joblib-1.5.2/joblib/test/_openmp_test_helper/setup.py 
new/joblib-1.5.3/joblib/test/_openmp_test_helper/setup.py
--- old/joblib-1.5.2/joblib/test/_openmp_test_helper/setup.py   2025-08-27 
14:15:17.000000000 +0200
+++ new/joblib-1.5.3/joblib/test/_openmp_test_helper/setup.py   2025-12-15 
09:41:21.000000000 +0100
@@ -2,10 +2,10 @@
 
 import os
 import sys
-from distutils.core import setup
-from distutils.extension import Extension
 
 from Cython.Build import cythonize
+from setuptools import setup
+from setuptools.extension import Extension
 
 if sys.platform == "darwin":
     os.environ["CC"] = "gcc-4.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib/test/test_memory.py 
new/joblib-1.5.3/joblib/test/test_memory.py
--- old/joblib-1.5.2/joblib/test/test_memory.py 2025-08-27 14:15:17.000000000 
+0200
+++ new/joblib-1.5.3/joblib/test/test_memory.py 2025-12-15 09:41:21.000000000 
+0100
@@ -12,12 +12,12 @@
 import logging
 import os
 import os.path
-import pathlib
 import pickle
 import shutil
 import sys
 import textwrap
 import time
+from pathlib import Path
 
 import pytest
 
@@ -1264,7 +1264,7 @@
 
 def test_instanciate_store_backend_with_pathlib_path():
     # Instantiate a FileSystemStoreBackend using a pathlib.Path object
-    path = pathlib.Path("some_folder")
+    path = Path("some_folder")
     backend_obj = _store_backend_factory("local", path)
     try:
         assert backend_obj.location == "some_folder"
@@ -1547,31 +1547,36 @@
         )
 
 
-@with_numpy
-@parametrize(
-    "location",
-    [
-        "test_cache_dir",
-        pathlib.Path("test_cache_dir"),
-        pathlib.Path("test_cache_dir").resolve(),
-    ],
-)
-def test_memory_creates_gitignore(location):
-    """Test that using the memory object automatically creates a `.gitignore` 
file
-    within the new cache directory."""
-
-    mem = Memory(location)
-    arr = np.asarray([[1, 2, 3], [4, 5, 6]])
-    costly_operation = mem.cache(np.square)
-    costly_operation(arr)
+class TestAutoGitignore:
+    "Tests for the MemorizedFunc and NotMemorizedFunc classes"
 
-    location = pathlib.Path(location)
+    def test_memory_creates_gitignore(self, tmpdir):
+        """Test that using the memory object automatically creates a 
`.gitignore` file
+        within the new cache directory."""
 
-    try:
-        path_to_gitignore_file = os.path.join(location, ".gitignore")
-        gitignore_file_content = "# Created by joblib automatically.\n*\n"
-        with open(path_to_gitignore_file) as f:
-            assert gitignore_file_content == f.read()
+        location = Path(tmpdir.mkdir("test_cache_dir"))
 
-    finally:  # remove cache folder after test
-        shutil.rmtree(location, ignore_errors=True)
+        mem = Memory(location)
+        costly_operation = mem.cache(id)
+        costly_operation(0)
+
+        gitignore_file = location / ".gitignore"
+        assert gitignore_file.exists()
+        assert gitignore_file.read_text() == "# Created by joblib 
automatically.\n*\n"
+
+    def test_memory_does_not_overwrite_existing_gitignore(self, tmpdir):
+        """Test that using the memory object does not overwrite an existing
+        `.gitignore` file within the cache directory."""
+
+        location = Path(tmpdir.mkdir("test_cache_dir"))
+        gitignore_file = location / ".gitignore"
+
+        existing_content = "# Existing .gitignore file!"
+        gitignore_file.write_text(existing_content)
+
+        # Cache a function and call it.
+        mem = Memory(location)
+        mem.cache(id)(0)
+
+        assert gitignore_file.exists()
+        assert gitignore_file.read_text() == existing_content
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib/test/test_utils.py 
new/joblib-1.5.3/joblib/test/test_utils.py
--- old/joblib-1.5.2/joblib/test/test_utils.py  2025-08-27 14:15:17.000000000 
+0200
+++ new/joblib-1.5.3/joblib/test/test_utils.py  2025-12-15 09:41:21.000000000 
+0100
@@ -5,13 +5,33 @@
 
 @pytest.mark.parametrize(
     "expr",
-    ["exec('import os')", "print(1)", "import os", "1+1; import os", "1^1"],
+    [
+        "exec('import os')",
+        "print(1)",
+        "import os",
+        "1+1; import os",
+        "1^1",
+        "' ' * 10**10",
+        "9. ** 10000.",
+    ],
 )
 def test_eval_expr_invalid(expr):
     with pytest.raises(ValueError, match="is not a valid or supported 
arithmetic"):
         eval_expr(expr)
 
 
+def test_eval_expr_too_long():
+    expr = "1" + "+1" * 50
+    with pytest.raises(ValueError, match="is too long"):
+        eval_expr(expr)
+
+
[email protected]("expr", ["1e7", "10**7", "9**9**9"])
+def test_eval_expr_too_large_literal(expr):
+    with pytest.raises(ValueError, match="Numeric literal .* is too large"):
+        eval_expr(expr)
+
+
 @pytest.mark.parametrize(
     "expr, result",
     [
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/joblib.egg-info/PKG-INFO 
new/joblib-1.5.3/joblib.egg-info/PKG-INFO
--- old/joblib-1.5.2/joblib.egg-info/PKG-INFO   2025-08-27 14:15:21.000000000 
+0200
+++ new/joblib-1.5.3/joblib.egg-info/PKG-INFO   2025-12-15 09:41:26.000000000 
+0100
@@ -1,9 +1,9 @@
 Metadata-Version: 2.4
 Name: joblib
-Version: 1.5.2
+Version: 1.5.3
 Summary: Lightweight pipelining with Python functions
 Author-email: Gael Varoquaux <[email protected]>
-License: BSD 3-Clause
+License-Expression: BSD-3-Clause
 Project-URL: Homepage, https://joblib.readthedocs.io
 Project-URL: Source, https://github.com/joblib/joblib
 Platform: any
@@ -12,7 +12,6 @@
 Classifier: Intended Audience :: Developers
 Classifier: Intended Audience :: Science/Research
 Classifier: Intended Audience :: Education
-Classifier: License :: OSI Approved :: BSD License
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3.9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/joblib-1.5.2/pyproject.toml 
new/joblib-1.5.3/pyproject.toml
--- old/joblib-1.5.2/pyproject.toml     2025-08-27 14:15:17.000000000 +0200
+++ new/joblib-1.5.3/pyproject.toml     2025-12-15 09:41:21.000000000 +0100
@@ -1,11 +1,11 @@
 [build-system]
-requires = ["setuptools>=61.2"]
+requires = ["setuptools>=77.0.3"]
 build-backend = "setuptools.build_meta"
 
 [project]
 name = "joblib"
 authors = [{name = "Gael Varoquaux", email = "[email protected]"}]
-license = {text = "BSD 3-Clause"}
+license = "BSD-3-Clause"
 description = "Lightweight pipelining with Python functions"
 classifiers = [
     "Development Status :: 5 - Production/Stable",
@@ -13,7 +13,6 @@
     "Intended Audience :: Developers",
     "Intended Audience :: Science/Research",
     "Intended Audience :: Education",
-    "License :: OSI Approved :: BSD License",
     "Operating System :: OS Independent",
     "Programming Language :: Python :: 3",
     "Programming Language :: Python :: 3.9",
@@ -48,6 +47,7 @@
 ]
 platforms = ["any"]
 include-package-data = false
+license-files = ["LICENSE.txt"]
 
 [tool.setuptools.package-data]
 "joblib.test" = [

Reply via email to