Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions pandas/tests/extension/base/missing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@


class BaseMissingTests:
def _honors_copy_keyword(self, data) -> bool:
"""Whether the EA honors the copy keyword in methods like fillna.

EAs that always return new data regardless of copy=False should
override this to return False.
"""
return True

def test_isna(self, data_missing):
expected = np.array([True, False])

Expand Down Expand Up @@ -137,10 +145,11 @@ def test_fillna_readonly(self, data_missing):
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

# but with copy=False, this raises for EAs that respect the copy keyword
with pytest.raises(ValueError, match="Cannot modify read-only array"):
data.fillna(data_missing[1], copy=False)
tm.assert_extension_array_equal(data, data_missing)
if self._honors_copy_keyword(data_missing):
# with copy=False, this raises for EAs that respect the copy keyword
with pytest.raises(ValueError, match="Cannot modify read-only array"):
data.fillna(data_missing[1], copy=False)
tm.assert_extension_array_equal(data, data_missing)

def test_fillna_series(self, data_missing):
fill_value = data_missing[1]
Expand Down
7 changes: 3 additions & 4 deletions pandas/tests/extension/decimal/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ def data_for_grouping():


class TestDecimalArray(base.ExtensionTests):
def _honors_copy_keyword(self, data) -> bool:
return False

def _get_expected_exception(
self, op_name: str, obj, other
) -> type[Exception] | tuple[type[Exception], ...] | None:
Expand Down Expand Up @@ -167,10 +170,6 @@ def test_fillna_limit_series(self, data_missing):
):
super().test_fillna_limit_series(data_missing)

@pytest.mark.xfail(reason="copy keyword is missing")
def test_fillna_readonly(self, data_missing):
super().test_fillna_readonly(data_missing)

def test_series_repr(self, data):
# Overriding this base test to explicitly test that
# the custom _formatter is used
Expand Down
18 changes: 3 additions & 15 deletions pandas/tests/extension/test_arrow.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ def data_for_twos(data):


class TestArrowArray(base.ExtensionTests):
def _honors_copy_keyword(self, data) -> bool:
return False

def _construct_for_combine_add(self, left, right):
dtype = left.dtype

Expand Down Expand Up @@ -666,21 +669,6 @@ def test_fillna_no_op_returns_copy(self, data):
assert result is not data
tm.assert_extension_array_equal(result, data)

def test_fillna_readonly(self, data_missing):
data = data_missing.copy()
data._readonly = True

# by default fillna(copy=True), then this works fine
result = data.fillna(data_missing[1])
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

# fillna(copy=False) is generally not honored by Arrow-backed array,
# but always returns new data -> same result as above
result = data.fillna(data_missing[1])
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

@pytest.mark.xfail(
reason="GH 45419: pyarrow.ChunkedArray does not support views", run=False
)
Expand Down
7 changes: 3 additions & 4 deletions pandas/tests/extension/test_interval.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@ def data_for_grouping():
class TestIntervalArray(base.ExtensionTests):
divmod_exc = TypeError

def _honors_copy_keyword(self, data) -> bool:
return False

def _supports_reduction(self, ser: pd.Series, op_name: str) -> bool:
return op_name in ["min", "max", "count"]

Expand All @@ -103,10 +106,6 @@ def test_fillna_limit_series(self, data_missing):
def test_fillna_length_mismatch(self, data_missing):
super().test_fillna_length_mismatch(data_missing)

@pytest.mark.xfail(reason="copy=False is not Implemented")
def test_fillna_readonly(self, data_missing):
super().test_fillna_readonly(data_missing)

@pytest.mark.filterwarnings(
"ignore:invalid value encountered in cast:RuntimeWarning"
)
Expand Down
18 changes: 3 additions & 15 deletions pandas/tests/extension/test_sparse.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ def data_for_compare(request):


class TestSparseArray(base.ExtensionTests):
def _honors_copy_keyword(self, data) -> bool:
return False

def _supports_reduction(self, obj, op_name: str) -> bool:
return True

Expand Down Expand Up @@ -237,21 +240,6 @@ def test_isna(self, data_missing):
def test_fillna_no_op_returns_copy(self, data, request):
super().test_fillna_no_op_returns_copy(data)

def test_fillna_readonly(self, data_missing):
# copy keyword is ignored by SparseArray.fillna
# -> copy=True vs False doesn't make a difference
data = data_missing.copy()
data._readonly = True

result = data.fillna(data_missing[1])
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

# fillna(copy=False) is ignored -> so same result as above
result = data.fillna(data_missing[1], copy=False)
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

@pytest.mark.xfail(reason="Unsupported")
def test_fillna_series(self, data_missing):
# this one looks doable.
Expand Down
22 changes: 3 additions & 19 deletions pandas/tests/extension/test_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ def data_for_grouping(dtype, chunked):


class TestStringArray(base.ExtensionTests):
def _honors_copy_keyword(self, data) -> bool:
return data.dtype.storage != "pyarrow"

@pytest.mark.parametrize("na_action", [None, "ignore"])
def test_map(self, data_missing, na_action, request, using_infer_string):
if data_missing.dtype.storage == "python" and not using_infer_string:
Expand Down Expand Up @@ -180,25 +183,6 @@ def test_fillna_no_op_returns_copy(self, data):
assert result is not data
tm.assert_extension_array_equal(result, data)

def test_fillna_readonly(self, data_missing):
data = data_missing.copy()
data._readonly = True

# by default fillna(copy=True), then this works fine
result = data.fillna(data_missing[1])
assert result[0] == data_missing[1]
tm.assert_extension_array_equal(data, data_missing)

# fillna(copy=False) is generally not honored by Arrow-backed array,
# but always returns new data -> same result as above
if data.dtype.storage == "pyarrow":
result = data.fillna(data_missing[1])
assert result[0] == data_missing[1]
else:
with pytest.raises(ValueError, match="Cannot modify read-only array"):
data.fillna(data_missing[1], copy=False)
tm.assert_extension_array_equal(data, data_missing)

def _get_expected_exception(
self, op_name: str, obj, other
) -> type[Exception] | tuple[type[Exception], ...] | None:
Expand Down
Loading