From 4dff9c392aaa28e1649bd9e73ef52b5336fddd43 Mon Sep 17 00:00:00 2001 From: tp Date: Fri, 17 Apr 2020 20:12:40 +0100 Subject: [PATCH] Changes --- doc/source/whatsnew/v1.1.0.rst | 4 +++- pandas/core/generic.py | 5 ++++- pandas/tests/indexing/multiindex/test_xs.py | 12 ++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 2f4e961ff433f3..dabe589f86ee9e 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -137,7 +137,9 @@ Other API changes Backwards incompatible API changes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - :meth:`DataFrame.swaplevels` now raises a ``TypeError`` if the axis is not a :class:`MultiIndex`. - Previously a ``AttributeError`` was raised (:issue:`31126`) + Previously an ``AttributeError`` was raised (:issue:`31126`) +- :meth:`DataFrame.xs` now raises a ``TypeError`` if a ``level`` keyword is supplied and the axis is not a :class:`MultiIndex`. + Previously an ``AttributeError`` was raised (:issue:`33610`) - :meth:`DataFrameGroupby.mean` and :meth:`SeriesGroupby.mean` (and similarly for :meth:`~DataFrameGroupby.median`, :meth:`~DataFrameGroupby.std` and :meth:`~DataFrameGroupby.var`) now raise a ``TypeError`` if a not-accepted keyword argument is passed into it. Previously a ``UnsupportedFunctionCall`` was raised (``AssertionError`` if ``min_count`` passed into :meth:`~DataFrameGroupby.median`) (:issue:`31485`) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 5c9da269e9729d..c897827502eda6 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -590,6 +590,8 @@ def swapaxes(self: FrameOrSeries, axis1, axis2, copy=True) -> FrameOrSeries: if copy: new_values = new_values.copy() + # ignore needed because of NDFrame constructor is different than + # DataFrame/Series constructors. return self._constructor(new_values, *new_axes).__finalize__( # type: ignore self, method="swapaxes" ) @@ -3490,7 +3492,8 @@ class animal locomotion axis = self._get_axis_number(axis) labels = self._get_axis(axis) if level is not None: - assert isinstance(labels, MultiIndex), type(labels) + if not isinstance(labels, MultiIndex): + raise TypeError("Index must be a MultiIndex") loc, new_ax = labels.get_loc_level(key, level=level, drop_level=drop_level) # create the tuple of the indexer diff --git a/pandas/tests/indexing/multiindex/test_xs.py b/pandas/tests/indexing/multiindex/test_xs.py index db8c0c643a6239..ff748d755c0631 100644 --- a/pandas/tests/indexing/multiindex/test_xs.py +++ b/pandas/tests/indexing/multiindex/test_xs.py @@ -243,3 +243,15 @@ def test_series_getitem_multiindex_xs_by_label(): result = s.xs("one", level="L2") tm.assert_series_equal(result, expected) + + +def test_xs_levels_raises(): + df = DataFrame({"A": [1, 2, 3]}) + + msg = "Index must be a MultiIndex" + with pytest.raises(TypeError, match=msg): + df.xs(0, level="as") + + s = df.A + with pytest.raises(TypeError, match=msg): + s.xs(0, level="as")