From 29bc817bf43ad1509d8d551f133f3194234cb56f Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Fri, 13 Mar 2020 09:58:29 -0700 Subject: [PATCH 1/4] loosen scalar check in Series.__getitem__ --- pandas/core/series.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 2d8eb9b29498a..f55d162f6ba5a 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -840,11 +840,15 @@ def _slice(self, slobj: slice, axis: int = 0) -> "Series": def __getitem__(self, key): key = com.apply_if_callable(key, self) + key = lib.item_from_zerodim(key) if key is Ellipsis: return self - key_is_scalar = is_scalar(key) + # check for is_list_like/slice instead of is_scalar to allow non-standard + # scalars through, e.g. cftime.datetime needed by xarray + # https://github.com/pydata/xarray/issues/3751 + key_is_scalar = not is_list_like(key) and not isinstance(key, slice) if isinstance(key, (list, tuple)): key = unpack_1tuple(key) From b982835a6a61735e70b7873e405fc1c2adb951bb Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 18 Mar 2020 12:55:11 -0700 Subject: [PATCH 2/4] test cases --- pandas/tests/dtypes/test_inference.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pandas/tests/dtypes/test_inference.py b/pandas/tests/dtypes/test_inference.py index e0fef833d4ced..ab9916eea8e5a 100644 --- a/pandas/tests/dtypes/test_inference.py +++ b/pandas/tests/dtypes/test_inference.py @@ -1437,6 +1437,7 @@ def test_is_scalar_pandas_scalars(self): assert is_scalar(Period("2014-01-01")) assert is_scalar(Interval(left=0, right=1)) assert is_scalar(DateOffset(days=1)) + assert is_scalar(pd.offsets.Minute(3)) def test_is_scalar_pandas_containers(self): assert not is_scalar(Series(dtype=object)) @@ -1445,6 +1446,11 @@ def test_is_scalar_pandas_containers(self): assert not is_scalar(DataFrame([[1]])) assert not is_scalar(Index([])) assert not is_scalar(Index([1])) + assert not is_scalar(Categorical([])) + assert not is_scalar(DatetimeIndex([])._data) + assert not is_scalar(TimedeltaIndex([])._data) + assert not is_scalar(DatetimeIndex([])._data.to_period("D")) + assert not is_scalar(pd.array([1, 2, 3])) def test_is_scalar_number(self): # Number() is not recognied by PyNumber_Check, so by extension From b4fbb2a5ecf3311ddb1f463eea1376c56878b14f Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 18 Mar 2020 14:56:49 -0700 Subject: [PATCH 3/4] check differently, whatsnew, test --- pandas/core/series.py | 9 +++++---- pandas/tests/series/indexing/test_indexing.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 6bb5c8269ba7c..3b019f7e38ed1 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -879,10 +879,7 @@ def __getitem__(self, key): if key is Ellipsis: return self - # check for is_list_like/slice instead of is_scalar to allow non-standard - # scalars through, e.g. cftime.datetime needed by xarray - # https://github.com/pydata/xarray/issues/3751 - key_is_scalar = not is_list_like(key) and not isinstance(key, slice) + key_is_scalar = lib.is_scalar(key) if isinstance(key, (list, tuple)): key = unpack_1tuple(key) @@ -930,6 +927,10 @@ def _get_with(self, key): elif isinstance(key, tuple): return self._get_values_tuple(key) + elif not is_list_like(key): + # e.g. scalars that aren't recognized by lib.is_scalar, GH#32684 + return self.loc[key] + if not isinstance(key, (list, np.ndarray, ExtensionArray, Series, Index)): key = list(key) diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 18fcbea683dd3..5b3786e1a0d3c 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -923,3 +923,15 @@ def test_getitem_2d_no_warning(): series = pd.Series([1, 2, 3], index=[1, 2, 3]) with tm.assert_produces_warning(None): series[:, None] + + +def test_getitem_unrecognized_scalar(): + # GH#32684 a scalar key that is not recognized by lib.is_scalar + + # a series that might be produced via `frame.dtypes` + ser = pd.Series([1, 2], index=[np.dtype("O"), np.dtype("i8")]) + + key = ser.index[1] + + result = ser[key] + assert result == 2 From b6bf0390a15ef1920d5ff37ac32ffe9bb65ca993 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 18 Mar 2020 15:13:54 -0700 Subject: [PATCH 4/4] remove unnecessary call, whatsnew but this time in the correct branch --- doc/source/whatsnew/v1.1.0.rst | 1 + pandas/core/series.py | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 0d3a9a8f969a4..441c6cee32b2a 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -303,6 +303,7 @@ Indexing - Bug in :meth:`Series.loc` and :meth:`DataFrame.loc` when indexing with an integer key on a object-dtype :class:`Index` that is not all-integers (:issue:`31905`) - Bug in :meth:`DataFrame.iloc.__setitem__` on a :class:`DataFrame` with duplicate columns incorrectly setting values for all matching columns (:issue:`15686`, :issue:`22036`) - Bug in :meth:`DataFrame.loc:` and :meth:`Series.loc` with a :class:`DatetimeIndex`, :class:`TimedeltaIndex`, or :class:`PeriodIndex` incorrectly allowing lookups of non-matching datetime-like dtypes (:issue:`32650`) +- Bug in :meth:`Series.__getitem__` indexing with non-standard scalars, e.g. ``np.dtype`` (:issue:`32684`) Missing ^^^^^^^ diff --git a/pandas/core/series.py b/pandas/core/series.py index 3b019f7e38ed1..21477cce48e63 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -874,12 +874,11 @@ def _slice(self, slobj: slice, axis: int = 0) -> "Series": def __getitem__(self, key): key = com.apply_if_callable(key, self) - key = lib.item_from_zerodim(key) if key is Ellipsis: return self - key_is_scalar = lib.is_scalar(key) + key_is_scalar = is_scalar(key) if isinstance(key, (list, tuple)): key = unpack_1tuple(key)