diff --git a/python-pandas.changes b/python-pandas.changes index a8443b7..3ee9fdf 100644 --- a/python-pandas.changes +++ b/python-pandas.changes @@ -1,3 +1,13 @@ +------------------------------------------------------------------- +Mon Sep 16 19:39:38 UTC 2024 - Markéta Machová + +- Add bunch of patches to fix the testsuite with NumPy 2.1 + * tests-wasm.patch + * tests-nomkl.patch + * tests-timedelta.patch + * tests-npdev.patch +- Skip one test failing with new timezone, the patch would be too big + ------------------------------------------------------------------- Sun Sep 8 10:02:47 UTC 2024 - Ben Greiner diff --git a/python-pandas.spec b/python-pandas.spec index 07d8d52..1923afe 100644 --- a/python-pandas.spec +++ b/python-pandas.spec @@ -77,6 +77,14 @@ Patch2: pandas-pr58484-matplotlib.patch Patch3: https://github.com/pandas-dev/pandas/pull/59175.patch#/pandas-pr59175-matplotlib.patch # PATCH-FIX-UPSTREAM pandas-pr59353-np2eval.patch -- gh#pandas-dev/pandas#59144 backported to 2.2, no new tests, see gh#pandas-dev/pandas#58548, gh#pandas-dev/pandas#59353 Patch4: pandas-pr59353-np2eval.patch +# PATCH-FIX-UPSTREAM gh#pandas-dev/pandas#2536d3a7 +Patch5: tests-npdev.patch +# PATCH-FIX-UPSTREAM gh#pandas-dev/pandas#d0cb2056 +Patch6: tests-timedelta.patch +# PATCH-FIX-UPSTREAM gh#pandas-dev/pandas#1044cf44 +Patch7: tests-nomkl.patch +# PATCH-FIX-UPSTREAM tiny part of gh#pandas-dev/pandas#4f743f98 +Patch8: tests-wasm.patch %if !%{with test} BuildRequires: %{python_module Cython >= 3.0.5} BuildRequires: %{python_module devel >= 3.9} @@ -520,6 +528,8 @@ SKIP_TESTS+=" or (test_scalar_unary and numexpr-pandas)" %endif # Numpy2: unexpected 'np.str_(...)' in error message SKIP_TESTS+=" or test_group_subplot_invalid_column_name" +# https://github.com/pandas-dev/pandas/pull/55901, not gonna merge this huge patch to fix one test failing with new timezone, will be included in new release +SKIP_TESTS+=" or test_array_inference[data7-expected7]" %ifarch %{ix86} %{arm32} # https://github.com/pandas-dev/pandas/issues/31856 diff --git a/tests-nomkl.patch b/tests-nomkl.patch new file mode 100644 index 0000000..8e1d38b --- /dev/null +++ b/tests-nomkl.patch @@ -0,0 +1,100 @@ +From 1044cf442109953987c1a47f476dc90d286b9f0f Mon Sep 17 00:00:00 2001 +From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> +Date: Tue, 20 Aug 2024 10:32:23 -1000 +Subject: [PATCH] CI: Uninstall nomkl & 32 bit Interval tests (#59553) + +* undo numpy 2 changes? + +* some interval 32 bit tests working + +* Revert "undo numpy 2 changes?" + +This reverts commit 39ce2229a96406edac107fc897e807251d364e2b. + +* nomkl? + +* nomkl? + +* Update .github/actions/build_pandas/action.yml + +* grep for nomkl + +* xfail WASM + +* Reverse condition +--- + .github/actions/build_pandas/action.yml | 7 +++++++ + pandas/tests/indexes/interval/test_interval_tree.py | 7 +++++-- + pandas/tests/indexing/interval/test_interval.py | 4 ++-- + pandas/tests/indexing/interval/test_interval_new.py | 4 ++-- + 4 files changed, 16 insertions(+), 6 deletions(-) + +diff --git a/pandas/tests/indexes/interval/test_interval_tree.py b/pandas/tests/indexes/interval/test_interval_tree.py +index 49b17f8b3d40e..df9c3b390f660 100644 +--- a/pandas/tests/indexes/interval/test_interval_tree.py ++++ b/pandas/tests/indexes/interval/test_interval_tree.py +@@ -4,7 +4,10 @@ + import pytest + + from pandas._libs.interval import IntervalTree +-from pandas.compat import IS64 ++from pandas.compat import ( ++ IS64, ++ WASM, ++) + + import pandas._testing as tm + +@@ -186,7 +189,7 @@ def test_construction_overflow(self): + expected = (50 + np.iinfo(np.int64).max) / 2 + assert result == expected + +- @pytest.mark.xfail(not IS64, reason="GH 23440") ++ @pytest.mark.xfail(WASM, reason="GH 23440") + @pytest.mark.parametrize( + "left, right, expected", + [ +diff --git a/pandas/tests/indexing/interval/test_interval.py b/pandas/tests/indexing/interval/test_interval.py +index b72ef57475305..6bcebefa6c696 100644 +--- a/pandas/tests/indexing/interval/test_interval.py ++++ b/pandas/tests/indexing/interval/test_interval.py +@@ -2,7 +2,7 @@ + import pytest + + from pandas._libs import index as libindex +-from pandas.compat import IS64 ++from pandas.compat import WASM + + import pandas as pd + from pandas import ( +@@ -210,7 +210,7 @@ def test_mi_intervalindex_slicing_with_scalar(self): + expected = Series([1, 6, 2, 8, 7], index=expected_index, name="value") + tm.assert_series_equal(result, expected) + +- @pytest.mark.xfail(not IS64, reason="GH 23440") ++ @pytest.mark.xfail(WASM, reason="GH 23440") + @pytest.mark.parametrize( + "base", + [101, 1010], +diff --git a/pandas/tests/indexing/interval/test_interval_new.py b/pandas/tests/indexing/interval/test_interval_new.py +index 4c1efe9e4f81d..051dc7b98f2aa 100644 +--- a/pandas/tests/indexing/interval/test_interval_new.py ++++ b/pandas/tests/indexing/interval/test_interval_new.py +@@ -3,7 +3,7 @@ + import numpy as np + import pytest + +-from pandas.compat import IS64 ++from pandas.compat import WASM + + from pandas import ( + Index, +@@ -214,7 +214,7 @@ def test_loc_getitem_missing_key_error_message( + obj.loc[[4, 5, 6]] + + +-@pytest.mark.xfail(not IS64, reason="GH 23440") ++@pytest.mark.xfail(WASM, reason="GH 23440") + @pytest.mark.parametrize( + "intervals", + [ diff --git a/tests-npdev.patch b/tests-npdev.patch new file mode 100644 index 0000000..c5edcd4 --- /dev/null +++ b/tests-npdev.patch @@ -0,0 +1,75 @@ +From 2536d3a736eea96b9da8b774e671516eb8f25f4a Mon Sep 17 00:00:00 2001 +From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> +Date: Wed, 24 Apr 2024 07:26:56 -1000 +Subject: [PATCH] CI: Fix npdev failures (#58389) + +* CI: Fix npdev failures + +* Use unique index, make array writable + +* Update pandas/_libs/hashtable_class_helper.pxi.in + +* Update pandas/tests/arrays/test_datetimelike.py + +* Update pandas/tests/arrays/test_datetimelike.py +--- + pandas/tests/arrays/test_datetimelike.py | 8 ++++++-- + pandas/tests/extension/base/missing.py | 2 ++ + pandas/tests/indexes/test_base.py | 4 ++-- + 3 files changed, 10 insertions(+), 4 deletions(-) + +diff --git a/pandas/tests/arrays/test_datetimelike.py b/pandas/tests/arrays/test_datetimelike.py +index 22c63af59a47c..3d8f8d791b763 100644 +--- a/pandas/tests/arrays/test_datetimelike.py ++++ b/pandas/tests/arrays/test_datetimelike.py +@@ -661,7 +661,9 @@ def test_array_interface(self, datetime_index): + assert result is expected + tm.assert_numpy_array_equal(result, expected) + result = np.array(arr, dtype="datetime64[ns]") +- assert result is not expected ++ if not np_version_gt2: ++ # TODO: GH 57739 ++ assert result is not expected + tm.assert_numpy_array_equal(result, expected) + + # to object dtype +@@ -976,7 +978,9 @@ def test_array_interface(self, timedelta_index): + assert result is expected + tm.assert_numpy_array_equal(result, expected) + result = np.array(arr, dtype="timedelta64[ns]") +- assert result is not expected ++ if not np_version_gt2: ++ # TODO: GH 57739 ++ assert result is not expected + tm.assert_numpy_array_equal(result, expected) + + # to object dtype +diff --git a/pandas/tests/extension/base/missing.py b/pandas/tests/extension/base/missing.py +index 4b9234a9904a2..cee565d4f7c1e 100644 +--- a/pandas/tests/extension/base/missing.py ++++ b/pandas/tests/extension/base/missing.py +@@ -27,7 +27,9 @@ def test_isna_returns_copy(self, data_missing, na_func): + expected = result.copy() + mask = getattr(result, na_func)() + if isinstance(mask.dtype, pd.SparseDtype): ++ # TODO: GH 57739 + mask = np.array(mask) ++ mask.flags.writeable = True + + mask[:] = True + tm.assert_series_equal(result, expected) +diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py +index 04858643d97b1..2e94961b673f8 100644 +--- a/pandas/tests/indexes/test_base.py ++++ b/pandas/tests/indexes/test_base.py +@@ -71,8 +71,8 @@ def test_constructor_casting(self, index): + tm.assert_contains_all(arr, new_index) + tm.assert_index_equal(index, new_index) + +- @pytest.mark.parametrize("index", ["string"], indirect=True) +- def test_constructor_copy(self, index, using_infer_string): ++ def test_constructor_copy(self, using_infer_string): ++ index = Index(list("abc"), name="name") + arr = np.array(index) + new_index = Index(arr, copy=True, name="name") + assert isinstance(new_index, Index) diff --git a/tests-timedelta.patch b/tests-timedelta.patch new file mode 100644 index 0000000..1484e66 --- /dev/null +++ b/tests-timedelta.patch @@ -0,0 +1,55 @@ +From d0cb2056d0b27080b2f5cc0b88db8d263f684230 Mon Sep 17 00:00:00 2001 +From: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> +Date: Wed, 7 Aug 2024 10:49:25 -1000 +Subject: [PATCH] COMPAT: Fix numpy 2.1 timedelta * DateOffset (#59441) + +--- + pandas/core/arrays/timedeltas.py | 8 ++++++++ + pandas/tests/arithmetic/test_timedelta64.py | 8 +++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/pandas/core/arrays/timedeltas.py b/pandas/core/arrays/timedeltas.py +index 15bfe442ca87f..83cc2871f5459 100644 +--- a/pandas/core/arrays/timedeltas.py ++++ b/pandas/core/arrays/timedeltas.py +@@ -467,6 +467,10 @@ def __mul__(self, other) -> Self: + if is_scalar(other): + # numpy will accept float and int, raise TypeError for others + result = self._ndarray * other ++ if result.dtype.kind != "m": ++ # numpy >= 2.1 may not raise a TypeError ++ # and seems to dispatch to others.__rmul__? ++ raise TypeError(f"Cannot multiply with {type(other).__name__}") + freq = None + if self.freq is not None and not isna(other): + freq = self.freq * other +@@ -494,6 +498,10 @@ def __mul__(self, other) -> Self: + + # numpy will accept float or int dtype, raise TypeError for others + result = self._ndarray * other ++ if result.dtype.kind != "m": ++ # numpy >= 2.1 may not raise a TypeError ++ # and seems to dispatch to others.__rmul__? ++ raise TypeError(f"Cannot multiply with {type(other).__name__}") + return type(self)._simple_new(result, dtype=result.dtype) + + __rmul__ = __mul__ +diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py +index 4583155502374..87e085fb22878 100644 +--- a/pandas/tests/arithmetic/test_timedelta64.py ++++ b/pandas/tests/arithmetic/test_timedelta64.py +@@ -1460,7 +1460,13 @@ def test_td64arr_mul_int(self, box_with_array): + def test_td64arr_mul_tdlike_scalar_raises(self, two_hours, box_with_array): + rng = timedelta_range("1 days", "10 days", name="foo") + rng = tm.box_expected(rng, box_with_array) +- msg = "argument must be an integer|cannot use operands with types dtype" ++ msg = "|".join( ++ [ ++ "argument must be an integer", ++ "cannot use operands with types dtype", ++ "Cannot multiply with", ++ ] ++ ) + with pytest.raises(TypeError, match=msg): + rng * two_hours + diff --git a/tests-wasm.patch b/tests-wasm.patch new file mode 100644 index 0000000..fdcb6b3 --- /dev/null +++ b/tests-wasm.patch @@ -0,0 +1,138 @@ +From 4f743f98649ce1fc17a57f7b02d81f7cc172dff6 Mon Sep 17 00:00:00 2001 +From: Agriya Khetarpal <74401230+agriyakhetarpal@users.noreply.github.com> +Date: Wed, 8 May 2024 22:21:57 +0530 +Subject: [PATCH] BLD, TST: Build and test Pyodide wheels for `pandas` in CI + (#57896) + +* Create initial Pyodide workflow + +* Do not import pandas folder from the repo + +* Install hypothesis for testing + +* Add pytest decorator to skip tests on WASM + +* Skip `time.tzset()` tests on WASM platforms + +* Skip file system access tests on WASM + +* Skip two more tzset test failures + +* Skip two more FS failures on WASM + +* Resolve last two tzset failures on WASM + +* Add a `WASM` constant for Emscripten platform checks + +* Fix floating point imprecision with `np.timedelta64` + +* Mark tz OverflowError as xfail on WASM + +* Try to fix OverflowError with date ranges + +* Move job to unit tests workflow, withdraw env vars + +* Fix up a few style errors, use WASM variable + +* Bump Pyodide to `0.25.1` + +See https://github.com/pyodide/pyodide/pull/4654 for +more discussion. This commit resolves a build error +coming from the `pyodide build` command which +broke due to a new `build` release by PyPA. + +* Use shorter job name + +* Skip test where warning is not raised properly + +* Don't run `test_date_time` loc check on WASM + +* Don't run additional loc checks in `test_sas7bdat` + +* Disable WASM OverflowError + +* Skip tests requiring fp exception support + +* xfail tests that require stricter tolerances + +* xfail test where `OverflowError`s are received + +* Remove upper-pin from `pydantic` + +* Better skip messages via `pytest.skipif` decorator + +* Import `WASM` var via public API where possible + +* Unpin `pytest` for Pyodide job + +* Add reason attr when using boolean to skip test + +* Don't xfail, skip tests that bring `OverflowError`s + +* Skip timedelta test that runs well only on 64-bit + +* Skip tests that use `np.timedelta64` + +--------- + +Co-authored-by: Matthew Roeschke <10647082+mroeschke@users.noreply.github.com> +--- + .github/workflows/unit-tests.yml | 61 ++++++++++++++++++- + pandas/compat/__init__.py | 2 + + pandas/compat/_constants.py | 2 + + pandas/tests/apply/test_str.py | 3 + + pandas/tests/arithmetic/test_timedelta64.py | 2 + + .../datetimes/methods/test_normalize.py | 4 ++ + .../datetimes/methods/test_resolution.py | 8 ++- + .../io/parser/common/test_file_buffer_url.py | 3 + + pandas/tests/io/parser/test_c_parser_only.py | 21 ++++--- + pandas/tests/io/sas/test_sas7bdat.py | 9 ++- + pandas/tests/io/test_common.py | 10 ++- + pandas/tests/io/xml/test_xml.py | 2 + + .../scalar/timestamp/methods/test_replace.py | 3 + + .../methods/test_timestamp_method.py | 3 + + pandas/tests/scalar/timestamp/test_formats.py | 3 + + pandas/tests/tools/test_to_datetime.py | 6 +- + pandas/tests/tools/test_to_timedelta.py | 6 +- + pandas/tests/tseries/offsets/test_common.py | 8 ++- + pandas/tests/tslibs/test_parsing.py | 2 + + pandas/util/_test_decorators.py | 5 ++ + 20 files changed, 146 insertions(+), 17 deletions(-) + +diff --git a/pandas/compat/__init__.py b/pandas/compat/__init__.py +index 572dd8c9b61a0..4583e7edebbdc 100644 +--- a/pandas/compat/__init__.py ++++ b/pandas/compat/__init__.py +@@ -22,6 +22,7 @@ + PY311, + PY312, + PYPY, ++ WASM, + ) + import pandas.compat.compressors + from pandas.compat.numpy import is_numpy_dev +@@ -207,4 +208,5 @@ def get_bz2_file() -> type[pandas.compat.compressors.BZ2File]: + "PY311", + "PY312", + "PYPY", ++ "WASM", + ] +diff --git a/pandas/compat/_constants.py b/pandas/compat/_constants.py +index 7bc3fbaaefebf..2625389e5254a 100644 +--- a/pandas/compat/_constants.py ++++ b/pandas/compat/_constants.py +@@ -17,6 +17,7 @@ + PY311 = sys.version_info >= (3, 11) + PY312 = sys.version_info >= (3, 12) + 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 "") + REF_COUNT = 2 if PY311 else 3 + +@@ -27,4 +28,5 @@ + "PY311", + "PY312", + "PYPY", ++ "WASM", + ] +