Skip to content

DEPR: downcast keyword #53671

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jun 29, 2023
Merged
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
2 changes: 1 addition & 1 deletion doc/source/whatsnew/v2.1.0.rst
Original file line number Diff line number Diff line change
@@ -255,6 +255,7 @@ Deprecations
- Deprecated making the functions in a list of functions given to :meth:`DataFrame.agg` attempt to operate on each element in the :class:`DataFrame` and only operate on the columns of the :class:`DataFrame` if the elementwise operations failed. To keep the current behavior, use :meth:`DataFrame.transform` instead. (:issue:`53325`)
- Deprecated passing a :class:`DataFrame` to :meth:`DataFrame.from_records`, use :meth:`DataFrame.set_index` or :meth:`DataFrame.drop` instead (:issue:`51353`)
- Deprecated silently dropping unrecognized timezones when parsing strings to datetimes (:issue:`18702`)
- Deprecated the "downcast" keyword in :meth:`Series.interpolate`, :meth:`DataFrame.interpolate`, :meth:`Series.fillna`, :meth:`DataFrame.fillna`, :meth:`Series.ffill`, :meth:`DataFrame.ffill`, :meth:`Series.bfill`, :meth:`DataFrame.bfill` (:issue:`40988`)
- Deprecated the ``axis`` keyword in :meth:`DataFrame.ewm`, :meth:`Series.ewm`, :meth:`DataFrame.rolling`, :meth:`Series.rolling`, :meth:`DataFrame.expanding`, :meth:`Series.expanding` (:issue:`51778`)
- Deprecated the ``axis`` keyword in :meth:`DataFrame.resample`, :meth:`Series.resample` (:issue:`51778`)
- Deprecated the behavior of :func:`concat` with both ``len(keys) != len(objs)``, in a future version this will raise instead of truncating to the shorter of the two sequences (:issue:`43485`)
@@ -292,7 +293,6 @@ Deprecations
- Deprecated :meth:`Series.first` and :meth:`DataFrame.first` (please create a mask and filter using ``.loc`` instead) (:issue:`45908`)
- Deprecated :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` for object-dtype (:issue:`53631`)
- Deprecated :meth:`Series.last` and :meth:`DataFrame.last` (please create a mask and filter using ``.loc`` instead) (:issue:`53692`)
- Deprecated allowing ``downcast`` keyword other than ``None``, ``False``, "infer", or a dict with these as values in :meth:`Series.fillna`, :meth:`DataFrame.fillna` (:issue:`40988`)
- Deprecated allowing arbitrary ``fill_value`` in :class:`SparseDtype`, in a future version the ``fill_value`` will need to be compatible with the ``dtype.subtype``, either a scalar that can be held by that subtype or ``NaN`` for integer or bool subtypes (:issue:`23124`)
- Deprecated behavior of :func:`assert_series_equal` and :func:`assert_frame_equal` considering NA-like values (e.g. ``NaN`` vs ``None`` as equivalent) (:issue:`52081`)
- Deprecated bytes input to :func:`read_excel`. To read a file path, use a string or path-like object. (:issue:`53767`)
136 changes: 83 additions & 53 deletions pandas/core/generic.py
Original file line number Diff line number Diff line change
@@ -6870,25 +6870,21 @@ def convert_dtypes(
# ----------------------------------------------------------------------
# Filling NA's

def _deprecate_downcast(self, downcast) -> None:
if isinstance(downcast, dict):
# GH#40988
for dc in downcast.values():
if dc is not None and dc is not False and dc != "infer":
warnings.warn(
"downcast entries other than None, False, and 'infer' "
"are deprecated and will raise in a future version",
FutureWarning,
stacklevel=find_stack_level(),
)
elif downcast is not None and downcast is not False and downcast != "infer":
# GH#40988
def _deprecate_downcast(self, downcast, method_name: str):
# GH#40988
if downcast is not lib.no_default:
warnings.warn(
"downcast other than None, False, and 'infer' are deprecated "
"and will raise in a future version",
f"The 'downcast' keyword in {method_name} is deprecated and "
"will be removed in a future version. Use "
"res.infer_objects(copy=False) to infer non-object dtype, or "
"pd.to_numeric with the 'downcast' keyword to downcast numeric "
"results.",
FutureWarning,
stacklevel=find_stack_level(),
)
else:
downcast = None
return downcast

@final
def _pad_or_backfill(
@@ -6977,7 +6973,7 @@ def fillna(
axis: Axis | None = None,
inplace: bool_t = False,
limit: int | None = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Self | None:
"""
Fill NA/NaN values using the specified method.
@@ -7096,7 +7092,8 @@ def fillna(
stacklevel=find_stack_level(),
)

self._deprecate_downcast(downcast)
was_no_default = downcast is lib.no_default
downcast = self._deprecate_downcast(downcast, "fillna")

# set the default here, so functions examining the signaure
# can detect if something was set (e.g. in groupby) (GH9221)
@@ -7113,7 +7110,11 @@ def fillna(
axis=axis,
limit=limit,
inplace=inplace,
downcast=downcast,
# error: Argument "downcast" to "_fillna_with_method" of "NDFrame"
# has incompatible type "Union[Dict[Any, Any], None,
# Literal[_NoDefault.no_default]]"; expected
# "Optional[Dict[Any, Any]]"
downcast=downcast, # type: ignore[arg-type]
)
else:
if self.ndim == 1:
@@ -7157,13 +7158,20 @@ def fillna(
if k not in result:
continue

# error: Item "None" of "Optional[Dict[Any, Any]]" has no
# attribute "get"
downcast_k = (
downcast
if not is_dict
else downcast.get(k) # type: ignore[union-attr]
)
if was_no_default:
downcast_k = lib.no_default
else:
downcast_k = (
# error: Incompatible types in assignment (expression
# has type "Union[Dict[Any, Any], None,
# Literal[_NoDefault.no_default], Any]", variable has
# type "_NoDefault")
downcast # type: ignore[assignment]
if not is_dict
# error: Item "None" of "Optional[Dict[Any, Any]]" has
# no attribute "get"
else downcast.get(k) # type: ignore[union-attr]
)

res_k = result[k].fillna(v, limit=limit, downcast=downcast_k)

@@ -7236,7 +7244,7 @@ def ffill(
axis: None | Axis = ...,
inplace: Literal[False] = ...,
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> Self:
...

@@ -7247,7 +7255,7 @@ def ffill(
axis: None | Axis = ...,
inplace: Literal[True],
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> None:
...

@@ -7258,7 +7266,7 @@ def ffill(
axis: None | Axis = ...,
inplace: bool_t = ...,
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> Self | None:
...

@@ -7270,7 +7278,7 @@ def ffill(
axis: None | Axis = None,
inplace: bool_t = False,
limit: None | int = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Self | None:
"""
Synonym for :meth:`DataFrame.fillna` with ``method='ffill'``.
@@ -7309,10 +7317,17 @@ def ffill(
3 3.0
dtype: float64
"""
self._deprecate_downcast(downcast)
downcast = self._deprecate_downcast(downcast, "ffill")

return self._pad_or_backfill(
"ffill", axis=axis, inplace=inplace, limit=limit, downcast=downcast
"ffill",
axis=axis,
inplace=inplace,
limit=limit,
# error: Argument "downcast" to "_fillna_with_method" of "NDFrame"
# has incompatible type "Union[Dict[Any, Any], None,
# Literal[_NoDefault.no_default]]"; expected "Optional[Dict[Any, Any]]"
downcast=downcast, # type: ignore[arg-type]
)

@final
@@ -7323,7 +7338,7 @@ def pad(
axis: None | Axis = None,
inplace: bool_t = False,
limit: None | int = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Self | None:
"""
Synonym for :meth:`DataFrame.fillna` with ``method='ffill'``.
@@ -7352,7 +7367,7 @@ def bfill(
axis: None | Axis = ...,
inplace: Literal[False] = ...,
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> Self:
...

@@ -7363,7 +7378,7 @@ def bfill(
axis: None | Axis = ...,
inplace: Literal[True],
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> None:
...

@@ -7374,7 +7389,7 @@ def bfill(
axis: None | Axis = ...,
inplace: bool_t = ...,
limit: None | int = ...,
downcast: dict | None = ...,
downcast: dict | None | lib.NoDefault = ...,
) -> Self | None:
...

@@ -7386,7 +7401,7 @@ def bfill(
axis: None | Axis = None,
inplace: bool_t = False,
limit: None | int = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Self | None:
"""
Synonym for :meth:`DataFrame.fillna` with ``method='bfill'``.
@@ -7407,12 +7422,6 @@ def bfill(
2 2.0
3 2.0
dtype: float64
>>> s.bfill(downcast='infer')
0 1
1 2
2 2
3 2
dtype: int64
>>> s.bfill(limit=1)
0 1.0
1 NaN
@@ -7435,16 +7444,23 @@ def bfill(
1 4.0 5.0
2 4.0 7.0
3 4.0 7.0
>>> df.bfill(downcast='infer', limit=1)
A B
0 1.0 5
1 NaN 5
2 4.0 7
3 4.0 7
"""
self._deprecate_downcast(downcast)
>>> df.bfill(limit=1)
A B
0 1.0 5.0
1 NaN 5.0
2 4.0 7.0
3 4.0 7.0
"""
downcast = self._deprecate_downcast(downcast, "bfill")
return self._pad_or_backfill(
"bfill", axis=axis, inplace=inplace, limit=limit, downcast=downcast
"bfill",
axis=axis,
inplace=inplace,
limit=limit,
# error: Argument "downcast" to "_fillna_with_method" of "NDFrame"
# has incompatible type "Union[Dict[Any, Any], None,
# Literal[_NoDefault.no_default]]"; expected "Optional[Dict[Any, Any]]"
downcast=downcast, # type: ignore[arg-type]
)

@final
@@ -7455,7 +7471,7 @@ def backfill(
axis: None | Axis = None,
inplace: bool_t = False,
limit: None | int = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Self | None:
"""
Synonym for :meth:`DataFrame.fillna` with ``method='bfill'``.
@@ -7780,7 +7796,7 @@ def interpolate(
inplace: bool_t = False,
limit_direction: Literal["forward", "backward", "both"] | None = None,
limit_area: Literal["inside", "outside"] | None = None,
downcast: Literal["infer"] | None = None,
downcast: Literal["infer"] | None | lib.NoDefault = lib.no_default,
**kwargs,
) -> Self | None:
"""
@@ -7851,6 +7867,9 @@ def interpolate(

downcast : optional, 'infer' or None, defaults to None
Downcast dtypes if possible.

.. deprecated:: 2.1.0

``**kwargs`` : optional
Keyword arguments to pass on to the interpolating function.

@@ -7949,6 +7968,17 @@ def interpolate(
3 16.0
Name: d, dtype: float64
"""
if downcast is not lib.no_default:
# GH#40988
warnings.warn(
f"The 'downcast' keyword in {type(self).__name__}.interpolate "
"is deprecated and will be removed in a future version. "
"Call result.infer_objects(copy=False) on the result instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
else:
downcast = None
if downcast is not None and downcast != "infer":
raise ValueError("downcast must be either None or 'infer'")

8 changes: 6 additions & 2 deletions pandas/core/groupby/generic.py
Original file line number Diff line number Diff line change
@@ -868,7 +868,7 @@ def fillna(
axis: Axis | None | lib.NoDefault = lib.no_default,
inplace: bool = False,
limit: int | None = None,
downcast: dict | None = None,
downcast: dict | None | lib.NoDefault = lib.no_default,
) -> Series | None:
"""
Fill NA/NaN values using the specified method within groups.
@@ -912,6 +912,8 @@ def fillna(
or the string 'infer' which will try to downcast to an appropriate
equal type (e.g. float64 to int64 if possible).

.. deprecated:: 2.1.0

Returns
-------
Series
@@ -2390,7 +2392,7 @@ def fillna(
axis: Axis | None | lib.NoDefault = lib.no_default,
inplace: bool = False,
limit: int | None = None,
downcast=None,
downcast=lib.no_default,
) -> DataFrame | None:
"""
Fill NA/NaN values using the specified method within groups.
@@ -2434,6 +2436,8 @@ def fillna(
or the string 'infer' which will try to downcast to an appropriate
equal type (e.g. float64 to int64 if possible).

.. deprecated:: 2.1.0

Returns
-------
DataFrame
6 changes: 5 additions & 1 deletion pandas/core/resample.py
Original file line number Diff line number Diff line change
@@ -844,7 +844,7 @@ def interpolate(
inplace: bool = False,
limit_direction: Literal["forward", "backward", "both"] = "forward",
limit_area=None,
downcast=None,
downcast=lib.no_default,
**kwargs,
):
"""
@@ -917,6 +917,9 @@ def interpolate(

downcast : optional, 'infer' or None, defaults to None
Downcast dtypes if possible.

.. deprecated::2.1.0

``**kwargs`` : optional
Keyword arguments to pass on to the interpolating function.

@@ -1000,6 +1003,7 @@ def interpolate(
Note that the series erroneously increases between two anchors
``07:00:00`` and ``07:00:02``.
"""
assert downcast is lib.no_default # just checking coverage
result = self._upsample("asfreq")
return result.interpolate(
method=method,
12 changes: 8 additions & 4 deletions pandas/core/reshape/pivot.py
Original file line number Diff line number Diff line change
@@ -207,26 +207,30 @@ def __internal_pivot_table(
to_unstack.append(i)
else:
to_unstack.append(name)
table = agged.unstack(to_unstack)
table = agged.unstack(to_unstack, fill_value=fill_value)

if not dropna:
if isinstance(table.index, MultiIndex):
m = MultiIndex.from_arrays(
cartesian_product(table.index.levels), names=table.index.names
)
table = table.reindex(m, axis=0)
table = table.reindex(m, axis=0, fill_value=fill_value)

if isinstance(table.columns, MultiIndex):
m = MultiIndex.from_arrays(
cartesian_product(table.columns.levels), names=table.columns.names
)
table = table.reindex(m, axis=1)
table = table.reindex(m, axis=1, fill_value=fill_value)

if sort is True and isinstance(table, ABCDataFrame):
table = table.sort_index(axis=1)

if fill_value is not None:
table = table.fillna(fill_value, downcast="infer")
table = table.fillna(fill_value)
if aggfunc is len and not observed and lib.is_integer(fill_value):
# TODO: can we avoid this? this used to be handled by
# downcast="infer" in fillna
table = table.astype(np.int64)

if margins:
if dropna:
12 changes: 8 additions & 4 deletions pandas/tests/arithmetic/test_timedelta64.py
Original file line number Diff line number Diff line change
@@ -2038,9 +2038,11 @@ def test_td64arr_div_numeric_array(
expected = [tdser.iloc[0, n] / vector[n] for n in range(len(vector))]
expected = tm.box_expected(expected, xbox).astype(object)
# We specifically expect timedelta64("NaT") here, not pd.NA
expected[2] = expected[2].fillna(
np.timedelta64("NaT", "ns"), downcast=False
)
msg = "The 'downcast' keyword in fillna"
with tm.assert_produces_warning(FutureWarning, match=msg):
expected[2] = expected[2].fillna(
np.timedelta64("NaT", "ns"), downcast=False
)
else:
expected = [tdser[n] / vector[n] for n in range(len(tdser))]
expected = [
@@ -2122,7 +2124,9 @@ def test_td64arr_all_nat_div_object_dtype_numeric(self, box_with_array):
if box_with_array is not Index:
expected = tm.box_expected(expected, box_with_array).astype(object)
if box_with_array in [Series, DataFrame]:
expected = expected.fillna(tdnat, downcast=False) # GH#18463
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
expected = expected.fillna(tdnat, downcast=False) # GH#18463

result = left / right
tm.assert_equal(result, expected)
4 changes: 3 additions & 1 deletion pandas/tests/copy_view/test_interp_fillna.py
Original file line number Diff line number Diff line change
@@ -218,7 +218,9 @@ def test_fillna_inplace(using_copy_on_write, downcast):
arr_a = get_array(df, "a")
arr_b = get_array(df, "b")

df.fillna(5.5, inplace=True, downcast=downcast)
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
df.fillna(5.5, inplace=True, downcast=downcast)
assert np.shares_memory(get_array(df, "a"), arr_a)
assert np.shares_memory(get_array(df, "b"), arr_b)
if using_copy_on_write:
18 changes: 12 additions & 6 deletions pandas/tests/frame/methods/test_fillna.py
Original file line number Diff line number Diff line change
@@ -292,20 +292,25 @@ def test_fillna_downcast(self):
# GH#15277
# infer int64 from float64
df = DataFrame({"a": [1.0, np.nan]})
result = df.fillna(0, downcast="infer")
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.fillna(0, downcast="infer")
expected = DataFrame({"a": [1, 0]})
tm.assert_frame_equal(result, expected)

# infer int64 from float64 when fillna value is a dict
df = DataFrame({"a": [1.0, np.nan]})
result = df.fillna({"a": 0}, downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.fillna({"a": 0}, downcast="infer")
expected = DataFrame({"a": [1, 0]})
tm.assert_frame_equal(result, expected)

def test_fillna_downcast_false(self, frame_or_series):
# GH#45603 preserve object dtype with downcast=False
obj = frame_or_series([1, 2, 3], dtype="object")
result = obj.fillna("", downcast=False)
msg = "The 'downcast' keyword in fillna"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = obj.fillna("", downcast=False)
tm.assert_equal(result, obj)

def test_fillna_downcast_noop(self, frame_or_series):
@@ -316,15 +321,16 @@ def test_fillna_downcast_noop(self, frame_or_series):

obj = frame_or_series([1, 2, 3], dtype=np.int64)

msg = "downcast other than None, False, and 'infer' are deprecated"
msg = "The 'downcast' keyword in fillna"
with tm.assert_produces_warning(FutureWarning, match=msg):
# GH#40988
res = obj.fillna("foo", downcast=np.dtype(np.int32))
expected = obj.astype(np.int32)
tm.assert_equal(res, expected)

obj2 = obj.astype(np.float64)
res2 = obj2.fillna("foo", downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
res2 = obj2.fillna("foo", downcast="infer")
expected2 = obj # get back int64
tm.assert_equal(res2, expected2)

@@ -648,7 +654,7 @@ def test_fillna_downcast_dict(self):
# GH#40809
df = DataFrame({"col1": [1, np.nan]})

msg = "downcast entries other than None, False, and 'infer' are deprecated"
msg = "The 'downcast' keyword in fillna"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.fillna({"col1": 2}, downcast={"col1": "int64"})
expected = DataFrame({"col1": [1, 2]})
27 changes: 20 additions & 7 deletions pandas/tests/frame/methods/test_interpolate.py
Original file line number Diff line number Diff line change
@@ -165,7 +165,9 @@ def test_interp_combo(self):
expected = Series([1.0, 2.0, 3.0, 4.0], name="A")
tm.assert_series_equal(result, expected)

result = df["A"].interpolate(downcast="infer")
msg = "The 'downcast' keyword in Series.interpolate is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df["A"].interpolate(downcast="infer")
expected = Series([1, 2, 3, 4], name="A")
tm.assert_series_equal(result, expected)

@@ -181,10 +183,14 @@ def test_inerpolate_invalid_downcast(self):
)

msg = "downcast must be either None or 'infer'"
msg2 = "The 'downcast' keyword in DataFrame.interpolate is deprecated"
msg3 = "The 'downcast' keyword in Series.interpolate is deprecated"
with pytest.raises(ValueError, match=msg):
df.interpolate(downcast="int64")
with tm.assert_produces_warning(FutureWarning, match=msg2):
df.interpolate(downcast="int64")
with pytest.raises(ValueError, match=msg):
df["A"].interpolate(downcast="int64")
with tm.assert_produces_warning(FutureWarning, match=msg3):
df["A"].interpolate(downcast="int64")

def test_interp_nan_idx(self):
df = DataFrame({"A": [1, 2, np.nan, 4], "B": [np.nan, 2, 3, 4]})
@@ -246,7 +252,9 @@ def test_interp_alt_scipy(self):
expected.loc[5, "A"] = 6
tm.assert_frame_equal(result, expected)

result = df.interpolate(method="barycentric", downcast="infer")
msg = "The 'downcast' keyword in DataFrame.interpolate is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.interpolate(method="barycentric", downcast="infer")
tm.assert_frame_equal(result, expected.astype(np.int64))

result = df.interpolate(method="krogh")
@@ -370,7 +378,9 @@ def test_interp_inplace(self, using_copy_on_write):
tm.assert_frame_equal(result, expected)

result = df.copy()
return_value = result["a"].interpolate(inplace=True, downcast="infer")
msg = "The 'downcast' keyword in Series.interpolate is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
return_value = result["a"].interpolate(inplace=True, downcast="infer")
assert return_value is None
if using_copy_on_write:
tm.assert_frame_equal(result, expected_cow)
@@ -406,11 +416,14 @@ def test_interp_ignore_all_good(self):
}
)

result = df.interpolate(downcast=None)
msg = "The 'downcast' keyword in DataFrame.interpolate is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df.interpolate(downcast=None)
tm.assert_frame_equal(result, expected)

# all good
result = df[["B", "D"]].interpolate(downcast=None)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = df[["B", "D"]].interpolate(downcast=None)
tm.assert_frame_equal(result, df[["B", "D"]])

def test_interp_time_inplace_axis(self):
4 changes: 3 additions & 1 deletion pandas/tests/frame/methods/test_quantile.py
Original file line number Diff line number Diff line change
@@ -736,7 +736,9 @@ def test_quantile_empty_no_rows_dt64(self, interp_method):
exp = exp.astype(object)
if interpolation == "nearest":
# GH#18463 TODO: would we prefer NaTs here?
exp = exp.fillna(np.nan, downcast=False)
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
exp = exp.fillna(np.nan, downcast=False)
tm.assert_series_equal(res, exp)

# both dt64tz
4 changes: 3 additions & 1 deletion pandas/tests/frame/test_logical_ops.py
Original file line number Diff line number Diff line change
@@ -165,7 +165,9 @@ def test_logical_with_nas(self):
expected = Series([True, True])
tm.assert_series_equal(result, expected)

result = d["a"].fillna(False, downcast=False) | d["b"]
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = d["a"].fillna(False, downcast=False) | d["b"]
expected = Series([True, True])
tm.assert_series_equal(result, expected)

4 changes: 3 additions & 1 deletion pandas/tests/groupby/test_categorical.py
Original file line number Diff line number Diff line change
@@ -1235,7 +1235,9 @@ def test_seriesgroupby_observed_false_or_none(df_cat, observed, operation):

expected = Series(data=[2, 4, np.nan, 1, np.nan, 3], index=index, name="C")
if operation == "agg":
expected = expected.fillna(0, downcast="infer")
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
expected = expected.fillna(0, downcast="infer")
grouped = df_cat.groupby(["A", "B"], observed=observed)["C"]
result = getattr(grouped, operation)(sum)
tm.assert_series_equal(result, expected)
14 changes: 9 additions & 5 deletions pandas/tests/groupby/transform/test_transform.py
Original file line number Diff line number Diff line change
@@ -764,10 +764,12 @@ def test_cython_transform_frame(request, op, args, targop, df_fix, gb_target):

expected = expected.sort_index(axis=1)
if op == "shift":
expected["string_missing"] = expected["string_missing"].fillna(
np.nan, downcast=False
)
expected["string"] = expected["string"].fillna(np.nan, downcast=False)
depr_msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
expected["string_missing"] = expected["string_missing"].fillna(
np.nan, downcast=False
)
expected["string"] = expected["string"].fillna(np.nan, downcast=False)

result = gb[expected.columns].transform(op, *args).sort_index(axis=1)
tm.assert_frame_equal(result, expected)
@@ -835,7 +837,9 @@ def test_cython_transform_frame_column(
expected = gb[c].apply(targop)
expected.name = c
if c in ["string_missing", "string"]:
expected = expected.fillna(np.nan, downcast=False)
depr_msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
expected = expected.fillna(np.nan, downcast=False)

res = gb[c].transform(op, *args)
tm.assert_series_equal(expected, res)
4 changes: 3 additions & 1 deletion pandas/tests/io/json/test_pandas.py
Original file line number Diff line number Diff line change
@@ -994,7 +994,9 @@ def test_round_trip_exception(self, datapath):

result = read_json(StringIO(s))
res = result.reindex(index=df.index, columns=df.columns)
res = res.fillna(np.nan, downcast=False)
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = res.fillna(np.nan, downcast=False)
tm.assert_frame_equal(res, df)

@pytest.mark.network
2 changes: 1 addition & 1 deletion pandas/tests/io/test_html.py
Original file line number Diff line number Diff line change
@@ -1497,7 +1497,7 @@ def test_extract_links(self, arg):

result = self.read_html(gh_13141_data, extract_links=arg)[0]
expected = DataFrame([data_exp, foot_exp], columns=head_exp)
expected = expected.fillna(np.nan, downcast=False)
expected = expected.fillna(np.nan)
tm.assert_frame_equal(result, expected)

def test_extract_links_bad(self, spam_data):
31 changes: 23 additions & 8 deletions pandas/tests/series/methods/test_fillna.py
Original file line number Diff line number Diff line change
@@ -175,13 +175,16 @@ def test_fillna_downcast(self):
# GH#15277
# infer int64 from float64
ser = Series([1.0, np.nan])
result = ser.fillna(0, downcast="infer")
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.fillna(0, downcast="infer")
expected = Series([1, 0])
tm.assert_series_equal(result, expected)

# infer int64 from float64 when fillna value is a dict
ser = Series([1.0, np.nan])
result = ser.fillna({1: 0}, downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
result = ser.fillna({1: 0}, downcast="infer")
expected = Series([1, 0])
tm.assert_series_equal(result, expected)

@@ -194,30 +197,42 @@ def test_fillna_downcast_infer_objects_to_numeric(self):

ser = Series(arr)

res = ser.fillna(3, downcast="infer")
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.fillna(3, downcast="infer")
expected = Series(np.arange(5), dtype=np.int64)
tm.assert_series_equal(res, expected)

res = ser.ffill(downcast="infer")
msg = "The 'downcast' keyword in ffill is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.ffill(downcast="infer")
expected = Series([0, 1, 2, 2, 4], dtype=np.int64)
tm.assert_series_equal(res, expected)

res = ser.bfill(downcast="infer")
msg = "The 'downcast' keyword in bfill is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.bfill(downcast="infer")
expected = Series([0, 1, 2, 4, 4], dtype=np.int64)
tm.assert_series_equal(res, expected)

# with a non-round float present, we will downcast to float64
ser[2] = 2.5

expected = Series([0, 1, 2.5, 3, 4], dtype=np.float64)
res = ser.fillna(3, downcast="infer")
msg = "The 'downcast' keyword in fillna is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.fillna(3, downcast="infer")
tm.assert_series_equal(res, expected)

res = ser.ffill(downcast="infer")
msg = "The 'downcast' keyword in ffill is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.ffill(downcast="infer")
expected = Series([0, 1, 2.5, 2.5, 4], dtype=np.float64)
tm.assert_series_equal(res, expected)

res = ser.bfill(downcast="infer")
msg = "The 'downcast' keyword in bfill is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
res = ser.bfill(downcast="infer")
expected = Series([0, 1, 2.5, 4, 4], dtype=np.float64)
tm.assert_series_equal(res, expected)

13 changes: 9 additions & 4 deletions pandas/tests/series/methods/test_interpolate.py
Original file line number Diff line number Diff line change
@@ -290,29 +290,34 @@ def test_interp_scipy_basic(self):
result = s.interpolate(method="slinear")
tm.assert_series_equal(result, expected)

result = s.interpolate(method="slinear", downcast="infer")
msg = "The 'downcast' keyword in Series.interpolate is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.interpolate(method="slinear", downcast="infer")
tm.assert_series_equal(result, expected)
# nearest
expected = Series([1, 3, 3, 12, 12, 25])
result = s.interpolate(method="nearest")
tm.assert_series_equal(result, expected.astype("float"))

result = s.interpolate(method="nearest", downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.interpolate(method="nearest", downcast="infer")
tm.assert_series_equal(result, expected)
# zero
expected = Series([1, 3, 3, 12, 12, 25])
result = s.interpolate(method="zero")
tm.assert_series_equal(result, expected.astype("float"))

result = s.interpolate(method="zero", downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.interpolate(method="zero", downcast="infer")
tm.assert_series_equal(result, expected)
# quadratic
# GH #15662.
expected = Series([1, 3.0, 6.823529, 12.0, 18.058824, 25.0])
result = s.interpolate(method="quadratic")
tm.assert_series_equal(result, expected)

result = s.interpolate(method="quadratic", downcast="infer")
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.interpolate(method="quadratic", downcast="infer")
tm.assert_series_equal(result, expected)
# cubic
expected = Series([1.0, 3.0, 6.8, 12.0, 18.2, 25.0])
4 changes: 3 additions & 1 deletion pandas/tests/series/methods/test_reindex.py
Original file line number Diff line number Diff line change
@@ -143,7 +143,9 @@ def test_reindex_pad2():
result = s.reindex(new_index).ffill()
tm.assert_series_equal(result, expected.astype("float64"))

result = s.reindex(new_index).ffill(downcast="infer")
msg = "The 'downcast' keyword in ffill is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = s.reindex(new_index).ffill(downcast="infer")
tm.assert_series_equal(result, expected)

expected = Series([1, 5, 3, 5], index=new_index)