Skip to content

Commit 42b6ae0

Browse files
topper-123CloseChoice
authored andcommitted
TYP: type NDFrame.(_get_axis|_get_axis_name|_get_axis_number) (pandas-dev#33610)
1 parent 4fd475d commit 42b6ae0

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

doc/source/whatsnew/v1.1.0.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,9 @@ Other API changes
182182
Backwards incompatible API changes
183183
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184184
- :meth:`DataFrame.swaplevels` now raises a ``TypeError`` if the axis is not a :class:`MultiIndex`.
185-
Previously a ``AttributeError`` was raised (:issue:`31126`)
185+
Previously an ``AttributeError`` was raised (:issue:`31126`)
186+
- :meth:`DataFrame.xs` now raises a ``TypeError`` if a ``level`` keyword is supplied and the axis is not a :class:`MultiIndex`.
187+
Previously an ``AttributeError`` was raised (:issue:`33610`)
186188
- :meth:`DataFrameGroupby.mean` and :meth:`SeriesGroupby.mean` (and similarly for :meth:`~DataFrameGroupby.median`, :meth:`~DataFrameGroupby.std` and :meth:`~DataFrameGroupby.var`)
187189
now raise a ``TypeError`` if a not-accepted keyword argument is passed into it.
188190
Previously a ``UnsupportedFunctionCall`` was raised (``AssertionError`` if ``min_count`` passed into :meth:`~DataFrameGroupby.median`) (:issue:`31485`)

pandas/core/generic.py

+18-18
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ def _construct_axes_from_arguments(
353353
return axes, kwargs
354354

355355
@classmethod
356-
def _get_axis_number(cls, axis):
356+
def _get_axis_number(cls, axis) -> int:
357357
axis = cls._AXIS_ALIASES.get(axis, axis)
358358
if is_integer(axis):
359359
if axis in cls._AXIS_NAMES:
@@ -366,7 +366,7 @@ def _get_axis_number(cls, axis):
366366
raise ValueError(f"No axis named {axis} for object type {cls.__name__}")
367367

368368
@classmethod
369-
def _get_axis_name(cls, axis):
369+
def _get_axis_name(cls, axis) -> str:
370370
axis = cls._AXIS_ALIASES.get(axis, axis)
371371
if isinstance(axis, str):
372372
if axis in cls._AXIS_NUMBERS:
@@ -378,12 +378,12 @@ def _get_axis_name(cls, axis):
378378
pass
379379
raise ValueError(f"No axis named {axis} for object type {cls.__name__}")
380380

381-
def _get_axis(self, axis):
381+
def _get_axis(self, axis) -> Index:
382382
name = self._get_axis_name(axis)
383383
return getattr(self, name)
384384

385385
@classmethod
386-
def _get_block_manager_axis(cls, axis):
386+
def _get_block_manager_axis(cls, axis) -> int:
387387
"""Map the axis to the block_manager axis."""
388388
axis = cls._get_axis_number(axis)
389389
if cls._AXIS_REVERSED:
@@ -590,7 +590,9 @@ def swapaxes(self: FrameOrSeries, axis1, axis2, copy=True) -> FrameOrSeries:
590590
if copy:
591591
new_values = new_values.copy()
592592

593-
return self._constructor(new_values, *new_axes).__finalize__(
593+
# ignore needed because of NDFrame constructor is different than
594+
# DataFrame/Series constructors.
595+
return self._constructor(new_values, *new_axes).__finalize__( # type: ignore
594596
self, method="swapaxes"
595597
)
596598

@@ -3491,6 +3493,8 @@ class animal locomotion
34913493
axis = self._get_axis_number(axis)
34923494
labels = self._get_axis(axis)
34933495
if level is not None:
3496+
if not isinstance(labels, MultiIndex):
3497+
raise TypeError("Index must be a MultiIndex")
34943498
loc, new_ax = labels.get_loc_level(key, level=level, drop_level=drop_level)
34953499

34963500
# create the tuple of the indexer
@@ -7628,11 +7632,11 @@ def at_time(
76287632
axis = self._get_axis_number(axis)
76297633

76307634
index = self._get_axis(axis)
7631-
try:
7632-
indexer = index.indexer_at_time(time, asof=asof)
7633-
except AttributeError as err:
7634-
raise TypeError("Index must be DatetimeIndex") from err
76357635

7636+
if not isinstance(index, DatetimeIndex):
7637+
raise TypeError("Index must be DatetimeIndex")
7638+
7639+
indexer = index.indexer_at_time(time, asof=asof)
76367640
return self._take_with_is_copy(indexer, axis=axis)
76377641

76387642
def between_time(
@@ -7711,16 +7715,12 @@ def between_time(
77117715
axis = self._get_axis_number(axis)
77127716

77137717
index = self._get_axis(axis)
7714-
try:
7715-
indexer = index.indexer_between_time(
7716-
start_time,
7717-
end_time,
7718-
include_start=include_start,
7719-
include_end=include_end,
7720-
)
7721-
except AttributeError as err:
7722-
raise TypeError("Index must be DatetimeIndex") from err
7718+
if not isinstance(index, DatetimeIndex):
7719+
raise TypeError("Index must be DatetimeIndex")
77237720

7721+
indexer = index.indexer_between_time(
7722+
start_time, end_time, include_start=include_start, include_end=include_end,
7723+
)
77247724
return self._take_with_is_copy(indexer, axis=axis)
77257725

77267726
def resample(

pandas/tests/indexing/multiindex/test_xs.py

+12
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,15 @@ def test_series_getitem_multiindex_xs_by_label():
243243

244244
result = s.xs("one", level="L2")
245245
tm.assert_series_equal(result, expected)
246+
247+
248+
def test_xs_levels_raises():
249+
df = DataFrame({"A": [1, 2, 3]})
250+
251+
msg = "Index must be a MultiIndex"
252+
with pytest.raises(TypeError, match=msg):
253+
df.xs(0, level="as")
254+
255+
s = df.A
256+
with pytest.raises(TypeError, match=msg):
257+
s.xs(0, level="as")

0 commit comments

Comments
 (0)