diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 30ae4ebe21ca4..769713cdf30e5 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -774,6 +774,8 @@ Indexing - Fixed bug where assigning a :class:`arrays.PandasArray` to a :class:`pandas.core.frame.DataFrame` would raise error (:issue:`26390`) - Allow keyword arguments for callable local reference used in the :meth:`DataFrame.query` string (:issue:`26426`) - Bug which produced ``AttributeError`` on partial matching :class:`Timestamp` in a :class:`MultiIndex` (:issue:`26944`) +- Bug in :meth:`DataFrame.loc` and :meth:`DataFrame.iloc` on a :class:`DataFrame` with a single timezone-aware datetime64[ns] column incorrectly returning a scalar instead of a :class:`Series` (:issue:`27110`) +- Missing ^^^^^^^ diff --git a/pandas/core/internals/blocks.py b/pandas/core/internals/blocks.py index b79f87461093d..cad37bf2b8ae1 100644 --- a/pandas/core/internals/blocks.py +++ b/pandas/core/internals/blocks.py @@ -1538,6 +1538,10 @@ def iget(self, col): col, loc = col if not com.is_null_slice(col) and col != 0: raise IndexError("{0} only contains one item".format(self)) + elif isinstance(col, slice): + if col != slice(None): + raise NotImplementedError(col) + return self.values[[loc]] return self.values[loc] else: if col != 0: diff --git a/pandas/tests/extension/base/getitem.py b/pandas/tests/extension/base/getitem.py index dfc82c6041eae..6a5507b51b3ba 100644 --- a/pandas/tests/extension/base/getitem.py +++ b/pandas/tests/extension/base/getitem.py @@ -73,6 +73,20 @@ def test_loc_frame(self, data): result = df.loc[:3, 'A'] self.assert_series_equal(result, expected) + def test_loc_iloc_frame_single_dtype(self, data): + # GH#27110 bug in ExtensionBlock.iget caused df.iloc[n] to incorrectly + # return a scalar + df = pd.DataFrame({"A": data}) + expected = pd.Series([data[2]], index=["A"], name=2, dtype=data.dtype) + + result = df.loc[2] + self.assert_series_equal(result, expected) + + expected = pd.Series([data[-1]], index=["A"], name=len(data) - 1, + dtype=data.dtype) + result = df.iloc[-1] + self.assert_series_equal(result, expected) + def test_getitem_scalar(self, data): result = data[0] assert isinstance(result, data.dtype.type) diff --git a/pandas/tests/extension/test_numpy.py b/pandas/tests/extension/test_numpy.py index f31fa5b87cfe5..74ca296d23295 100644 --- a/pandas/tests/extension/test_numpy.py +++ b/pandas/tests/extension/test_numpy.py @@ -180,6 +180,10 @@ def test_take_series(self, data): # ValueError: PandasArray must be 1-dimensional. super().test_take_series(data) + @pytest.mark.xfail(reason="astype doesn't recognize data.dtype") + def test_loc_iloc_frame_single_dtype(self, data): + super().test_loc_iloc_frame_single_dtype(data) + class TestGroupby(BaseNumPyTests, base.BaseGroupbyTests): @skip_nested diff --git a/pandas/tests/groupby/aggregate/test_other.py b/pandas/tests/groupby/aggregate/test_other.py index a061eaa1a2c6f..903ffa23173cb 100644 --- a/pandas/tests/groupby/aggregate/test_other.py +++ b/pandas/tests/groupby/aggregate/test_other.py @@ -421,11 +421,15 @@ def test_agg_timezone_round_trip(): assert ts == grouped.nth(0)['B'].iloc[0] assert ts == grouped.head(1)['B'].iloc[0] assert ts == grouped.first()['B'].iloc[0] - assert ts == grouped.apply(lambda x: x.iloc[0])[0] + + # GH#27110 applying iloc should return a DataFrame + assert ts == grouped.apply(lambda x: x.iloc[0]).iloc[0, 0] ts = df['B'].iloc[2] assert ts == grouped.last()['B'].iloc[0] - assert ts == grouped.apply(lambda x: x.iloc[-1])[0] + + # GH#27110 applying iloc should return a DataFrame + assert ts == grouped.apply(lambda x: x.iloc[-1]).iloc[0, 0] def test_sum_uint64_overflow(): diff --git a/pandas/tests/indexing/test_datetime.py b/pandas/tests/indexing/test_datetime.py index d4da34cab6f5c..278fa6bd44f99 100644 --- a/pandas/tests/indexing/test_datetime.py +++ b/pandas/tests/indexing/test_datetime.py @@ -39,7 +39,7 @@ def test_setitem_with_datetime_tz(self): def test_indexing_with_datetime_tz(self): - # 8260 + # GH#8260 # support datetime64 with tz idx = Index(date_range('20130101', periods=3, tz='US/Eastern'), @@ -65,11 +65,12 @@ def test_indexing_with_datetime_tz(self): # indexing - fast_xs df = DataFrame({'a': date_range('2014-01-01', periods=10, tz='UTC')}) result = df.iloc[5] - expected = Timestamp('2014-01-06 00:00:00+0000', tz='UTC', freq='D') - assert result == expected + expected = Series([Timestamp('2014-01-06 00:00:00+0000', tz='UTC')], + index=['a'], name=5) + tm.assert_series_equal(result, expected) result = df.loc[5] - assert result == expected + tm.assert_series_equal(result, expected) # indexing - boolean result = df[df.a > df.a[3]]