Your message dated Wed, 16 Sep 2026 21:49:08 +0000
with message-id <[email protected]>
and subject line Bug#1144864: fixed in pandas 2.3.3+dfsg-5
has caused the Debian Bug report #1144864,
regarding pandas: FTBFS building against python 3.15
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact [email protected]
immediately.)


-- 
1144864: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1144864
Debian Bug Tracking System
Contact [email protected] with problems
--- Begin Message ---
Package: src:pandas
Version: 3.0.5+dfsg-1
User: [email protected]
Usertags: python3.15
Tags: patch

Hi!

While rebuilding the Python related packages against the Python 3.15rc1
version we found that pandas fails to build from source[1]. The upstream
code already has fixes for these issues and since there are many
packages that require pandas to build I already applied these fixes in
the packages that are in the rebuild sandbox[2].

Please consider applying this patches in your next upload, or consider
updating pandas when a new release including these patches is available.

Happy hacking,

[1]: 
https://debusine.debian.net/debian/r-python-python3.15/work-request/1012982/
[2]: https://debusine.debian.net/debian/r-python-python3.15/

--
"recursividad 95, 154, 156, 201, 224, 293"
-- El Lenguaje de Programacion C, pag. 293 (Kernighan & Ritchie)
Saludos /\/\ /\ >< `/
Description: Python 3.15 compatibility fixes
 Backport of upstream commit 7bb284ac43 (PR #66473) for Python 3.15 support:
 - Support optional %z and %:z (colon_z) in strptime
 - Explicitly close XML iterparse parser to avoid unclosed iterator ResourceWarning
 - Accept Python 3.15 TypeError / ValueError error message changes in tests
 - Define and export PY315 in pandas.compat
Origin: upstream, https://github.com/pandas-dev/pandas/commit/7bb284ac438d2b981a7f42e3bdd0fe5ee26aada0
Bug: https://github.com/pandas-dev/pandas/issues/66473
Forwarded: not-needed

Index: pandas/pandas/_libs/tslibs/strptime.pyx
===================================================================
--- pandas.orig/pandas/_libs/tslibs/strptime.pyx
+++ pandas/pandas/_libs/tslibs/strptime.pyx
@@ -167,6 +167,7 @@ cdef dict _parse_code_table = {"y": 0,
                                "Z": 17,
                                "p": 18,  # an additional key, only with I
                                "z": 19,
+                               "colon_z": 24,
                                "G": 20,
                                "V": 21,
                                "u": 22}
@@ -178,7 +179,7 @@ cdef _validate_fmt(str fmt):
             raise ValueError("Cannot use '%W' or '%U' without day and year")
         if "%A" not in fmt and "%a" not in fmt and "%w" not in fmt:
             raise ValueError("Cannot use '%W' or '%U' without day and year")
-    elif "%Z" in fmt and "%z" in fmt:
+    elif "%Z" in fmt and ("%z" in fmt or "%:z" in fmt):
         raise ValueError("Cannot parse both %Z and %z")
     elif "%j" in fmt and "%G" in fmt:
         raise ValueError("Day of the year directive '%j' is not "
@@ -618,9 +619,19 @@ cdef tzinfo _parse_with_format(
                 f"time data \"{val}\" doesn't match format \"{fmt}\""
             )
         if len(val) != found.end():
+            rest = val[found.end():]
+            # Specific check for '%:z' directive
+            if (
+                "colon_z" in found.re.groupindex
+                and found.group("colon_z") is not None
+                and rest[0] != ":"
+            ):
+                raise ValueError(
+                    f"Missing colon in %:z before '{rest}', got '{val}'"
+                )
             raise ValueError(
                 "unconverted data remains when parsing with "
-                f"format \"{fmt}\": \"{val[found.end():]}\""
+                f"format \"{fmt}\": \"{rest}\""
             )
 
     else:
@@ -760,9 +771,15 @@ cdef tzinfo _parse_with_format(
         elif parse_code == 17:
             # e.g. val='2011-12-30T00:00:00.000000UTC'; fmt='%Y-%m-%dT%H:%M:%S.%f%Z'
             tz = zoneinfo.ZoneInfo(found_dict["Z"])
-        elif parse_code == 19:
+        # elif group_key in ('z', 'colon_z'):
+        elif parse_code == 19 or parse_code == 24:
             # e.g. val='March 1, 2018 12:00:00+0400'; fmt='%B %d, %Y %H:%M:%S%z'
-            tz = parse_timezone_directive(found_dict["z"])
+            if found_dict[group_key] is None:
+                raise ValueError(
+                    f"time data \"{val}\" doesn't match format \"{fmt}\""
+                )
+
+            tz = parse_timezone_directive(found_dict[group_key])
         elif parse_code == 20:
             # e.g. val='2015-1-7'; fmt='%G-%V-%u'
             iso_year = int(found_dict["G"])
Index: pandas/pandas/compat/__init__.py
===================================================================
--- pandas.orig/pandas/compat/__init__.py
+++ pandas/pandas/compat/__init__.py
@@ -21,6 +21,7 @@ from pandas.compat._constants import (
     ISMUSL,
     PY312,
     PY314,
+    PY315,
     PYPY,
     WASM,
 )
@@ -161,6 +162,7 @@ __all__ = [
     "ISMUSL",
     "PY312",
     "PY314",
+    "PY315",
     "PYARROW_INSTALLED",
     "PYARROW_MIN_VERSION",
     "PYPY",
Index: pandas/pandas/compat/_constants.py
===================================================================
--- pandas.orig/pandas/compat/_constants.py
+++ pandas/pandas/compat/_constants.py
@@ -15,6 +15,7 @@ IS64 = sys.maxsize > 2**32
 
 PY312 = sys.version_info >= (3, 12)
 PY314 = sys.version_info >= (3, 14)
+PY315 = sys.version_info >= (3, 15)
 PYPY = platform.python_implementation() == "PyPy"
 WASM = (sys.platform == "emscripten") or (platform.machine() in ["wasm32", "wasm64"])
 ISMUSL = "musl" in (sysconfig.get_config_var("HOST_GNU_TYPE") or "")
@@ -30,6 +31,7 @@ __all__ = [
     "ISMUSL",
     "PY312",
     "PY314",
+    "PY315",
     "PYPY",
     "WASM",
 ]
Index: pandas/pandas/io/xml.py
===================================================================
--- pandas.orig/pandas/io/xml.py
+++ pandas/pandas/io/xml.py
@@ -337,44 +337,53 @@ class _XMLFrameParser:
             set(self.iterparse[row_node])
         )
 
-        for event, elem in iterparse(self.path_or_buffer, events=("start", "end")):
-            curr_elem = elem.tag.split("}")[1] if "}" in elem.tag else elem.tag
-
-            if event == "start":
-                if curr_elem == row_node:
-                    row = {}
-
-            if row is not None:
-                if self.names and iterparse_repeats:
-                    for col, nm in zip(
-                        self.iterparse[row_node], self.names, strict=True
-                    ):
-                        if curr_elem == col:
-                            elem_val = elem.text if elem.text else None
-                            if elem_val not in row.values() and nm not in row:
-                                row[nm] = elem_val
-
-                        if col in elem.attrib:
-                            if elem.attrib[col] not in row.values() and nm not in row:
-                                row[nm] = elem.attrib[col]
-                else:
-                    for col in self.iterparse[row_node]:
-                        if curr_elem == col:
-                            row[col] = elem.text if elem.text else None
-                        if col in elem.attrib:
-                            row[col] = elem.attrib[col]
-
-            if event == "end":
-                if curr_elem == row_node and row is not None:
-                    dicts.append(row)
-                    row = None
-
-                elem.clear()
-                if hasattr(elem, "getprevious"):
-                    while (
-                        elem.getprevious() is not None and elem.getparent() is not None
-                    ):
-                        del elem.getparent()[0]
+        parser = iterparse(self.path_or_buffer, events=("start", "end"))
+        try:
+            for event, elem in parser:
+                curr_elem = elem.tag.split("}")[1] if "}" in elem.tag else elem.tag
+
+                if event == "start":
+                    if curr_elem == row_node:
+                        row = {}
+
+                if row is not None:
+                    if self.names and iterparse_repeats:
+                        for col, nm in zip(
+                            self.iterparse[row_node], self.names, strict=True
+                        ):
+                            if curr_elem == col:
+                                elem_val = elem.text if elem.text else None
+                                if elem_val not in row.values() and nm not in row:
+                                    row[nm] = elem_val
+
+                            if col in elem.attrib:
+                                if (
+                                    elem.attrib[col] not in row.values()
+                                    and nm not in row
+                                ):
+                                    row[nm] = elem.attrib[col]
+                    else:
+                        for col in self.iterparse[row_node]:
+                            if curr_elem == col:
+                                row[col] = elem.text if elem.text else None
+                            if col in elem.attrib:
+                                row[col] = elem.attrib[col]
+
+                if event == "end":
+                    if curr_elem == row_node and row is not None:
+                        dicts.append(row)
+                        row = None
+
+                    elem.clear()
+                    if hasattr(elem, "getprevious"):
+                        while (
+                            elem.getprevious() is not None
+                            and elem.getparent() is not None
+                        ):
+                            del elem.getparent()[0]
+        finally:
+            if hasattr(parser, "close"):
+                parser.close()
 
         if dicts == []:
             raise ParserError("No result from selected items in iterparse.")
Index: pandas/pandas/tests/extension/decimal/test_decimal.py
===================================================================
--- pandas.orig/pandas/tests/extension/decimal/test_decimal.py
+++ pandas/pandas/tests/extension/decimal/test_decimal.py
@@ -151,7 +151,12 @@ class TestDecimalArray(base.ExtensionTes
         # GH#57723
         # EAs that don't have special logic for None will raise, unlike pandas'
         # which interpret None as the NA value for the dtype.
-        msg = "conversion from NoneType to Decimal is not supported"
+        msg = "|".join(
+            [
+                "Cannot convert None to Decimal",  # PY315 - maybe linux specific
+                "conversion from NoneType to Decimal is not supported",
+            ]
+        )
         with pytest.raises(TypeError, match=msg):
             super().test_fillna_with_none(data_missing)
 
Index: pandas/pandas/tests/frame/indexing/test_indexing.py
===================================================================
--- pandas.orig/pandas/tests/frame/indexing/test_indexing.py
+++ pandas/pandas/tests/frame/indexing/test_indexing.py
@@ -12,6 +12,7 @@ import pytest
 from pandas._libs import iNaT
 from pandas.errors import InvalidIndexError
 
+from pandas.compat import PY315
 from pandas.core.dtypes.common import is_integer
 
 import pandas as pd
@@ -30,7 +31,10 @@ from pandas import (
 import pandas._testing as tm
 
 # We pass through a TypeError raised by numpy
-_slice_msg = "slice indices must be integers or None or have an __index__ method"
+if PY315:
+    _slice_msg = "slice indices must be integers or have an __index__ method"
+else:
+    _slice_msg = "slice indices must be integers or None or have an __index__ method"
 
 
 class TestDataFrameIndexing:
Index: pandas/pandas/tests/indexes/period/test_partial_slicing.py
===================================================================
--- pandas.orig/pandas/tests/indexes/period/test_partial_slicing.py
+++ pandas/pandas/tests/indexes/period/test_partial_slicing.py
@@ -1,6 +1,8 @@
 import numpy as np
 import pytest
 
+from pandas.compat import PY315
+
 from pandas import (
     DataFrame,
     PeriodIndex,
@@ -53,7 +55,10 @@ class TestPeriodIndex:
         # GH#6716
         idx = make_range(start="2013/01/01", freq="D", periods=400)
 
-        msg = "slice indices must be integers or None or have an __index__ method"
+        if PY315:
+            msg = "slice indices must be integers or have an __index__ method"
+        else:
+            msg = "slice indices must be integers or None or have an __index__ method"
         # slices against index should raise IndexError
         values = [
             "2014",
@@ -82,7 +87,10 @@ class TestPeriodIndex:
     def test_range_slice_seconds(self, make_range):
         # GH#6716
         idx = make_range(start="2013/01/01 09:00:00", freq="s", periods=4000)
-        msg = "slice indices must be integers or None or have an __index__ method"
+        if PY315:
+            msg = "slice indices must be integers or have an __index__ method"
+        else:
+            msg = "slice indices must be integers or None or have an __index__ method"
 
         # slices against index should raise IndexError
         values = [
Index: pandas/pandas/tests/indexes/test_old_base.py
===================================================================
--- pandas.orig/pandas/tests/indexes/test_old_base.py
+++ pandas/pandas/tests/indexes/test_old_base.py
@@ -7,6 +7,7 @@ import numpy as np
 import pytest
 
 from pandas._libs.tslibs import Timestamp
+from pandas.compat import PY315
 from pandas.errors import Pandas4Warning
 
 from pandas.core.dtypes.common import (
@@ -452,6 +453,8 @@ class TestBase:
         if len(index) == 0:
             # 0 vs 0.5 in error message varies with numpy version
             msg = "index (0|0.5) is out of bounds for axis 0 with size 0"
+        elif PY315:
+            msg = "slice indices must be integers or have an __index__ method"
         else:
             msg = "slice indices must be integers or None or have an __index__ method"
 
Index: pandas/pandas/tests/indexing/test_floats.py
===================================================================
--- pandas.orig/pandas/tests/indexing/test_floats.py
+++ pandas/pandas/tests/indexing/test_floats.py
@@ -1,6 +1,8 @@
 import numpy as np
 import pytest
 
+from pandas.compat import PY315
+
 from pandas import (
     DataFrame,
     Index,
@@ -251,7 +253,12 @@ class TestFloatIndexers:
         # setitem
         if indexer_sli is tm.iloc:
             # otherwise we keep the same message as above
-            msg = "slice indices must be integers or None or have an __index__ method"
+            if PY315:
+                msg = "slice indices must be integers or have an __index__ method"
+            else:
+                msg = (
+                    "slice indices must be integers or None or have an __index__ method"
+                )
         with pytest.raises(TypeError, match=msg):
             indexer_sli(s)[idx] = 0
 
Index: pandas/pandas/tests/scalar/timestamp/test_constructors.py
===================================================================
--- pandas.orig/pandas/tests/scalar/timestamp/test_constructors.py
+++ pandas/pandas/tests/scalar/timestamp/test_constructors.py
@@ -18,7 +18,10 @@ import pytest
 
 import pandas.util._test_decorators as td
 from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
-from pandas.compat import PY314
+from pandas.compat import (
+    PY314,
+    PY315,
+)
 from pandas.errors import (
     OutOfBoundsDatetime,
     Pandas4Warning,
@@ -240,7 +243,13 @@ class TestTimestampConstructorPositional
 
     def test_constructor_keyword(self):
         # GH#10758
-        msg = "function missing required argument 'day'|Required argument 'day'"
+        msg = "|".join(
+            [
+                r"datetime\(\) missing required argument 'day'",  # PY315
+                "function missing required argument 'day'",
+                "Required argument 'day'",
+            ]
+        )
         with pytest.raises(TypeError, match=msg):
             Timestamp(year=2000, month=1)
 
@@ -299,7 +308,15 @@ class TestTimestampConstructorPositional
         # GH#31200
 
         # The exact error message of datetime() depends on its version
-        msg1 = r"function missing required argument '(year|month|day)' \(pos [123]\)"
+        if PY315:
+            msg1 = (
+                r"datetime\(\) missing required argument "
+                r"'(year|month|day)' \(pos [123]\)"
+            )
+        else:
+            msg1 = (
+                r"function missing required argument '(year|month|day)' \(pos [123]\)"
+            )
         msg2 = r"Required argument '(year|month|day)' \(pos [123]\) not found"
         msg = "|".join([msg1, msg2])
 
Index: pandas/pandas/tests/tools/test_to_datetime.py
===================================================================
--- pandas.orig/pandas/tests/tools/test_to_datetime.py
+++ pandas/pandas/tests/tools/test_to_datetime.py
@@ -23,6 +23,7 @@ from pandas._libs.tslibs import (
 )
 from pandas.compat import (
     PY314,
+    PY315,
     WASM,
 )
 from pandas.errors import (
@@ -517,6 +518,39 @@ class TestTimeConversionFormats:
         expected = DatetimeIndex(expected_dates)
         tm.assert_index_equal(result, expected)
 
+    @pytest.mark.xfail(
+        not PY315, reason="%:z directive not supported prior to 3.15", raises=ValueError
+    )
+    def test_to_datetime_colon_z_offset(self):
+        dates = [
+            "2010-01-01 12:00:00+04:00",
+            "2010-01-01 12:00:00+04:30",
+            "2010-01-01 12:00:00-05:00",
+        ]
+        expected_dates = [
+            "2010-01-01 08:00:00+00:00",
+            "2010-01-01 07:30:00+00:00",
+            "2010-01-01 17:00:00+00:00",
+        ]
+        fmt = "%Y-%m-%d %H:%M:%S%:z"
+
+        result = to_datetime(dates, format=fmt, utc=True)
+        expected = DatetimeIndex(expected_dates)
+        tm.assert_index_equal(result, expected)
+
+    def test_to_datetime_missing_colon_z_offset(self):
+        # test adapted from python/cpython#136961
+        dates = ["+04:0030"]
+        fmt = "%:z"
+
+        if PY315:
+            msg = r"Missing colon in %:z before '30', got '\+04:0030'"
+        else:
+            msg = "':' is a bad directive in format '%:z'"
+
+        with pytest.raises(ValueError, match=msg):
+            to_datetime(dates, format=fmt, utc=True)
+
     @pytest.mark.parametrize(
         "offset", ["+0", "-1foo", "UTCbar", ":10", "+01:000:01", ""]
     )
@@ -1390,9 +1424,12 @@ class TestToDatetime:
     @pytest.mark.parametrize("errors", ["coerce", "raise"])
     def test_invalid_format_raises(self, errors):
         # https://github.com/pandas-dev/pandas/issues/50255
-        with pytest.raises(
-            ValueError, match="':' is a bad directive in format 'H%:M%:S%"
-        ):
+        if PY315:
+            msg = r"':M' is a bad directive in format 'H%:M%:S%"
+        else:
+            msg = "':' is a bad directive in format 'H%:M%:S%"
+
+        with pytest.raises(ValueError, match=msg):
             to_datetime(["00:00:00"], format="H%:M%:S%", errors=errors)
 
     @pytest.mark.parametrize("value", ["a", "00:01:99"])

Attachment: signature.asc
Description: PGP signature


--- End Message ---
--- Begin Message ---
Source: pandas
Source-Version: 2.3.3+dfsg-5
Done: Rebecca N. Palmer <[email protected]>

We believe that the bug you reported is fixed in the latest version of
pandas, which is due to be installed in the Debian FTP archive.

A summary of the changes between this version and the previous one is
attached.

Thank you for reporting the bug, which will now be closed.  If you
have further comments please address them to [email protected],
and the maintainer will reopen the bug report if appropriate.

Debian distribution maintenance software
pp.
Rebecca N. Palmer <[email protected]> (supplier of updated pandas package)

(This message was generated automatically at their request; if you
believe that there is a problem with it please contact the archive
administrators by mailing [email protected])


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

Format: 1.8
Date: Wed, 16 Sep 2026 20:30:23 +0100
Source: pandas
Architecture: source
Version: 2.3.3+dfsg-5
Distribution: unstable
Urgency: medium
Maintainer: Debian Science Maintainers 
<[email protected]>
Changed-By: Rebecca N. Palmer <[email protected]>
Closes: 1144864 1148010
Changes:
 pandas (2.3.3+dfsg-5) unstable; urgency=medium
 .
   * Be compatible with Python 3.15. (Closes: #1144864)
   * Reduce numerical instability in rolling var/skew/kurt.
   * Use 64-bit type in skiprows. (Closes: #1148010)
Checksums-Sha1:
 1c30c1e9c3c2712e8c5cffad115e379a28da2322 5624 pandas_2.3.3+dfsg-5.dsc
 98cd00cb06b7b783c7988bce026b3cdab653a546 121552 
pandas_2.3.3+dfsg-5.debian.tar.xz
 5bb176954dd0c6d66bb2e1e5a93ce1f514fcb19c 10123 
pandas_2.3.3+dfsg-5_source.buildinfo
Checksums-Sha256:
 ab3999f2260984471dadaaafe283c9bd2c27807f4dba5548f41ec6f400c26fd4 5624 
pandas_2.3.3+dfsg-5.dsc
 2a5657149fef567093c74eb07e1fddf6119a3a22c53a0eeb2e4d32372f3b41e4 121552 
pandas_2.3.3+dfsg-5.debian.tar.xz
 ccfac76017e04900f0822f3900c9881a3e80c60d19c3ddcbc74c1fa7accec7f6 10123 
pandas_2.3.3+dfsg-5_source.buildinfo
Files:
 f2bba7d14ee49e120ac84dfef1926011 5624 python optional pandas_2.3.3+dfsg-5.dsc
 cdf677bc8a0efef6251929aa8b3c1c25 121552 python optional 
pandas_2.3.3+dfsg-5.debian.tar.xz
 6380aa96ab0b53bf9c9865644685838f 10123 python optional 
pandas_2.3.3+dfsg-5_source.buildinfo

-----BEGIN PGP SIGNATURE-----

iQJMBAEBCgA2FiEEZ8sxEAXE7b4yF1MI3uUNDVZ+omYFAmqrAlEYHHJlYmVjY2Ff
cGFsbWVyQHpvaG8uY29tAAoJEN7lDQ1WfqJmPFkP/3lOe/gGWD1AUtjnuvRW5mNn
2eqNJQOldhXkSdeh5gVbB83bIn2vTg5hlqxHUO3anIwP+xVHrZFEx9BQ3GA4oqz1
8WSzxRSfaiFJHZcqjIn+NgLCYtGwLi3+SVa6LJfYVsYRMQFLPbX8dijwoYjS9UgO
HS2k5VpKQgye2ddmiOkXg3k0LgQ+IrXftth1MozqxkhrcrzRPirAiCyvVOmulNVI
0y/1q3bTpD+ervKWnbKi6kbiG+gb8Gh0A7h2HA7dqUrDJXmj43/L0d/vU45nPhLA
o6kFgzFw2maJih3sTlf+N5NSZGJA1p5x5czNCZDvUgvbQKiKYEe5QiSGMtbv+Z/P
EHSqlcE/l5C6M/SmPR8JIZmU5IYuO40xnZwxbMYXxzekEKu2bIE6rZoOuqIbyiXg
X1dXsK7NHL7FnKVYOjvy7WPmISxY1HYAqdLGi2j0C78e2SHjfybzcoVMTSSYFAWV
pzgHeBPFuGv/d/HBZCiuMHzdnLVozFRYSf5VmdlnvWfAKg7HzIUz1J6kIEx0Qqh3
jFu7y2S3wje/NSK3nKJWzl1bb5mQE2sg4RBfpObQIjknQiaXkFboMrnaVYyrngLE
TME9XviQvHCufUjpLa86qtmzhb20B8pP3pW19vUIDJD5GkNn/KNGoYOVqf/AN74k
92GXPlM9Cp4wnABEr9B5
=W4G+
-----END PGP SIGNATURE-----

Attachment: pgpUmHizeEpGV.pgp
Description: PGP signature


--- End Message ---
-- 
debian-science-maintainers mailing list
[email protected]
https://alioth-lists.debian.net/cgi-bin/mailman/listinfo/debian-science-maintainers

Reply via email to