From be47b864146b22faa5f960dabeee51d55dc63751 Mon Sep 17 00:00:00 2001 From: Julian Harbeck Date: Wed, 5 Nov 2025 17:46:58 +0100 Subject: [PATCH 1/3] Stop item_from_zerodim from converting subclasses of np.ndarray to float --- pandas/_libs/lib.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/_libs/lib.pyx b/pandas/_libs/lib.pyx index f0da99c795ebf..f0f068fde21ad 100644 --- a/pandas/_libs/lib.pyx +++ b/pandas/_libs/lib.pyx @@ -322,7 +322,7 @@ def item_from_zerodim(val: object) -> object: >>> item_from_zerodim(np.array([1])) array([1]) """ - if cnp.PyArray_IsZeroDim(val): + if cnp.PyArray_IsZeroDim(val) and cnp.PyArray_CheckExact(val): return cnp.PyArray_ToScalar(cnp.PyArray_DATA(val), val) return val From f27863309d94c8cd07de8b3cb3a8b1b7fb8a55dd Mon Sep 17 00:00:00 2001 From: Julian Harbeck Date: Tue, 11 Nov 2025 18:18:58 +0000 Subject: [PATCH 2/3] Add test for checking item_from_zerodim for np.ndarray and subclasses --- pandas/tests/libs/test_lib.py | 49 +++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/pandas/tests/libs/test_lib.py b/pandas/tests/libs/test_lib.py index f619ba4dd204b..7573f39764cbb 100644 --- a/pandas/tests/libs/test_lib.py +++ b/pandas/tests/libs/test_lib.py @@ -307,3 +307,52 @@ def test_ensure_string_array_list_of_lists(): # Each item in result should still be a list, not a stringified version expected = np.array(["['t', 'e', 's', 't']", "['w', 'o', 'r', 'd']"], dtype=object) tm.assert_numpy_array_equal(result, expected) + + +def test_item_from_zerodim_for_subclasses(): + # GH#62981 Ensure item_from_zerodim preserves subclasses of ndarray + # Define a custom ndarray subclass + class TestArray(np.ndarray): + def __new__(cls, input_array): + return np.asarray(input_array).view(cls) + + def __array_finalize__(self, obj) -> None: + self._is_test_array = True + + # Define test data + val_0_dim = 1 + val_1_dim = [1, 2, 3] + + # 0-dim and 1-dim numpy arrays + arr_0_dim = np.array(val_0_dim) + arr_1_dim = np.array(val_1_dim) + + # 0-dim and 1-dim TestArray arrays + test_arr_0_dim = TestArray(val_0_dim) + test_arr_1_dim = TestArray(val_1_dim) + + # Check that behavior did not change for regular numpy arrays + # Test with regular numpy 0-dim array + result = lib.item_from_zerodim(arr_0_dim) + expected = val_0_dim + assert result == expected + assert np.isscalar(result) + + # Test with regular numpy 1-dim array + result = lib.item_from_zerodim(arr_1_dim) + expected = arr_1_dim + tm.assert_numpy_array_equal(result, expected) + assert isinstance(result, np.ndarray) + + # Check that behaviour for subclasses now is as expected + # Test with TestArray 0-dim array + result = lib.item_from_zerodim(test_arr_0_dim) + expected = test_arr_0_dim + assert result == expected + assert isinstance(result, TestArray) + + # Test with TestArray 1-dim array + result = lib.item_from_zerodim(test_arr_1_dim) + expected = test_arr_1_dim + assert np.all(result == expected) + assert isinstance(result, TestArray) From ea682be0d882842b89e56746c668ff9867918d09 Mon Sep 17 00:00:00 2001 From: Julian Harbeck Date: Tue, 11 Nov 2025 18:47:49 +0000 Subject: [PATCH 3/3] Fix formatting --- pandas/tests/libs/test_lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/libs/test_lib.py b/pandas/tests/libs/test_lib.py index 7573f39764cbb..a00968ceda138 100644 --- a/pandas/tests/libs/test_lib.py +++ b/pandas/tests/libs/test_lib.py @@ -318,7 +318,7 @@ def __new__(cls, input_array): def __array_finalize__(self, obj) -> None: self._is_test_array = True - + # Define test data val_0_dim = 1 val_1_dim = [1, 2, 3]