diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 2a718fdcf16e7..b58a917f5d8b4 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -397,7 +397,7 @@ Other Deprecations - Deprecated silent dropping of columns that raised a ``TypeError``, ``DataError``, and some cases of ``ValueError`` in :meth:`Series.aggregate`, :meth:`DataFrame.aggregate`, :meth:`Series.groupby.aggregate`, and :meth:`DataFrame.groupby.aggregate` when used with a list (:issue:`43740`) - Deprecated casting behavior when setting timezone-aware value(s) into a timezone-aware :class:`Series` or :class:`DataFrame` column when the timezones do not match. Previously this cast to object dtype. In a future version, the values being inserted will be converted to the series or column's existing timezone (:issue:`37605`) - Deprecated casting behavior when passing an item with mismatched-timezone to :meth:`DatetimeIndex.insert`, :meth:`DatetimeIndex.putmask`, :meth:`DatetimeIndex.where` :meth:`DatetimeIndex.fillna`, :meth:`Series.mask`, :meth:`Series.where`, :meth:`Series.fillna`, :meth:`Series.shift`, :meth:`Series.replace`, :meth:`Series.reindex` (and :class:`DataFrame` column analogues). In the past this has cast to object dtype. In a future version, these will cast the passed item to the index or series's timezone (:issue:`37605`) -- +- Deprecated the 'errors' keyword argument in :meth:`Series.where`, :meth:`DataFrame.where`, :meth:`Series.mask`, and meth:`DataFrame.mask`; in a future version the argument will be removed (:issue:`44294`) .. --------------------------------------------------------------------------- diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 5c24c57925393..9186365fc390e 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -10907,7 +10907,7 @@ def where( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): return super().where(cond, other, inplace, axis, level, errors, try_cast) @@ -10922,7 +10922,7 @@ def mask( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): return super().mask(cond, other, inplace, axis, level, errors, try_cast) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index f3d7d6cee5446..b53679e2b584a 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -8900,7 +8900,7 @@ def _where( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, ): """ Equivalent to public method `where`, except that `other` is not @@ -8908,6 +8908,14 @@ def _where( """ inplace = validate_bool_kwarg(inplace, "inplace") + if errors is not lib.no_default: + warnings.warn( + f"The 'errors' keyword in {type(self).__name__}.where and mask is " + "deprecated and will be removed in a future version.", + FutureWarning, + stacklevel=find_stack_level(), + ) + if axis is not None: axis = self._get_axis_number(axis) @@ -9025,7 +9033,6 @@ def _where( other=other, cond=cond, align=align, - errors=errors, ) result = self._constructor(new_data) return result.__finalize__(self) @@ -9044,7 +9051,7 @@ def where( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): """ @@ -9077,6 +9084,9 @@ def where( - 'raise' : allow exceptions to be raised. - 'ignore' : suppress exceptions. On error return original object. + .. deprecated:: 1.4.0 + Previously was silently ignored. + try_cast : bool, default None Try to cast the result back to the input type (if possible). @@ -9197,7 +9207,7 @@ def mask( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): diff --git a/pandas/core/internals/array_manager.py b/pandas/core/internals/array_manager.py index 7f728ac9ddae5..29edb80f473fa 100644 --- a/pandas/core/internals/array_manager.py +++ b/pandas/core/internals/array_manager.py @@ -327,7 +327,7 @@ def apply_with_block(self: T, f, align_keys=None, swap_axis=True, **kwargs) -> T return type(self)(result_arrays, self._axes) - def where(self: T, other, cond, align: bool, errors: str) -> T: + def where(self: T, other, cond, align: bool) -> T: if align: align_keys = ["other", "cond"] else: @@ -339,7 +339,6 @@ def where(self: T, other, cond, align: bool, errors: str) -> T: align_keys=align_keys, other=other, cond=cond, - errors=errors, ) # TODO what is this used for? diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index 751cf41a09f14..33c78f396b80b 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1144,7 +1144,7 @@ def shift(self, periods: int, axis: int = 0, fill_value: Any = None) -> list[Blo return [self.make_block(new_values)] - def where(self, other, cond, errors="raise") -> list[Block]: + def where(self, other, cond) -> list[Block]: """ evaluate the block; return result block(s) from the result @@ -1152,9 +1152,6 @@ def where(self, other, cond, errors="raise") -> list[Block]: ---------- other : a ndarray/object cond : np.ndarray[bool], SparseArray[bool], or BooleanArray - errors : str, {'raise', 'ignore'}, default 'raise' - - ``raise`` : allow exceptions to be raised - - ``ignore`` : suppress exceptions. On error return original object Returns ------- @@ -1163,7 +1160,6 @@ def where(self, other, cond, errors="raise") -> list[Block]: assert cond.ndim == self.ndim assert not isinstance(other, (ABCIndex, ABCSeries, ABCDataFrame)) - assert errors in ["raise", "ignore"] transpose = self.ndim == 2 values = self.values @@ -1185,9 +1181,8 @@ def where(self, other, cond, errors="raise") -> list[Block]: # or if we are a single block (ndim == 1) if not self._can_hold_element(other): # we cannot coerce, return a compat dtype - # we are explicitly ignoring errors block = self.coerce_to_target_dtype(other) - blocks = block.where(orig_other, cond, errors=errors) + blocks = block.where(orig_other, cond) return self._maybe_downcast(blocks, "infer") # error: Argument 1 to "setitem_datetimelike_compat" has incompatible type @@ -1586,7 +1581,7 @@ def shift(self, periods: int, axis: int = 0, fill_value: Any = None) -> list[Blo new_values = self.values.shift(periods=periods, fill_value=fill_value) return [self.make_block_same_class(new_values)] - def where(self, other, cond, errors="raise") -> list[Block]: + def where(self, other, cond) -> list[Block]: cond = extract_bool_array(cond) assert not isinstance(other, (ABCIndex, ABCSeries, ABCDataFrame)) @@ -1619,7 +1614,7 @@ def where(self, other, cond, errors="raise") -> list[Block]: # For now at least only support casting e.g. # Interval[int64]->Interval[float64] raise - return blk.where(other, cond, errors) + return blk.where(other, cond) raise return [self.make_block_same_class(result)] @@ -1704,7 +1699,7 @@ def putmask(self, mask, new) -> list[Block]: arr.T.putmask(mask, new) return [self] - def where(self, other, cond, errors="raise") -> list[Block]: + def where(self, other, cond) -> list[Block]: arr = self.values cond = extract_bool_array(cond) @@ -1712,7 +1707,7 @@ def where(self, other, cond, errors="raise") -> list[Block]: try: res_values = arr.T._where(cond, other).T except (ValueError, TypeError): - return Block.where(self, other, cond, errors=errors) + return Block.where(self, other, cond) nb = self.make_block_same_class(res_values) return [nb] diff --git a/pandas/core/internals/managers.py b/pandas/core/internals/managers.py index 9286238e81fc3..7db19eda0f2fb 100644 --- a/pandas/core/internals/managers.py +++ b/pandas/core/internals/managers.py @@ -315,7 +315,7 @@ def apply( out = type(self).from_blocks(result_blocks, self.axes) return out - def where(self: T, other, cond, align: bool, errors: str) -> T: + def where(self: T, other, cond, align: bool) -> T: if align: align_keys = ["other", "cond"] else: @@ -327,7 +327,6 @@ def where(self: T, other, cond, align: bool, errors: str) -> T: align_keys=align_keys, other=other, cond=cond, - errors=errors, ) def setitem(self: T, indexer, value) -> T: diff --git a/pandas/core/series.py b/pandas/core/series.py index b67f16008bb13..391169af598c2 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -5461,7 +5461,7 @@ def where( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): return super().where(cond, other, inplace, axis, level, errors, try_cast) @@ -5476,7 +5476,7 @@ def mask( inplace=False, axis=None, level=None, - errors="raise", + errors=lib.no_default, try_cast=lib.no_default, ): return super().mask(cond, other, inplace, axis, level, errors, try_cast) diff --git a/pandas/tests/series/methods/test_fillna.py b/pandas/tests/series/methods/test_fillna.py index 2feaf4e951ab8..b132041f8afd0 100644 --- a/pandas/tests/series/methods/test_fillna.py +++ b/pandas/tests/series/methods/test_fillna.py @@ -147,15 +147,18 @@ def test_fillna_consistency(self): ) tm.assert_series_equal(result, expected) - # where (we ignore the errors=) - result = ser.where( - [True, False], Timestamp("20130101", tz="US/Eastern"), errors="ignore" - ) + msg = "The 'errors' keyword in " + with tm.assert_produces_warning(FutureWarning, match=msg): + # where (we ignore the errors=) + result = ser.where( + [True, False], Timestamp("20130101", tz="US/Eastern"), errors="ignore" + ) tm.assert_series_equal(result, expected) - result = ser.where( - [True, False], Timestamp("20130101", tz="US/Eastern"), errors="ignore" - ) + with tm.assert_produces_warning(FutureWarning, match=msg): + result = ser.where( + [True, False], Timestamp("20130101", tz="US/Eastern"), errors="ignore" + ) tm.assert_series_equal(result, expected) # with a non-datetime