Skip to content

Commit 1b8bb72

Browse files
phoflmeeseeksmachine
authored andcommitted
Backport PR pandas-dev#41789: Bug in xs raising KeyError for MultiIndex columns with droplevel False and list indexe
1 parent 29e8da1 commit 1b8bb72

File tree

5 files changed

+43
-3
lines changed

5 files changed

+43
-3
lines changed

doc/source/whatsnew/v1.2.5.rst

+7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,13 @@ Fixed regressions
2121

2222
.. ---------------------------------------------------------------------------
2323
24+
.. _whatsnew_125.deprecations:
25+
26+
Deprecations
27+
~~~~~~~~~~~~
28+
29+
- Deprecated passing lists as ``key`` to :meth:`DataFrame.xs` and :meth:`Series.xs` (:issue:`41760`)
30+
2431
.. _whatsnew_125.bug_fixes:
2532

2633
Bug fixes

pandas/core/generic.py

+9
Original file line numberDiff line numberDiff line change
@@ -3705,6 +3705,15 @@ class animal locomotion
37053705
"""
37063706
axis = self._get_axis_number(axis)
37073707
labels = self._get_axis(axis)
3708+
3709+
if isinstance(key, list):
3710+
warnings.warn(
3711+
"Passing lists as key for xs is deprecated and will be removed in a "
3712+
"future version. Pass key as a tuple instead.",
3713+
FutureWarning,
3714+
stacklevel=2,
3715+
)
3716+
37083717
if level is not None:
37093718
if not isinstance(labels, MultiIndex):
37103719
raise TypeError("Index must be a MultiIndex")

pandas/tests/frame/indexing/test_xs.py

+15-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,8 @@ def test_xs_keep_level(self):
9999
expected = df[:1]
100100
tm.assert_frame_equal(result, expected)
101101

102-
result = df.xs([2008, "sat"], level=["year", "day"], drop_level=False)
102+
with tm.assert_produces_warning(FutureWarning):
103+
result = df.xs([2008, "sat"], level=["year", "day"], drop_level=False)
103104
tm.assert_frame_equal(result, expected)
104105

105106
def test_xs_view(self):
@@ -172,7 +173,11 @@ def test_xs_with_duplicates(self, key, level, multiindex_dataframe_random_data):
172173
assert df.index.is_unique is False
173174
expected = concat([frame.xs("one", level="second")] * 2)
174175

175-
result = df.xs(key, level=level)
176+
if isinstance(key, list):
177+
with tm.assert_produces_warning(FutureWarning):
178+
result = df.xs(key, level=level)
179+
else:
180+
result = df.xs(key, level=level)
176181
tm.assert_frame_equal(result, expected)
177182

178183
def test_xs_missing_values_in_index(self):
@@ -327,3 +332,11 @@ def test_xs_droplevel_false_view(self):
327332
df.values[0, 0] = 2
328333
expected = DataFrame({"a": [2]})
329334
tm.assert_frame_equal(result, expected)
335+
336+
def test_xs_list_indexer_droplevel_false(self):
337+
# GH#41760
338+
mi = MultiIndex.from_tuples([("x", "m", "a"), ("x", "n", "b"), ("y", "o", "c")])
339+
df = DataFrame([[1, 2, 3], [4, 5, 6]], columns=mi)
340+
with tm.assert_produces_warning(FutureWarning):
341+
with pytest.raises(KeyError, match="y"):
342+
df.xs(["x", "y"], drop_level=False, axis=1)

pandas/tests/indexing/multiindex/test_partial.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ def test_xs_partial(
6767
)
6868
df = DataFrame(np.random.randn(8, 4), index=index, columns=list("abcd"))
6969

70-
result = df.xs(["foo", "one"])
70+
with tm.assert_produces_warning(FutureWarning):
71+
result = df.xs(["foo", "one"])
7172
expected = df.loc["foo", "one"]
7273
tm.assert_frame_equal(result, expected)
7374

pandas/tests/series/indexing/test_xs.py

+10
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,13 @@ def test_series_xs_droplevel_false(self):
6565
),
6666
)
6767
tm.assert_series_equal(result, expected)
68+
69+
def test_xs_key_as_list(self):
70+
# GH#41760
71+
mi = MultiIndex.from_tuples([("a", "x")], names=["level1", "level2"])
72+
ser = Series([1], index=mi)
73+
with tm.assert_produces_warning(FutureWarning):
74+
ser.xs(["a", "x"], axis=0, drop_level=False)
75+
76+
with tm.assert_produces_warning(FutureWarning):
77+
ser.xs(["a"], axis=0, drop_level=False)

0 commit comments

Comments
 (0)