Skip to content

Commit 981f125

Browse files
authored
BUG: Index.fillna silently ignoring 'downcast' kwarg (pandas-dev#44873)
1 parent e8c591d commit 981f125

File tree

5 files changed

+19
-20
lines changed

5 files changed

+19
-20
lines changed

doc/source/whatsnew/v1.4.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ Missing
711711
- Bug in :meth:`DataFrame.fillna` not replacing missing values when using a dict-like ``value`` and duplicate column names (:issue:`43476`)
712712
- Bug in constructing a :class:`DataFrame` with a dictionary ``np.datetime64`` as a value and ``dtype='timedelta64[ns]'``, or vice-versa, incorrectly casting instead of raising (:issue:`??`)
713713
- Bug in :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` with ``inplace=True`` not writing to the underlying array(s) in-place (:issue:`44749`)
714+
- Bug in :meth:`Index.fillna` incorrectly returning an un-filled :class:`Index` when NA values are present and ``downcast`` argument is specified. This now raises ``NotImplementedError`` instead; do not pass ``downcast`` argument (:issue:`44873`)
714715
-
715716

716717
MultiIndex

pandas/core/indexes/base.py

+6-1
Original file line numberDiff line numberDiff line change
@@ -2723,13 +2723,18 @@ def fillna(self, value=None, downcast=None):
27232723
DataFrame.fillna : Fill NaN values of a DataFrame.
27242724
Series.fillna : Fill NaN Values of a Series.
27252725
"""
2726+
27262727
value = self._require_scalar(value)
27272728
if self.hasnans:
27282729
result = self.putmask(self._isnan, value)
27292730
if downcast is None:
27302731
# no need to care metadata other than name
2731-
# because it can't have freq if
2732+
# because it can't have freq if it has NaTs
27322733
return Index._with_infer(result, name=self.name)
2734+
raise NotImplementedError(
2735+
f"{type(self).__name__}.fillna does not support 'downcast' "
2736+
"argument values other than 'None'."
2737+
)
27332738
return self._view()
27342739

27352740
def dropna(self: _IndexT, how: str_t = "any") -> _IndexT:

pandas/core/indexes/category.py

-14
Original file line numberDiff line numberDiff line change
@@ -377,20 +377,6 @@ def __contains__(self, key: Any) -> bool:
377377

378378
return contains(self, key, container=self._engine)
379379

380-
@doc(Index.fillna)
381-
def fillna(self, value, downcast=None):
382-
value = self._require_scalar(value)
383-
try:
384-
cat = self._data.fillna(value)
385-
except (ValueError, TypeError):
386-
# invalid fill_value
387-
if not self.hasnans:
388-
# nothing to fill, we can get away without casting
389-
return self.copy()
390-
return self.astype(object).fillna(value, downcast=downcast)
391-
392-
return type(self)._simple_new(cat, name=self.name)
393-
394380
# TODO(2.0): remove reindex once non-unique deprecation is enforced
395381
def reindex(
396382
self, target, method=None, level=None, limit=None, tolerance=None

pandas/tests/indexes/categorical/test_fillna.py

+7-5
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,19 @@ def test_fillna_categorical(self):
2525
tm.assert_index_equal(result, expected)
2626

2727
def test_fillna_copies_with_no_nas(self):
28-
# Nothing to fill, should still get a copy
28+
# Nothing to fill, should still get a copy for the Categorical method,
29+
# but OK to get a view on CategoricalIndex method
2930
ci = CategoricalIndex([0, 1, 1])
30-
cat = ci._data
3131
result = ci.fillna(0)
32-
assert result._values._ndarray is not cat._ndarray
33-
assert result._values._ndarray.base is None
32+
assert result is not ci
33+
assert tm.shares_memory(result, ci)
3434

35-
# Same check directly on the Categorical object
35+
# But at the EA level we always get a copy.
36+
cat = ci._data
3637
result = cat.fillna(0)
3738
assert result._ndarray is not cat._ndarray
3839
assert result._ndarray.base is None
40+
assert not tm.shares_memory(result, cat)
3941

4042
def test_fillna_validates_with_no_nas(self):
4143
# We validate the fill value even if fillna is a no-op

pandas/tests/indexes/common.py

+5
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,11 @@ def test_fillna(self, index):
516516

517517
idx = type(index)(values)
518518

519+
msg = "does not support 'downcast'"
520+
with pytest.raises(NotImplementedError, match=msg):
521+
# For now at least, we only raise if there are NAs present
522+
idx.fillna(idx[0], downcast="infer")
523+
519524
expected = np.array([False] * len(idx), dtype=bool)
520525
expected[1] = True
521526
tm.assert_numpy_array_equal(idx._isnan, expected)

0 commit comments

Comments
 (0)