From 0b612bfafd3a57ca8a010279d0c375ee268f03b9 Mon Sep 17 00:00:00 2001 From: Brock Date: Fri, 21 May 2021 22:28:01 -0700 Subject: [PATCH 1/2] REGR: CategoricalIndex(None) --- pandas/core/indexes/category.py | 11 +++++++++++ .../tests/indexes/categorical/test_category.py | 5 +++++ .../indexes/categorical/test_constructors.py | 8 ++++++-- pandas/tests/indexes/common.py | 16 +++++++++++----- .../tests/indexes/datetimes/test_datetimelike.py | 3 --- pandas/tests/indexes/period/test_period.py | 3 ++- .../tests/indexes/timedeltas/test_timedelta.py | 3 --- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/pandas/core/indexes/category.py b/pandas/core/indexes/category.py index e835990eb8d89..ec3552cf751b9 100644 --- a/pandas/core/indexes/category.py +++ b/pandas/core/indexes/category.py @@ -222,6 +222,17 @@ def __new__( name = maybe_extract_name(name, data, cls) + if data is None: + # GH#38944 + warnings.warn( + "Constructing a CategoricalIndex without passing data is " + "deprecated and will raise in a future version. " + "Use CategoricalIndex([], ...) instead", + FutureWarning, + stacklevel=2, + ) + data = [] + if is_scalar(data): raise cls._scalar_data_error(data) diff --git a/pandas/tests/indexes/categorical/test_category.py b/pandas/tests/indexes/categorical/test_category.py index 40ab887d5bb5d..6a9f7c2a80922 100644 --- a/pandas/tests/indexes/categorical/test_category.py +++ b/pandas/tests/indexes/categorical/test_category.py @@ -38,6 +38,11 @@ def test_can_hold_identifiers(self): key = idx[0] assert idx._can_hold_identifiers_and_holds_name(key) is True + def test_pickle_compat_construction(self): + # Once the deprecation is enforced, we can use the parent class's test + with tm.assert_produces_warning(FutureWarning, match="without passing data"): + self._index_cls() + def test_insert(self, simple_index): ci = simple_index diff --git a/pandas/tests/indexes/categorical/test_constructors.py b/pandas/tests/indexes/categorical/test_constructors.py index 35620875d5a1a..e756d10e9935b 100644 --- a/pandas/tests/indexes/categorical/test_constructors.py +++ b/pandas/tests/indexes/categorical/test_constructors.py @@ -12,10 +12,14 @@ class TestCategoricalIndexConstructors: def test_construction_disallows_scalar(self): - msg = "must be called with a collection of some kind" - with pytest.raises(TypeError, match=msg): + with tm.assert_produces_warning(FutureWarning, match="without passing data"): CategoricalIndex(categories=list("abcd"), ordered=False) + # Once the deprecation is enforced, we can revert the test to + # msg = "must be called with a collection of some kind" + # with pytest.raises(TypeError, match=msg): + # CategoricalIndex(categories=list("abcd"), ordered=False) + def test_construction(self): ci = CategoricalIndex(list("aabbca"), categories=list("abcd"), ordered=False) diff --git a/pandas/tests/indexes/common.py b/pandas/tests/indexes/common.py index 8c4f25c5b20fc..0ea3abcaefcf2 100644 --- a/pandas/tests/indexes/common.py +++ b/pandas/tests/indexes/common.py @@ -47,11 +47,17 @@ def create_index(self) -> Index: def test_pickle_compat_construction(self): # need an object to create with - msg = ( - r"Index\(\.\.\.\) must be called with a collection of some " - r"kind, None was passed|" - r"__new__\(\) missing 1 required positional argument: 'data'|" - r"__new__\(\) takes at least 2 arguments \(1 given\)" + msg = "|".join( + [ + r"Index\(\.\.\.\) must be called with a collection of some " + r"kind, None was passed", + r"DatetimeIndex\(\) must be called with a collection of some " + r"kind, None was passed", + r"TimedeltaIndex\(\) must be called with a collection of some " + r"kind, None was passed", + r"__new__\(\) missing 1 required positional argument: 'data'", + r"__new__\(\) takes at least 2 arguments \(1 given\)", + ] ) with pytest.raises(TypeError, match=msg): self._index_cls() diff --git a/pandas/tests/indexes/datetimes/test_datetimelike.py b/pandas/tests/indexes/datetimes/test_datetimelike.py index 0a387fe3141e4..31ec8c497299e 100644 --- a/pandas/tests/indexes/datetimes/test_datetimelike.py +++ b/pandas/tests/indexes/datetimes/test_datetimelike.py @@ -32,9 +32,6 @@ def test_format(self, simple_index): def test_shift(self): pass # handled in test_ops - def test_pickle_compat_construction(self): - pass - def test_intersection(self): pass # handled in test_setops diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index b80e92b105dbd..83c82c18f3d1e 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -35,8 +35,9 @@ def simple_index(self) -> Index: def index(self, request): return request.param + @pytest.mark.xfail(reason="Goes through a generate_range path") def test_pickle_compat_construction(self): - pass + super().test_pickle_compat_construction() @pytest.mark.parametrize("freq", ["D", "M", "A"]) def test_pickle_round_trip(self, freq): diff --git a/pandas/tests/indexes/timedeltas/test_timedelta.py b/pandas/tests/indexes/timedeltas/test_timedelta.py index 478697ed1a5be..33f0565c0b23b 100644 --- a/pandas/tests/indexes/timedeltas/test_timedelta.py +++ b/pandas/tests/indexes/timedeltas/test_timedelta.py @@ -42,9 +42,6 @@ def test_numeric_compat(self): def test_shift(self): pass # this is handled in test_arithmetic.py - def test_pickle_compat_construction(self): - pass - def test_pickle_after_set_freq(self): tdi = timedelta_range("1 day", periods=4, freq="s") tdi = tdi._with_freq(None) From eec93f813798e5d4ffed3ee053ed03c59c68303d Mon Sep 17 00:00:00 2001 From: Brock Date: Sat, 22 May 2021 18:28:29 -0700 Subject: [PATCH 2/2] whatsnew, test --- doc/source/whatsnew/v1.3.0.rst | 1 + .../indexes/categorical/test_constructors.py | 15 +++++++++------ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/doc/source/whatsnew/v1.3.0.rst b/doc/source/whatsnew/v1.3.0.rst index d357e4a633347..5e76310e5f514 100644 --- a/doc/source/whatsnew/v1.3.0.rst +++ b/doc/source/whatsnew/v1.3.0.rst @@ -652,6 +652,7 @@ Build Deprecations ~~~~~~~~~~~~ - Deprecated allowing scalars to be passed to the :class:`Categorical` constructor (:issue:`38433`) +- Deprecated constructing :class:`CategoricalIndex` without passing list-like data (:issue:`38944`) - Deprecated allowing subclass-specific keyword arguments in the :class:`Index` constructor, use the specific subclass directly instead (:issue:`14093`, :issue:`21311`, :issue:`22315`, :issue:`26974`) - Deprecated ``astype`` of datetimelike (``timedelta64[ns]``, ``datetime64[ns]``, ``Datetime64TZDtype``, ``PeriodDtype``) to integer dtypes, use ``values.view(...)`` instead (:issue:`38544`) - Deprecated :meth:`MultiIndex.is_lexsorted` and :meth:`MultiIndex.lexsort_depth`, use :meth:`MultiIndex.is_monotonic_increasing` instead (:issue:`32259`) diff --git a/pandas/tests/indexes/categorical/test_constructors.py b/pandas/tests/indexes/categorical/test_constructors.py index e756d10e9935b..98da8038401e7 100644 --- a/pandas/tests/indexes/categorical/test_constructors.py +++ b/pandas/tests/indexes/categorical/test_constructors.py @@ -11,14 +11,17 @@ class TestCategoricalIndexConstructors: - def test_construction_disallows_scalar(self): - with tm.assert_produces_warning(FutureWarning, match="without passing data"): + def test_construction_without_data_deprecated(self): + # Once the deprecation is enforced, we can add this case to + # test_construction_disallows_scalar + msg = "without passing data" + with tm.assert_produces_warning(FutureWarning, match=msg): CategoricalIndex(categories=list("abcd"), ordered=False) - # Once the deprecation is enforced, we can revert the test to - # msg = "must be called with a collection of some kind" - # with pytest.raises(TypeError, match=msg): - # CategoricalIndex(categories=list("abcd"), ordered=False) + def test_construction_disallows_scalar(self): + msg = "must be called with a collection of some kind" + with pytest.raises(TypeError, match=msg): + CategoricalIndex(data=1, categories=list("abcd"), ordered=False) def test_construction(self):