From 9485dc1831d56ecfdc1efc88fdb2aa672043396b Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 15 Apr 2020 14:20:31 -0700 Subject: [PATCH 1/3] BUG: DatetimeIndex.insert on empty can preserve freq --- pandas/core/indexes/datetimelike.py | 4 ++++ pandas/tests/indexes/datetimes/test_insert.py | 13 +++++++++++++ pandas/tests/indexes/timedeltas/test_insert.py | 11 ++++++++--- pandas/tests/series/indexing/test_indexing.py | 4 ++++ 4 files changed, 29 insertions(+), 3 deletions(-) diff --git a/pandas/core/indexes/datetimelike.py b/pandas/core/indexes/datetimelike.py index c15680a47d216..b83b64c144681 100644 --- a/pandas/core/indexes/datetimelike.py +++ b/pandas/core/indexes/datetimelike.py @@ -941,6 +941,10 @@ def insert(self, loc, item): freq = self.freq elif (loc == len(self)) and item - self.freq == self[-1]: freq = self.freq + elif self.freq is not None: + # Adding a single item to an empty index may preserve freq + if self.freq.is_on_offset(item): + freq = self.freq item = item.asm8 try: diff --git a/pandas/tests/indexes/datetimes/test_insert.py b/pandas/tests/indexes/datetimes/test_insert.py index 4abb4f0006444..6dba023c8e4d5 100644 --- a/pandas/tests/indexes/datetimes/test_insert.py +++ b/pandas/tests/indexes/datetimes/test_insert.py @@ -24,6 +24,19 @@ def test_insert_invalid_na(self, tz): with pytest.raises(TypeError, match="incompatible label"): idx.insert(0, np.timedelta64("NaT")) + def test_insert_empty_preserves_freq(self, tz_naive_fixture): + tz = tz_naive_fixture + dti = DatetimeIndex([], tz=tz, freq="D") + item = Timestamp("2017-04-05").tz_localize(tz) + + result = dti.insert(0, item) + assert result.freq == dti.freq + + # But not when we insert an item that doesnt conform to freq + dti = DatetimeIndex([], tz=tz, freq="W-THU") + result = dti.insert(0, item) + assert result.freq is None + def test_insert(self): idx = DatetimeIndex(["2000-01-04", "2000-01-01", "2000-01-02"], name="idx") diff --git a/pandas/tests/indexes/timedeltas/test_insert.py b/pandas/tests/indexes/timedeltas/test_insert.py index b214e009db869..fc4bd225a1e82 100644 --- a/pandas/tests/indexes/timedeltas/test_insert.py +++ b/pandas/tests/indexes/timedeltas/test_insert.py @@ -96,6 +96,11 @@ def test_insert_empty(self): idx = timedelta_range("1 Day", periods=3) td = idx[0] - idx[:0].insert(0, td) - idx[:0].insert(1, td) - idx[:0].insert(-1, td) + result = idx[:0].insert(0, td) + assert result.freq == "D" + + result = idx[:0].insert(1, td) + assert result.freq == "D" + + result = idx[:0].insert(-1, td) + assert result.freq == "D" diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 522ed4df96ad2..92730e5c1e96f 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -284,6 +284,8 @@ def test_setitem(datetime_series, string_series): expected = string_series.append(app) tm.assert_series_equal(s, expected) + +def test_setitem_empty_series(): # Test for issue #10193 key = pd.Timestamp("2012-01-01") series = pd.Series(dtype=object) @@ -291,10 +293,12 @@ def test_setitem(datetime_series, string_series): expected = pd.Series(47, [key]) tm.assert_series_equal(series, expected) + # GH#???? our index should retain its freq series = pd.Series([], pd.DatetimeIndex([], freq="D"), dtype=object) series[key] = 47 expected = pd.Series(47, pd.DatetimeIndex([key], freq="D")) tm.assert_series_equal(series, expected) + assert series.index.freq == expected.index.freq def test_setitem_dtypes(): From 65143a1ea83b8315458a8477bc8c0d0790323f32 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 15 Apr 2020 14:22:19 -0700 Subject: [PATCH 2/3] update GH ref --- pandas/tests/series/indexing/test_indexing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 92730e5c1e96f..900374824eb25 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -293,7 +293,7 @@ def test_setitem_empty_series(): expected = pd.Series(47, [key]) tm.assert_series_equal(series, expected) - # GH#???? our index should retain its freq + # GH#33573 our index should retain its freq series = pd.Series([], pd.DatetimeIndex([], freq="D"), dtype=object) series[key] = 47 expected = pd.Series(47, pd.DatetimeIndex([key], freq="D")) From 28794098d88a1c00e6339a85f6af54e46dbce667 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 16 Apr 2020 11:48:09 -0700 Subject: [PATCH 3/3] whatsnew --- doc/source/whatsnew/v1.1.0.rst | 1 + pandas/tests/indexes/datetimes/test_insert.py | 1 + pandas/tests/indexes/timedeltas/test_insert.py | 1 + 3 files changed, 3 insertions(+) diff --git a/doc/source/whatsnew/v1.1.0.rst b/doc/source/whatsnew/v1.1.0.rst index 82c43811c0444..f892dcdd364b9 100644 --- a/doc/source/whatsnew/v1.1.0.rst +++ b/doc/source/whatsnew/v1.1.0.rst @@ -479,6 +479,7 @@ Indexing - Bug in :meth:`DataFrame.copy` _item_cache not invalidated after copy causes post-copy value updates to not be reflected (:issue:`31784`) - Bug in `Series.__getitem__` with an integer key and a :class:`MultiIndex` with leading integer level failing to raise ``KeyError`` if the key is not present in the first level (:issue:`33355`) - Bug in :meth:`DataFrame.iloc` when slicing a single column-:class:`DataFrame`` with ``ExtensionDtype`` (e.g. ``df.iloc[:, :1]``) returning an invalid result (:issue:`32957`) +- Bug in :meth:`DatetimeIndex.insert` and :meth:`TimedeltaIndex.insert` causing index ``freq`` to be lost when setting an element into an empty :class:`Series` (:issue:33573`) Missing ^^^^^^^ diff --git a/pandas/tests/indexes/datetimes/test_insert.py b/pandas/tests/indexes/datetimes/test_insert.py index 6dba023c8e4d5..034e1c6a4e1b0 100644 --- a/pandas/tests/indexes/datetimes/test_insert.py +++ b/pandas/tests/indexes/datetimes/test_insert.py @@ -25,6 +25,7 @@ def test_insert_invalid_na(self, tz): idx.insert(0, np.timedelta64("NaT")) def test_insert_empty_preserves_freq(self, tz_naive_fixture): + # GH#33573 tz = tz_naive_fixture dti = DatetimeIndex([], tz=tz, freq="D") item = Timestamp("2017-04-05").tz_localize(tz) diff --git a/pandas/tests/indexes/timedeltas/test_insert.py b/pandas/tests/indexes/timedeltas/test_insert.py index fc4bd225a1e82..e65c871428bab 100644 --- a/pandas/tests/indexes/timedeltas/test_insert.py +++ b/pandas/tests/indexes/timedeltas/test_insert.py @@ -93,6 +93,7 @@ def test_insert_dont_cast_strings(self): def test_insert_empty(self): # Corner case inserting with length zero doesnt raise IndexError + # GH#33573 for freq preservation idx = timedelta_range("1 Day", periods=3) td = idx[0]