From 0a45fcc2eb77c803b44545c947a2aa03d27b1065 Mon Sep 17 00:00:00 2001
From: Oleh Kozynets <ok7mailbox@gmail.com>
Date: Mon, 30 Nov 2020 19:13:26 +0100
Subject: [PATCH 1/5] Fix unit tests.

---
 doc/source/whatsnew/v1.2.0.rst                |  2 +-
 pandas/core/arrays/categorical.py             | 27 ++++++++++++++++---
 .../arrays/categorical/test_analytics.py      |  4 ++-
 pandas/tests/arrays/categorical/test_api.py   |  5 +++-
 4 files changed, 31 insertions(+), 7 deletions(-)

diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst
index ecea79be5b4dc..7f2265bd716aa 100644
--- a/doc/source/whatsnew/v1.2.0.rst
+++ b/doc/source/whatsnew/v1.2.0.rst
@@ -477,7 +477,7 @@ Deprecations
 - :meth:`Series.slice_shift` and :meth:`DataFrame.slice_shift` are deprecated, use :meth:`Series.shift` or :meth:`DataFrame.shift` instead (:issue:`37601`)
 - Partial slicing on unordered :class:`DatetimeIndex` with keys, which are not in Index is deprecated and will be removed in a future version (:issue:`18531`)
 - Deprecated :meth:`Index.asi8` for :class:`Index` subclasses other than :class:`DatetimeIndex`, :class:`TimedeltaIndex`, and :class:`PeriodIndex` (:issue:`37877`)
-- The ``inplace`` parameter of :meth:`Categorical.remove_unused_categories` is deprecated and will be removed in a future version (:issue:`37643`)
+- The ``inplace`` parameter of :meth:`Categorical.remove_categories`, :meth:`Categorical.remove_unused_categories` is deprecated and will be removed in a future version (:issue:`37643`)
 
 .. ---------------------------------------------------------------------------
 
diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py
index 62e508c491740..7f5e40db2c26e 100644
--- a/pandas/core/arrays/categorical.py
+++ b/pandas/core/arrays/categorical.py
@@ -3,7 +3,7 @@
 import operator
 from shutil import get_terminal_size
 from typing import Dict, Hashable, List, Sequence, Type, TypeVar, Union, cast
-from warnings import warn
+from warnings import catch_warnings, simplefilter, warn
 
 import numpy as np
 
@@ -1016,7 +1016,7 @@ def add_categories(self, new_categories, inplace=False):
         if not inplace:
             return cat
 
-    def remove_categories(self, removals, inplace=False):
+    def remove_categories(self, removals, inplace=no_default):
         """
         Remove the specified categories.
 
@@ -1031,6 +1031,8 @@ def remove_categories(self, removals, inplace=False):
            Whether or not to remove the categories inplace or return a copy of
            this categorical with removed categories.
 
+           .. deprecated:: 1.2.0
+
         Returns
         -------
         cat : Categorical or None
@@ -1049,6 +1051,17 @@ def remove_categories(self, removals, inplace=False):
         remove_unused_categories : Remove categories which are not used.
         set_categories : Set the categories to the specified ones.
         """
+        if inplace is not no_default:
+            warn(
+                "The `inplace` parameter in pandas.Categorical."
+                "remove_categories is deprecated and "
+                "will be removed in a future version.",
+                FutureWarning,
+                stacklevel=2,
+            )
+        else:
+            inplace = False
+
         inplace = validate_bool_kwarg(inplace, "inplace")
         if not is_list_like(removals):
             removals = [removals]
@@ -2289,14 +2302,20 @@ def replace(self, to_replace, value, inplace: bool = False):
                 continue
             if replace_value in cat.categories:
                 if isna(new_value):
-                    cat.remove_categories(replace_value, inplace=True)
+                    with catch_warnings():
+                        simplefilter("ignore")
+                        cat.remove_categories(replace_value, inplace=True)
                     continue
+
                 categories = cat.categories.tolist()
                 index = categories.index(replace_value)
+
                 if new_value in cat.categories:
                     value_index = categories.index(new_value)
                     cat._codes[cat._codes == index] = value_index
-                    cat.remove_categories(replace_value, inplace=True)
+                    with catch_warnings():
+                        simplefilter("ignore")
+                        cat.remove_categories(replace_value, inplace=True)
                 else:
                     categories[index] = new_value
                     cat.rename_categories(categories, inplace=True)
diff --git a/pandas/tests/arrays/categorical/test_analytics.py b/pandas/tests/arrays/categorical/test_analytics.py
index 7bd7d29ec9703..e938a94083139 100644
--- a/pandas/tests/arrays/categorical/test_analytics.py
+++ b/pandas/tests/arrays/categorical/test_analytics.py
@@ -352,7 +352,9 @@ def test_validate_inplace_raises(self, value):
             cat.add_categories(new_categories=["D", "E", "F"], inplace=value)
 
         with pytest.raises(ValueError, match=msg):
-            cat.remove_categories(removals=["D", "E", "F"], inplace=value)
+            with tm.assert_produces_warning(FutureWarning):
+                # issue #37643 inplace kwarg deprecated
+                cat.remove_categories(removals=["D", "E", "F"], inplace=value)
 
         with pytest.raises(ValueError, match=msg):
             with tm.assert_produces_warning(FutureWarning):
diff --git a/pandas/tests/arrays/categorical/test_api.py b/pandas/tests/arrays/categorical/test_api.py
index 98b0f978c5f59..083c23ed5b01b 100644
--- a/pandas/tests/arrays/categorical/test_api.py
+++ b/pandas/tests/arrays/categorical/test_api.py
@@ -348,7 +348,10 @@ def test_remove_categories(self):
         tm.assert_categorical_equal(res, new)
 
         # inplace == True
-        res = cat.remove_categories("c", inplace=True)
+        with tm.assert_produces_warning(FutureWarning):
+            # issue #37643 inplace kwarg deprecated
+            res = cat.remove_categories("c", inplace=True)
+
         tm.assert_categorical_equal(cat, new)
         assert res is None
 

From d4c13f619c510dc853b5c532b6b42c67c1b74281 Mon Sep 17 00:00:00 2001
From: Oleh Kozynets <OlehKSS@users.noreply.github.com>
Date: Mon, 18 Jan 2021 12:06:05 +0100
Subject: [PATCH 2/5] Update whatsnew entry.

---
 doc/source/whatsnew/v1.2.0.rst | 2 +-
 doc/source/whatsnew/v1.3.0.rst | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/doc/source/whatsnew/v1.2.0.rst b/doc/source/whatsnew/v1.2.0.rst
index 628fc75f2b45b..8e9361125513b 100644
--- a/doc/source/whatsnew/v1.2.0.rst
+++ b/doc/source/whatsnew/v1.2.0.rst
@@ -533,7 +533,7 @@ Deprecations
 - Partial slicing on unordered :class:`.DatetimeIndex` objects with keys that are not in the index is deprecated and will be removed in a future version (:issue:`18531`)
 - The ``how`` keyword in :meth:`PeriodIndex.astype` is deprecated and will be removed in a future version, use ``index.to_timestamp(how=how)`` instead (:issue:`37982`)
 - Deprecated :meth:`Index.asi8` for :class:`Index` subclasses other than :class:`.DatetimeIndex`, :class:`.TimedeltaIndex`, and :class:`PeriodIndex` (:issue:`37877`)
-- The ``inplace`` parameter of :meth:`Categorical.remove_categories`, :meth:`Categorical.remove_unused_categories` is deprecated and will be removed in a future version (:issue:`37643`)
+- The ``inplace`` parameter of :meth:`Categorical.remove_unused_categories` is deprecated and will be removed in a future version (:issue:`37643`)
 - The ``null_counts`` parameter of :meth:`DataFrame.info` is deprecated and replaced by ``show_counts``. It will be removed in a future version (:issue:`37999`)
 
 .. ---------------------------------------------------------------------------
diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst
index 6a85bfd852e19..c7aa8ed3ea860 100644
--- a/doc/source/whatsnew/v1.3.0.rst
+++ b/doc/source/whatsnew/v1.3.0.rst
@@ -192,6 +192,7 @@ Deprecations
 - Deprecated comparison of :class:`Timestamp` object with ``datetime.date`` objects.  Instead of e.g. ``ts <= mydate`` use ``ts <= pd.Timestamp(mydate)`` or ``ts.date() <= mydate`` (:issue:`36131`)
 - Deprecated :attr:`Rolling.win_type` returning ``"freq"`` (:issue:`38963`)
 - Deprecated :attr:`Rolling.is_datetimelike` (:issue:`38963`)
+- The ``inplace`` parameter of :meth:`Categorical.remove_categories` is deprecated and will be removed in a future version (:issue:`37643`)
 -
 
 .. ---------------------------------------------------------------------------

From 1e1694162623460ab2bf75b58b2063e37b3acbde Mon Sep 17 00:00:00 2001
From: Oleh Kozynets <oleh.kozynets@outlook.com>
Date: Mon, 5 Apr 2021 22:08:08 +0200
Subject: [PATCH 3/5] Fix pre-commit errors.

---
 pandas/core/arrays/categorical.py | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py
index 06cf89e470935..d616a004ecf49 100644
--- a/pandas/core/arrays/categorical.py
+++ b/pandas/core/arrays/categorical.py
@@ -17,7 +17,11 @@
     Union,
     cast,
 )
-from warnings import catch_warnings, simplefilter, warn
+from warnings import (
+    catch_warnings,
+    simplefilter,
+    warn,
+)
 
 import numpy as np
 

From be47fecf356958581de81d28cbe6316a713e1092 Mon Sep 17 00:00:00 2001
From: Oleh Kozynets <oleh.kozynets@outlook.com>
Date: Sat, 10 Apr 2021 20:51:34 +0200
Subject: [PATCH 4/5] Update warning message.

---
 pandas/core/arrays/categorical.py | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py
index d616a004ecf49..77050fd2cb9b8 100644
--- a/pandas/core/arrays/categorical.py
+++ b/pandas/core/arrays/categorical.py
@@ -1167,8 +1167,9 @@ def remove_categories(self, removals, inplace=no_default):
         if inplace is not no_default:
             warn(
                 "The `inplace` parameter in pandas.Categorical."
-                "remove_categories is deprecated and "
-                "will be removed in a future version.",
+                "remove_categories is deprecated and will be removed in "
+                "a future version. Removing unused categories will always "
+                "return a new Categorical object.",
                 FutureWarning,
                 stacklevel=2,
             )

From 3bcdd2b3d02296884e656ffa6d7dc9bde6f0df1f Mon Sep 17 00:00:00 2001
From: Oleh Kozynets <oleh.kozynets@outlook.com>
Date: Mon, 19 Apr 2021 22:39:55 +0200
Subject: [PATCH 5/5] Update the package version in comment.

---
 pandas/core/arrays/categorical.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/pandas/core/arrays/categorical.py b/pandas/core/arrays/categorical.py
index c87501a719372..853b1b38a444b 100644
--- a/pandas/core/arrays/categorical.py
+++ b/pandas/core/arrays/categorical.py
@@ -1141,7 +1141,7 @@ def remove_categories(self, removals, inplace=no_default):
            Whether or not to remove the categories inplace or return a copy of
            this categorical with removed categories.
 
-           .. deprecated:: 1.2.0
+           .. deprecated:: 1.3.0
 
         Returns
         -------