Skip to content

Commit fae3e80

Browse files
TST (string dtype): resolve xfails for frame fillna and replace tests + fix bug in replace for string (#60295)
* TST (string dtype): resolve xfails for frame fillna and replace tests + fix bug in replace for string * fix fillna upcast issue * fix reshaping of condition in where - only do for 2d blocks
1 parent 63d3971 commit fae3e80

File tree

4 files changed

+80
-80
lines changed

4 files changed

+80
-80
lines changed

pandas/core/array_algos/replace.py

+2
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,6 @@ def re_replacer(s):
151151
if mask is None:
152152
values[:] = f(values)
153153
else:
154+
if values.ndim != mask.ndim:
155+
mask = np.broadcast_to(mask, values.shape)
154156
values[mask] = f(values[mask])

pandas/core/internals/blocks.py

+7
Original file line numberDiff line numberDiff line change
@@ -1688,6 +1688,13 @@ def where(self, other, cond) -> list[Block]:
16881688
if isinstance(self.dtype, (IntervalDtype, StringDtype)):
16891689
# TestSetitemFloatIntervalWithIntIntervalValues
16901690
blk = self.coerce_to_target_dtype(orig_other, raise_on_upcast=False)
1691+
if (
1692+
self.ndim == 2
1693+
and isinstance(orig_cond, np.ndarray)
1694+
and orig_cond.ndim == 1
1695+
and not is_1d_only_ea_dtype(blk.dtype)
1696+
):
1697+
orig_cond = orig_cond[:, None]
16911698
return blk.where(orig_other, orig_cond)
16921699

16931700
elif isinstance(self, NDArrayBackedExtensionBlock):

pandas/tests/frame/methods/test_fillna.py

+22-35
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
import numpy as np
22
import pytest
33

4-
from pandas._config import using_string_dtype
5-
64
from pandas import (
75
Categorical,
86
DataFrame,
@@ -65,15 +63,20 @@ def test_fillna_datetime(self, datetime_frame):
6563
with pytest.raises(TypeError, match=msg):
6664
datetime_frame.fillna()
6765

68-
# TODO(infer_string) test as actual error instead of xfail
69-
@pytest.mark.xfail(using_string_dtype(), reason="can't fill 0 in string")
70-
def test_fillna_mixed_type(self, float_string_frame):
66+
def test_fillna_mixed_type(self, float_string_frame, using_infer_string):
7167
mf = float_string_frame
7268
mf.loc[mf.index[5:20], "foo"] = np.nan
7369
mf.loc[mf.index[-10:], "A"] = np.nan
74-
# TODO: make stronger assertion here, GH 25640
75-
mf.fillna(value=0)
76-
mf.ffill()
70+
71+
result = mf.ffill()
72+
assert (
73+
result.loc[result.index[-10:], "A"] == result.loc[result.index[-11], "A"]
74+
).all()
75+
assert (result.loc[result.index[5:20], "foo"] == "bar").all()
76+
77+
result = mf.fillna(value=0)
78+
assert (result.loc[result.index[-10:], "A"] == 0).all()
79+
assert (result.loc[result.index[5:20], "foo"] == 0).all()
7780

7881
def test_fillna_mixed_float(self, mixed_float_frame):
7982
# mixed numeric (but no float16)
@@ -84,28 +87,21 @@ def test_fillna_mixed_float(self, mixed_float_frame):
8487
result = mf.ffill()
8588
_check_mixed_float(result, dtype={"C": None})
8689

87-
@pytest.mark.xfail(using_string_dtype(), reason="TODO(infer_string)")
88-
def test_fillna_different_dtype(self, using_infer_string):
90+
def test_fillna_different_dtype(self):
8991
# with different dtype (GH#3386)
9092
df = DataFrame(
9193
[["a", "a", np.nan, "a"], ["b", "b", np.nan, "b"], ["c", "c", np.nan, "c"]]
9294
)
9395

94-
if using_infer_string:
95-
with tm.assert_produces_warning(FutureWarning, match="Downcasting"):
96-
result = df.fillna({2: "foo"})
97-
else:
98-
result = df.fillna({2: "foo"})
96+
result = df.fillna({2: "foo"})
9997
expected = DataFrame(
10098
[["a", "a", "foo", "a"], ["b", "b", "foo", "b"], ["c", "c", "foo", "c"]]
10199
)
100+
# column is originally float (all-NaN) -> filling with string gives object dtype
101+
expected[2] = expected[2].astype("object")
102102
tm.assert_frame_equal(result, expected)
103103

104-
if using_infer_string:
105-
with tm.assert_produces_warning(FutureWarning, match="Downcasting"):
106-
return_value = df.fillna({2: "foo"}, inplace=True)
107-
else:
108-
return_value = df.fillna({2: "foo"}, inplace=True)
104+
return_value = df.fillna({2: "foo"}, inplace=True)
109105
tm.assert_frame_equal(df, expected)
110106
assert return_value is None
111107

@@ -276,8 +272,7 @@ def test_fillna_dictlike_value_duplicate_colnames(self, columns):
276272
expected["A"] = 0.0
277273
tm.assert_frame_equal(result, expected)
278274

279-
@pytest.mark.xfail(using_string_dtype(), reason="TODO(infer_string)")
280-
def test_fillna_dtype_conversion(self, using_infer_string):
275+
def test_fillna_dtype_conversion(self):
281276
# make sure that fillna on an empty frame works
282277
df = DataFrame(index=["A", "B", "C"], columns=[1, 2, 3, 4, 5])
283278
result = df.dtypes
@@ -292,7 +287,7 @@ def test_fillna_dtype_conversion(self, using_infer_string):
292287
# empty block
293288
df = DataFrame(index=range(3), columns=["A", "B"], dtype="float64")
294289
result = df.fillna("nan")
295-
expected = DataFrame("nan", index=range(3), columns=["A", "B"])
290+
expected = DataFrame("nan", dtype="object", index=range(3), columns=["A", "B"])
296291
tm.assert_frame_equal(result, expected)
297292

298293
@pytest.mark.parametrize("val", ["", 1, np.nan, 1.0])
@@ -540,18 +535,10 @@ def test_fillna_col_reordering(self):
540535
filled = df.ffill()
541536
assert df.columns.tolist() == filled.columns.tolist()
542537

543-
# TODO(infer_string) test as actual error instead of xfail
544-
@pytest.mark.xfail(using_string_dtype(), reason="can't fill 0 in string")
545-
def test_fill_corner(self, float_frame, float_string_frame):
546-
mf = float_string_frame
547-
mf.loc[mf.index[5:20], "foo"] = np.nan
548-
mf.loc[mf.index[-10:], "A"] = np.nan
549-
550-
filled = float_string_frame.fillna(value=0)
551-
assert (filled.loc[filled.index[5:20], "foo"] == 0).all()
552-
del float_string_frame["foo"]
553-
554-
float_frame.reindex(columns=[]).fillna(value=0)
538+
def test_fill_empty(self, float_frame):
539+
df = float_frame.reindex(columns=[])
540+
result = df.fillna(value=0)
541+
tm.assert_frame_equal(result, df)
555542

556543
def test_fillna_with_columns_and_limit(self):
557544
# GH40989

0 commit comments

Comments
 (0)