diff --git a/doc/source/whatsnew/v0.24.0.rst b/doc/source/whatsnew/v0.24.0.rst index 1961ca2febb32..2b8cb81b78c4d 100644 --- a/doc/source/whatsnew/v0.24.0.rst +++ b/doc/source/whatsnew/v0.24.0.rst @@ -1321,6 +1321,7 @@ Datetimelike - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` where indexing with ``Ellipsis`` would incorrectly lose the index's ``freq`` attribute (:issue:`21282`) - Clarified error message produced when passing an incorrect ``freq`` argument to :class:`DatetimeIndex` with ``NaT`` as the first entry in the passed data (:issue:`11587`) - Bug in :func:`to_datetime` where ``box`` and ``utc`` arguments were ignored when passing a :class:`DataFrame` or ``dict`` of unit mappings (:issue:`23760`) +- Bug in :attr:`Series.dt` where the cache would not update properly after an in-place operation (:issue:`24408`) - Bug in :class:`PeriodIndex` where comparisons against an array-like object with length 1 failed to raise ``ValueError`` (:issue:`23078`) Timedelta diff --git a/pandas/core/indexes/accessors.py b/pandas/core/indexes/accessors.py index 670c4a2d8a414..791ef8223de98 100644 --- a/pandas/core/indexes/accessors.py +++ b/pandas/core/indexes/accessors.py @@ -27,7 +27,6 @@ def __init__(self, data, orig): self._parent = data self.orig = orig self.name = getattr(data, 'name', None) - self.index = getattr(data, 'index', None) self._freeze() def _get_values(self): @@ -71,8 +70,7 @@ def _delegate_property_get(self, name): result = take_1d(result, self.orig.cat.codes) index = self.orig.index else: - index = self.index - + index = self._parent.index # return the result as a Series, which is by definition a copy result = Series(result, index=index, name=self.name) @@ -98,7 +96,7 @@ def _delegate_method(self, name, *args, **kwargs): if not is_list_like(result): return result - result = Series(result, index=self.index, name=self.name) + result = Series(result, index=self._parent.index, name=self.name) # setting this object will show a SettingWithCopyWarning/Error result._is_copy = ("modifications to a method of a datetimelike " @@ -261,7 +259,7 @@ def components(self): 3 0 0 0 3 0 0 0 4 0 0 0 4 0 0 0 """ # noqa: E501 - return self._get_values().components.set_index(self.index) + return self._get_values().components.set_index(self._parent.index) @property def freq(self): diff --git a/pandas/tests/plotting/test_series.py b/pandas/tests/plotting/test_series.py index b5c69bb9e6443..b857979005f5e 100644 --- a/pandas/tests/plotting/test_series.py +++ b/pandas/tests/plotting/test_series.py @@ -890,3 +890,15 @@ def test_misc_bindings(self, mock): assert s.plot.lag() == 2 assert s.plot.autocorrelation() == 2 assert s.plot.bootstrap() == 2 + + @pytest.mark.xfail + def test_plot_accessor_updates_on_inplace(self): + s = Series([1, 2, 3, 4]) + _, ax = self.plt.subplots() + ax = s.plot(ax=ax) + before = ax.xaxis.get_ticklocs() + + s.drop([0, 1], inplace=True) + _, ax = self.plt.subplots() + after = ax.xaxis.get_ticklocs() + tm.assert_numpy_array_equal(before, after) diff --git a/pandas/tests/series/test_api.py b/pandas/tests/series/test_api.py index 65f5c59deba36..09e556af883c1 100644 --- a/pandas/tests/series/test_api.py +++ b/pandas/tests/series/test_api.py @@ -204,6 +204,11 @@ def test_from_array_deprecated(self): with tm.assert_produces_warning(FutureWarning): self.series_klass.from_array([1, 2, 3]) + def test_sparse_accessor_updates_on_inplace(self): + s = pd.Series([1, 1, 2, 3], dtype="Sparse[int]") + s.drop([0, 1], inplace=True) + assert s.sparse.density == 1.0 + class TestSeriesMisc(TestData, SharedWithSparse): @@ -447,6 +452,11 @@ def f(x): exp = Series([], dtype='float64', index=Index([], dtype='float64')) tm.assert_series_equal(result, exp) + def test_str_accessor_updates_on_inplace(self): + s = pd.Series(list('abc')) + s.drop([0], inplace=True) + assert len(s.str.lower()) == 2 + def test_str_attribute(self): # GH9068 methods = ['strip', 'rstrip', 'lstrip'] @@ -535,6 +545,12 @@ def test_cat_accessor_no_new_attributes(self): match="You cannot add any new attribute"): c.cat.xlabel = "a" + def test_cat_accessor_updates_on_inplace(self): + s = Series(list('abc')).astype('category') + s.drop(0, inplace=True) + s.cat.remove_unused_categories(inplace=True) + assert len(s.cat.categories) == 2 + def test_categorical_delegations(self): # invalid accessor diff --git a/pandas/tests/series/test_datetime_values.py b/pandas/tests/series/test_datetime_values.py index 745a9eee6c300..895717835c630 100644 --- a/pandas/tests/series/test_datetime_values.py +++ b/pandas/tests/series/test_datetime_values.py @@ -485,6 +485,13 @@ def test_dt_accessor_invalid(self, ser): ser.dt assert not hasattr(ser, 'dt') + def test_dt_accessor_updates_on_inplace(self): + s = Series(pd.date_range('2018-01-01', periods=10)) + s[2] = None + s.fillna(pd.Timestamp('2018-01-01'), inplace=True) + result = s.dt.date + assert result[0] == result[2] + def test_between(self): s = Series(bdate_range('1/1/2000', periods=20).astype(object)) s[::2] = np.nan