|
4 | 4 | import pytest
|
5 | 5 |
|
6 | 6 | import pandas as pd
|
7 |
| -from pandas.core.arrays.numpy_ import PandasDtype |
| 7 | +import pandas._testing as tm |
8 | 8 |
|
9 | 9 | from .base import BaseExtensionTests
|
10 | 10 |
|
@@ -93,6 +93,92 @@ def test_setitem_iloc_scalar_multiple_homogoneous(self, data):
|
93 | 93 | df.iloc[10, 1] = data[1]
|
94 | 94 | assert df.loc[10, "B"] == data[1]
|
95 | 95 |
|
| 96 | + @pytest.mark.parametrize( |
| 97 | + "mask", |
| 98 | + [ |
| 99 | + np.array([True, True, True, False, False]), |
| 100 | + pd.array([True, True, True, False, False], dtype="boolean"), |
| 101 | + ], |
| 102 | + ids=["numpy-array", "boolean-array"], |
| 103 | + ) |
| 104 | + def test_setitem_mask(self, data, mask, box_in_series): |
| 105 | + arr = data[:5].copy() |
| 106 | + expected = arr.take([0, 0, 0, 3, 4]) |
| 107 | + if box_in_series: |
| 108 | + arr = pd.Series(arr) |
| 109 | + expected = pd.Series(expected) |
| 110 | + arr[mask] = data[0] |
| 111 | + self.assert_equal(expected, arr) |
| 112 | + |
| 113 | + def test_setitem_mask_raises(self, data, box_in_series): |
| 114 | + # wrong length |
| 115 | + mask = np.array([True, False]) |
| 116 | + |
| 117 | + if box_in_series: |
| 118 | + data = pd.Series(data) |
| 119 | + |
| 120 | + with pytest.raises(IndexError, match="wrong length"): |
| 121 | + data[mask] = data[0] |
| 122 | + |
| 123 | + mask = pd.array(mask, dtype="boolean") |
| 124 | + with pytest.raises(IndexError, match="wrong length"): |
| 125 | + data[mask] = data[0] |
| 126 | + |
| 127 | + def test_setitem_mask_boolean_array_raises(self, data, box_in_series): |
| 128 | + # missing values in mask |
| 129 | + mask = pd.array(np.zeros(data.shape, dtype="bool"), dtype="boolean") |
| 130 | + mask[:2] = pd.NA |
| 131 | + |
| 132 | + if box_in_series: |
| 133 | + data = pd.Series(data) |
| 134 | + |
| 135 | + msg = ( |
| 136 | + "Cannot mask with a boolean indexer containing NA values|" |
| 137 | + "cannot mask with array containing NA / NaN values" |
| 138 | + ) |
| 139 | + with pytest.raises(ValueError, match=msg): |
| 140 | + data[mask] = data[0] |
| 141 | + |
| 142 | + @pytest.mark.parametrize( |
| 143 | + "idx", |
| 144 | + [[0, 1, 2], pd.array([0, 1, 2], dtype="Int64"), np.array([0, 1, 2])], |
| 145 | + ids=["list", "integer-array", "numpy-array"], |
| 146 | + ) |
| 147 | + def test_setitem_integer_array(self, data, idx, box_in_series): |
| 148 | + arr = data[:5].copy() |
| 149 | + expected = data.take([0, 0, 0, 3, 4]) |
| 150 | + |
| 151 | + if box_in_series: |
| 152 | + arr = pd.Series(arr) |
| 153 | + expected = pd.Series(expected) |
| 154 | + |
| 155 | + arr[idx] = arr[0] |
| 156 | + self.assert_equal(arr, expected) |
| 157 | + |
| 158 | + @pytest.mark.parametrize( |
| 159 | + "idx, box_in_series", |
| 160 | + [ |
| 161 | + ([0, 1, 2, pd.NA], False), |
| 162 | + pytest.param( |
| 163 | + [0, 1, 2, pd.NA], True, marks=pytest.mark.xfail(reason="GH-31948") |
| 164 | + ), |
| 165 | + (pd.array([0, 1, 2, pd.NA], dtype="Int64"), False), |
| 166 | + (pd.array([0, 1, 2, pd.NA], dtype="Int64"), False), |
| 167 | + ], |
| 168 | + ids=["list-False", "list-True", "integer-array-False", "integer-array-True"], |
| 169 | + ) |
| 170 | + def test_setitem_integer_with_missing_raises(self, data, idx, box_in_series): |
| 171 | + arr = data.copy() |
| 172 | + |
| 173 | + # TODO(xfail) this raises KeyError about labels not found (it tries label-based) |
| 174 | + # for list of labels with Series |
| 175 | + if box_in_series: |
| 176 | + arr = pd.Series(data, index=[tm.rands(4) for _ in range(len(data))]) |
| 177 | + |
| 178 | + msg = "Cannot index with an integer indexer containing NA values" |
| 179 | + with pytest.raises(ValueError, match=msg): |
| 180 | + arr[idx] = arr[0] |
| 181 | + |
96 | 182 | @pytest.mark.parametrize("as_callable", [True, False])
|
97 | 183 | @pytest.mark.parametrize("setter", ["loc", None])
|
98 | 184 | def test_setitem_mask_aligned(self, data, as_callable, setter):
|
@@ -219,14 +305,3 @@ def test_setitem_preserves_views(self, data):
|
219 | 305 | data[0] = data[1]
|
220 | 306 | assert view1[0] == data[1]
|
221 | 307 | assert view2[0] == data[1]
|
222 |
| - |
223 |
| - def test_setitem_nullable_mask(self, data): |
224 |
| - # GH 31446 |
225 |
| - # TODO: there is some issue with PandasArray, therefore, |
226 |
| - # TODO: skip the setitem test for now, and fix it later |
227 |
| - if data.dtype != PandasDtype("object"): |
228 |
| - arr = data[:5] |
229 |
| - expected = data.take([0, 0, 0, 3, 4]) |
230 |
| - mask = pd.array([True, True, True, False, False]) |
231 |
| - arr[mask] = data[0] |
232 |
| - self.assert_extension_array_equal(expected, arr) |
|
0 commit comments