Skip to content
Merged
3 changes: 2 additions & 1 deletion doc/source/whatsnew/v1.1.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Fixed regressions
- Regression in :meth:`DataFrame.replace` where a ``TypeError`` would be raised when attempting to replace elements of type :class:`Interval` (:issue:`35931`)
- Fix regression in pickle roundtrip of the ``closed`` attribute of :class:`IntervalIndex` (:issue:`35658`)
- Fixed regression in :meth:`DataFrameGroupBy.agg` where a ``ValueError: buffer source array is read-only`` would be raised when the underlying array is read-only (:issue:`36014`)
-
- Fixed regression in :meth:`Series.__getitem__` incorrectly raising when the input was a tuple. (:issue:`35534`)
- Fixed regression in :meth:`Series.__getitem__` incorrectly raising when the input was a frozenset. (:issue:`35747`)

.. ---------------------------------------------------------------------------

Expand Down
25 changes: 12 additions & 13 deletions pandas/core/series.py
Original file line number Diff line number Diff line change
Expand Up @@ -887,21 +887,20 @@ def __getitem__(self, key):
elif key_is_scalar:
return self._get_value(key)

if (
isinstance(key, tuple)
and is_hashable(key)
and isinstance(self.index, MultiIndex)
):
if not is_iterator(key) and is_hashable(key):
# Otherwise index.get_value will raise InvalidIndexError
try:
result = self._get_value(key)

return result
if isinstance(self.index, MultiIndex):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of doing the if first, can you do it in the keyerror itself e.g.

try:
    result = self._get_value(key)
    return result
except KeyError:
    if isinstance(self.index, MultiIndex):
        return self._get_values_tuple(key)

of course maybe we should actually do this inside _get_value

Copy link
Member Author

@rhshadrach rhshadrach Sep 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since _get_value is called from 4 places, I'll look into doing this for 1.2 in a followup.

try:
result = self._get_value(key)
return result

except KeyError:
# We still have the corner case where this tuple is a key
# in the first level of our MultiIndex
return self._get_values_tuple(key)
except KeyError:
# We still have the corner case where this tuple is a key
# in the first level of our MultiIndex
return self._get_values_tuple(key)
else:
# No fallback for an Index
return self._get_value(key)

if is_iterator(key):
key = list(key)
Expand Down
24 changes: 24 additions & 0 deletions pandas/tests/series/indexing/test_indexing.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
""" test get/set & misc """

from datetime import timedelta
import re

import numpy as np
import pytest
Expand Down Expand Up @@ -942,3 +943,26 @@ def assert_slices_equivalent(l_slc, i_slc):
for key2 in [keystr2, box(keystr2)]:
assert_slices_equivalent(SLC[key2:key:-1], SLC[13:8:-1])
assert_slices_equivalent(SLC[key:key2:-1], SLC[0:0:-1])


def test_tuple_index():
# GH 35534 - Selecting values when a Series has an Index of tuples
s = pd.Series([1, 2], index=[("a",), ("b",)])
assert s[("a",)] == 1
assert s[("b",)] == 2
s[("b",)] = 3
assert s[("b",)] == 3
with pytest.raises(KeyError, match="('c',)"):
s[("c",)]


def test_frozenset_index():
# GH35747 - Selecting values when a Series has an Index of frozenset
idx0, idx1 = frozenset("a"), frozenset("b")
s = pd.Series([1, 2], index=[idx0, idx1])
assert s[idx0] == 1
assert s[idx1] == 2
s[idx1] = 3
assert s[idx1] == 3
with pytest.raises(KeyError, match=re.escape("frozenset({'c'})")):
s[frozenset("c")]