Repository: pandas-dev/pandas

Issue:
API/DEPR: replace raise_conflict-kwarg in df.update with errors
From [review](https://github.com/pandas-dev/pandas/pull/23192/files#r225758408) in #23192:
> pls create [an issue] to deprecate this arg and rename to `errors=`

The idea is to replace the `raise_conflict=True|False` with `errors='ignore'|'raise'`.

Same goes for `Panel`.


Discussion:

Resolving patch:
diff --git a/pandas/core/frame.py b/pandas/core/frame.py
--- a/pandas/core/frame.py
+++ b/pandas/core/frame.py
@@ -5213,8 +5213,10 @@ def combiner(x, y):
 
         return self.combine(other, combiner, overwrite=False)
 
+    @deprecate_kwarg(old_arg_name='raise_conflict', new_arg_name='errors',
+                     mapping={False: 'ignore', True: 'raise'})
     def update(self, other, join='left', overwrite=True, filter_func=None,
-               raise_conflict=False):
+               errors='ignore'):
         """
         Modify in place using non-NA values from another DataFrame.
 
@@ -5238,17 +5240,28 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
             * False: only update values that are NA in
               the original DataFrame.
 
-        filter_func : callable(1d-array) -> boolean 1d-array, optional
+        filter_func : callable(1d-array) -> bool 1d-array, optional
             Can choose to replace values other than NA. Return True for values
             that should be updated.
-        raise_conflict : bool, default False
-            If True, will raise a ValueError if the DataFrame and `other`
+        errors : {'raise', 'ignore'}, default 'ignore'
+            If 'raise', will raise a ValueError if the DataFrame and `other`
             both contain non-NA data in the same place.
 
+            .. versionchanged :: 0.24.0
+               Changed from `raise_conflict=False|True`
+               to `errors='ignore'|'raise'`.
+
+        Returns
+        -------
+        None : method directly changes calling object
+
         Raises
         ------
         ValueError
-            When `raise_conflict` is True and there's overlapping non-NA data.
+            * When `errors='raise'` and there's overlapping non-NA data.
+            * When `errors` is not either `'ignore'` or `'raise'`
+        NotImplementedError
+            * If `join != 'left'`
 
         See Also
         --------
@@ -5319,6 +5332,9 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
         # TODO: Support other joins
         if join != 'left':  # pragma: no cover
             raise NotImplementedError("Only left join is supported")
+        if errors not in ['ignore', 'raise']:
+            raise ValueError("The parameter errors must be either "
+                             "'ignore' or 'raise'")
 
         if not isinstance(other, DataFrame):
             other = DataFrame(other)
@@ -5332,7 +5348,7 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
                 with np.errstate(all='ignore'):
                     mask = ~filter_func(this) | isna(that)
             else:
-                if raise_conflict:
+                if errors == 'raise':
                     mask_this = notna(that)
                     mask_that = notna(this)
                     if any(mask_this & mask_that):
diff --git a/pandas/core/panel.py b/pandas/core/panel.py
--- a/pandas/core/panel.py
+++ b/pandas/core/panel.py
@@ -32,7 +32,7 @@
                                    create_block_manager_from_blocks)
 from pandas.core.series import Series
 from pandas.core.reshape.util import cartesian_product
-from pandas.util._decorators import Appender, Substitution
+from pandas.util._decorators import Appender, Substitution, deprecate_kwarg
 from pandas.util._validators import validate_axis_style_args
 
 _shared_doc_kwargs = dict(
@@ -1235,7 +1235,12 @@ def reindex(self, *args, **kwargs):
         kwargs.update(axes)
         kwargs.pop('axis', None)
         kwargs.pop('labels', None)
-        return super(Panel, self).reindex(**kwargs)
+
+        with warnings.catch_warnings():
+            warnings.simplefilter("ignore", FutureWarning)
+            # do not warn about constructing Panel when reindexing
+            result = super(Panel, self).reindex(**kwargs)
+        return result
 
     @Substitution(**_shared_doc_kwargs)
     @Appender(NDFrame.rename.__doc__)
@@ -1377,25 +1382,37 @@ def join(self, other, how='left', lsuffix='', rsuffix=''):
             return concat([self] + list(other), axis=0, join=how,
                           join_axes=join_axes, verify_integrity=True)
 
+    @deprecate_kwarg(old_arg_name='raise_conflict', new_arg_name='errors',
+                     mapping={False: 'ignore', True: 'raise'})
     def update(self, other, join='left', overwrite=True, filter_func=None,
-               raise_conflict=False):
+               errors='ignore'):
         """
-        Modify Panel in place using non-NA values from passed
-        Panel, or object coercible to Panel. Aligns on items
+        Modify Panel in place using non-NA values from other Panel.
+
+        May also use object coercible to Panel. Will align on items.
 
         Parameters
         ----------
         other : Panel, or object coercible to Panel
-        join : How to join individual DataFrames
-            {'left', 'right', 'outer', 'inner'}, default 'left'
-        overwrite : boolean, default True
-            If True then overwrite values for common keys in the calling panel
-        filter_func : callable(1d-array) -> 1d-array<boolean>, default None
+            The object from which the caller will be udpated.
+        join : {'left', 'right', 'outer', 'inner'}, default 'left'
+            How individual DataFrames are joined.
+        overwrite : bool, default True
+            If True then overwrite values for common keys in the calling Panel.
+        filter_func : callable(1d-array) -> 1d-array<bool>, default None
             Can choose to replace values other than NA. Return True for values
-            that should be updated
-        raise_conflict : bool
-            If True, will raise an error if a DataFrame and other both
-            contain data in the same place.
+            that should be updated.
+        errors : {'raise', 'ignore'}, default 'ignore'
+            If 'raise', will raise an error if a DataFrame and other both.
+
+            .. versionchanged :: 0.24.0
+               Changed from `raise_conflict=False|True`
+               to `errors='ignore'|'raise'`.
+
+        See Also
+        --------
+        DataFrame.update : Similar method for DataFrames.
+        dict.update : Similar method for dictionaries.
         """
 
         if not isinstance(other, self._constructor):
@@ -1406,8 +1423,8 @@ def update(self, other, join='left', overwrite=True, filter_func=None,
         other = other.reindex(**{axis_name: axis_values})
 
         for frame in axis_values:
-            self[frame].update(other[frame], join, overwrite, filter_func,
-                               raise_conflict)
+            self[frame].update(other[frame], join=join, overwrite=overwrite,
+                               filter_func=filter_func, errors=errors)
 
     def _get_join_index(self, other, how):
         if how == 'left':


Test patch:
diff --git a/pandas/tests/frame/test_combine_concat.py b/pandas/tests/frame/test_combine_concat.py
--- a/pandas/tests/frame/test_combine_concat.py
+++ b/pandas/tests/frame/test_combine_concat.py
@@ -313,7 +313,17 @@ def test_update_filtered(self):
                               [1.5, nan, 7.]])
         assert_frame_equal(df, expected)
 
-    def test_update_raise(self):
+    @pytest.mark.parametrize('bad_kwarg, exception, msg', [
+        # errors must be 'ignore' or 'raise'
+        ({'errors': 'something'}, ValueError, 'The parameter errors must.*'),
+        ({'join': 'inner'}, NotImplementedError, 'Only left join is supported')
+    ])
+    def test_update_raise_bad_parameter(self, bad_kwarg, exception, msg):
+        df = DataFrame([[1.5, 1, 3.]])
+        with pytest.raises(exception, match=msg):
+            df.update(df, **bad_kwarg)
+
+    def test_update_raise_on_overlap(self):
         df = DataFrame([[1.5, 1, 3.],
                         [1.5, nan, 3.],
                         [1.5, nan, 3],
@@ -322,7 +332,14 @@ def test_update_raise(self):
         other = DataFrame([[2., nan],
                            [nan, 7]], index=[1, 3], columns=[1, 2])
         with pytest.raises(ValueError, match="Data overlaps"):
-            df.update(other, raise_conflict=True)
+            df.update(other, errors='raise')
+
+    @pytest.mark.parametrize('raise_conflict', [True, False])
+    def test_update_deprecation(self, raise_conflict):
+        df = DataFrame([[1.5, 1, 3.]])
+        other = DataFrame()
+        with tm.assert_produces_warning(FutureWarning):
+            df.update(other, raise_conflict=raise_conflict)
 
     def test_update_from_non_df(self):
         d = {'a': Series([1, 2, 3, 4]), 'b': Series([5, 6, 7, 8])}
diff --git a/pandas/tests/test_panel.py b/pandas/tests/test_panel.py
--- a/pandas/tests/test_panel.py
+++ b/pandas/tests/test_panel.py
@@ -2341,7 +2341,17 @@ def test_update_filtered(self):
 
         assert_panel_equal(pan, expected)
 
-    def test_update_raise(self):
+    @pytest.mark.parametrize('bad_kwarg, exception, msg', [
+        # errors must be 'ignore' or 'raise'
+        ({'errors': 'something'}, ValueError, 'The parameter errors must.*'),
+        ({'join': 'inner'}, NotImplementedError, 'Only left join is supported')
+    ])
+    def test_update_raise_bad_parameter(self, bad_kwarg, exception, msg):
+        pan = Panel([[[1.5, np.nan, 3.]]])
+        with pytest.raises(exception, match=msg):
+            pan.update(pan, **bad_kwarg)
+
+    def test_update_raise_on_overlap(self):
         pan = Panel([[[1.5, np.nan, 3.], [1.5, np.nan, 3.],
                       [1.5, np.nan, 3.],
                       [1.5, np.nan, 3.]],
@@ -2349,8 +2359,15 @@ def test_update_raise(self):
                       [1.5, np.nan, 3.],
                       [1.5, np.nan, 3.]]])
 
-        pytest.raises(Exception, pan.update, *(pan, ),
-                      **{'raise_conflict': True})
+        with pytest.raises(ValueError, match='Data overlaps'):
+            pan.update(pan, errors='raise')
+
+    @pytest.mark.parametrize('raise_conflict', [True, False])
+    def test_update_deprecation(self, raise_conflict):
+        pan = Panel([[[1.5, np.nan, 3.]]])
+        other = Panel([[[]]])
+        with tm.assert_produces_warning(FutureWarning):
+            pan.update(other, raise_conflict=raise_conflict)
 
     def test_all_any(self):
         assert (self.panel.all(axis=0).values == nanall(