From d789157cf7c316d88bc17c84e3caa70865799b62 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 10 Jul 2019 07:35:38 -0700 Subject: [PATCH 1/5] BUG: fix inserting tz-aware datetime to Series, closes #12862 --- pandas/core/series.py | 7 +++++++ pandas/tests/series/indexing/test_indexing.py | 17 ++++++++++++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index b3a7f38aef8ef..c7be302be3c87 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1230,6 +1230,13 @@ def setitem(key, value): if _is_unorderable_exception(e): raise IndexError(key) + if is_scalar(key) and not is_integer(key) and key not in self.index: + # GH#12862 adding an new key to the Series + # Note: ave to exclude integers because that is ambiguously + # position-based + self.loc[key] = value + return + if com.is_bool_indexer(key): key = check_bool_indexer(self.index, key) try: diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index c8342c54e9b5d..c8f9859177ead 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -523,7 +523,22 @@ def test_setitem_with_tz_dst(): tm.assert_series_equal(s, exp) -def test_categorial_assigning_ops(): +def test_setitem_new_key_tz(): + # GH#12862 should not raise on assigning the second value + vals = [ + pd.to_datetime(42).tz_localize("UTC"), + pd.to_datetime(666).tz_localize("UTC"), + ] + + ser = pd.Series() + ser["foo"] = vals[0] + ser["bar"] = vals[1] + + expected = pd.Series(vals, index=["foo", "bar"]) + tm.assert_series_equal(ser, expected) + + +def test_categorical_assigning_ops(): orig = Series(Categorical(["b", "b"], categories=["a", "b"])) s = orig.copy() s[:] = "a" From 3d73d6e802d7f5177d079b75d3875b6d8f688026 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 10 Jul 2019 07:38:24 -0700 Subject: [PATCH 2/5] whatsnew --- doc/source/whatsnew/v0.25.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 4908bf6495d61..a902e088e8f7c 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -1051,6 +1051,7 @@ Indexing - Bug in :class:`Categorical` and :class:`CategoricalIndex` with :class:`Interval` values when using the ``in`` operator (``__contains``) with objects that are not comparable to the values in the ``Interval`` (:issue:`23705`) - 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`) - Bug in :class:`CategoricalIndex` and :class:`Categorical` incorrectly raising ``ValueError`` instead of ``TypeError`` when a list is passed using the ``in`` operator (``__contains__``) (:issue:`21729`) +- Bug in :class:`Series` setting a new key (``__setitem__``) with a timezone-aware datetime incorrectly raising ``ValueError`` (:issue:`12862`) - Missing From 158a3d5f762cedda9957fba7483cff7b0e456728 Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 10 Jul 2019 09:15:23 -0700 Subject: [PATCH 3/5] typo fixup --- pandas/core/series.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index c7be302be3c87..820b26c3a6a2a 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1232,7 +1232,7 @@ def setitem(key, value): if is_scalar(key) and not is_integer(key) and key not in self.index: # GH#12862 adding an new key to the Series - # Note: ave to exclude integers because that is ambiguously + # Note: have to exclude integers because that is ambiguously # position-based self.loc[key] = value return From efb81b96a9104f5e061f6a42fb45643b12c9568c Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Wed, 10 Jul 2019 18:32:58 -0700 Subject: [PATCH 4/5] also test loc --- pandas/tests/series/indexing/test_indexing.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index c8f9859177ead..0f176b9876dfb 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -529,12 +529,18 @@ def test_setitem_new_key_tz(): pd.to_datetime(42).tz_localize("UTC"), pd.to_datetime(666).tz_localize("UTC"), ] + expected = pd.Series(vals, index=["foo", "bar"]) ser = pd.Series() ser["foo"] = vals[0] ser["bar"] = vals[1] - expected = pd.Series(vals, index=["foo", "bar"]) + tm.assert_series_equal(ser, expected) + + ser = pd.Series() + ser.loc["foo"] = vals[0] + ser.loc["bar"] = vals[1] + tm.assert_series_equal(ser, expected) From 128f8b145cbb1b1fd42037d4ec35f84223c5f4ac Mon Sep 17 00:00:00 2001 From: jbrockmendel Date: Thu, 11 Jul 2019 08:06:26 -0700 Subject: [PATCH 5/5] requested refactor --- pandas/core/series.py | 14 ++++++------ pandas/tests/indexing/test_loc.py | 22 ++++++++++++++++++- pandas/tests/series/indexing/test_indexing.py | 21 ------------------ 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/pandas/core/series.py b/pandas/core/series.py index 4da4cc564bf90..acb0826953508 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -1231,13 +1231,6 @@ def setitem(key, value): if _is_unorderable_exception(e): raise IndexError(key) - if is_scalar(key) and not is_integer(key) and key not in self.index: - # GH#12862 adding an new key to the Series - # Note: have to exclude integers because that is ambiguously - # position-based - self.loc[key] = value - return - if com.is_bool_indexer(key): key = check_bool_indexer(self.index, key) try: @@ -1275,6 +1268,13 @@ def _set_with(self, key, value): except Exception: pass + if is_scalar(key) and not is_integer(key) and key not in self.index: + # GH#12862 adding an new key to the Series + # Note: have to exclude integers because that is ambiguously + # position-based + self.loc[key] = value + return + if is_scalar(key): key = [key] elif not isinstance(key, (list, Series, np.ndarray)): diff --git a/pandas/tests/indexing/test_loc.py b/pandas/tests/indexing/test_loc.py index d749e697c8282..90d1b0b1e0198 100644 --- a/pandas/tests/indexing/test_loc.py +++ b/pandas/tests/indexing/test_loc.py @@ -802,7 +802,7 @@ def test_loc_setitem_with_scalar_index(self, indexer, value): assert is_scalar(result) and result == "Z" - def test_loc_coerceion(self): + def test_loc_coercion(self): # 12411 df = DataFrame({"date": [Timestamp("20130101").tz_localize("UTC"), pd.NaT]}) @@ -838,6 +838,26 @@ def test_loc_coerceion(self): result = df.iloc[3:] tm.assert_series_equal(result.dtypes, expected) + def test_setitem_new_key_tz(self): + # GH#12862 should not raise on assigning the second value + vals = [ + pd.to_datetime(42).tz_localize("UTC"), + pd.to_datetime(666).tz_localize("UTC"), + ] + expected = pd.Series(vals, index=["foo", "bar"]) + + ser = pd.Series() + ser["foo"] = vals[0] + ser["bar"] = vals[1] + + tm.assert_series_equal(ser, expected) + + ser = pd.Series() + ser.loc["foo"] = vals[0] + ser.loc["bar"] = vals[1] + + tm.assert_series_equal(ser, expected) + def test_loc_non_unique(self): # GH3659 # non-unique indexer with loc slice diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index 451f97db1a5d7..6ff878f07da84 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -523,27 +523,6 @@ def test_setitem_with_tz_dst(): tm.assert_series_equal(s, exp) -def test_setitem_new_key_tz(): - # GH#12862 should not raise on assigning the second value - vals = [ - pd.to_datetime(42).tz_localize("UTC"), - pd.to_datetime(666).tz_localize("UTC"), - ] - expected = pd.Series(vals, index=["foo", "bar"]) - - ser = pd.Series() - ser["foo"] = vals[0] - ser["bar"] = vals[1] - - tm.assert_series_equal(ser, expected) - - ser = pd.Series() - ser.loc["foo"] = vals[0] - ser.loc["bar"] = vals[1] - - tm.assert_series_equal(ser, expected) - - def test_categorical_assigning_ops(): orig = Series(Categorical(["b", "b"], categories=["a", "b"])) s = orig.copy()