From 5a9b1b930bfb79d4324bb7a635aefe79de74ca1c Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 2 Mar 2018 14:28:12 -0600 Subject: [PATCH 1/6] fix: scalar timestamp assignment (#19843) --- pandas/core/frame.py | 10 ++++++-- .../scalar/timestamp/test_assignment_dtype.py | 23 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 pandas/tests/scalar/timestamp/test_assignment_dtype.py diff --git a/pandas/core/frame.py b/pandas/core/frame.py index ff4064b3f8c56..b2a508c8c3daa 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -2868,9 +2868,15 @@ def reindexer(value): value = maybe_infer_to_datetimelike(value) else: - # upcast the scalar + # cast ignores pandas dtypes. so save the dtype first + from pandas.core.dtypes.cast import infer_dtype_from_scalar + pd_dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) + + # upcast value = cast_scalar_to_array(len(self.index), value) - value = maybe_cast_to_datetime(value, value.dtype) + + # then add dtype back in + value = maybe_cast_to_datetime(value, pd_dtype) # return internal types directly if is_extension_type(value) or is_extension_array_dtype(value): diff --git a/pandas/tests/scalar/timestamp/test_assignment_dtype.py b/pandas/tests/scalar/timestamp/test_assignment_dtype.py new file mode 100644 index 0000000000000..f706b21ec7c43 --- /dev/null +++ b/pandas/tests/scalar/timestamp/test_assignment_dtype.py @@ -0,0 +1,23 @@ +import pandas as pd +from pandas.core.dtypes.dtypes import DatetimeTZDtype + + +# referencing #19843: scalar assignment of a tz-aware is object dtype + +class TestTimestampProperties(object): + + def test_scalar_assignment(self): + df = pd.DataFrame(index=(0, 1, 2)) + + df['now'] = pd.Timestamp('20130101', tz='UTC') + + assert isinstance(df.dtypes[0], DatetimeTZDtype) + + def test_datetime_index_assignment(self): + df = pd.DataFrame(index=(0, 1, 2)) + + di = pd.DatetimeIndex( + [pd.Timestamp('20130101', tz='UTC')]).repeat(len(df)) + df['now'] = di + + assert isinstance(df.dtypes[0], DatetimeTZDtype) From 601cf545585f39bbe994f21b95a56a9d123c88c4 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 2 Mar 2018 15:43:55 -0600 Subject: [PATCH 2/6] moved tests --- pandas/tests/frame/test_indexing.py | 18 +++++++++++++++ .../scalar/timestamp/test_assignment_dtype.py | 23 ------------------- 2 files changed, 18 insertions(+), 23 deletions(-) delete mode 100644 pandas/tests/scalar/timestamp/test_assignment_dtype.py diff --git a/pandas/tests/frame/test_indexing.py b/pandas/tests/frame/test_indexing.py index a8b81b1b03552..4f7ee74d2f7c7 100644 --- a/pandas/tests/frame/test_indexing.py +++ b/pandas/tests/frame/test_indexing.py @@ -37,6 +37,8 @@ from pandas.tests.frame.common import TestData +from pandas.core.dtypes.dtypes import DatetimeTZDtype + class TestDataFrameIndexing(TestData): @@ -3042,6 +3044,22 @@ def test_transpose(self): expected.index = ['A', 'B'] assert_frame_equal(result, expected) + def test_scalar_assignment(self): + df = pd.DataFrame(index=(0, 1, 2)) + + df['now'] = pd.Timestamp('20130101', tz='UTC') + + assert isinstance(df.dtypes[0], DatetimeTZDtype) + + def test_datetime_index_assignment(self): + df = pd.DataFrame(index=(0, 1, 2)) + + di = pd.DatetimeIndex( + [pd.Timestamp('20130101', tz='UTC')]).repeat(len(df)) + df['now'] = di + + assert isinstance(df.dtypes[0], DatetimeTZDtype) + class TestDataFrameIndexingUInt64(TestData): diff --git a/pandas/tests/scalar/timestamp/test_assignment_dtype.py b/pandas/tests/scalar/timestamp/test_assignment_dtype.py deleted file mode 100644 index f706b21ec7c43..0000000000000 --- a/pandas/tests/scalar/timestamp/test_assignment_dtype.py +++ /dev/null @@ -1,23 +0,0 @@ -import pandas as pd -from pandas.core.dtypes.dtypes import DatetimeTZDtype - - -# referencing #19843: scalar assignment of a tz-aware is object dtype - -class TestTimestampProperties(object): - - def test_scalar_assignment(self): - df = pd.DataFrame(index=(0, 1, 2)) - - df['now'] = pd.Timestamp('20130101', tz='UTC') - - assert isinstance(df.dtypes[0], DatetimeTZDtype) - - def test_datetime_index_assignment(self): - df = pd.DataFrame(index=(0, 1, 2)) - - di = pd.DatetimeIndex( - [pd.Timestamp('20130101', tz='UTC')]).repeat(len(df)) - df['now'] = di - - assert isinstance(df.dtypes[0], DatetimeTZDtype) From 33f865129a9cfc3aa4ecba4b5a5f2b5e531b4178 Mon Sep 17 00:00:00 2001 From: Dylan Date: Fri, 2 Mar 2018 16:02:31 -0600 Subject: [PATCH 3/6] issue number in tests --- pandas/tests/frame/test_indexing.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pandas/tests/frame/test_indexing.py b/pandas/tests/frame/test_indexing.py index 4f7ee74d2f7c7..b05416687f7ad 100644 --- a/pandas/tests/frame/test_indexing.py +++ b/pandas/tests/frame/test_indexing.py @@ -3045,19 +3045,17 @@ def test_transpose(self): assert_frame_equal(result, expected) def test_scalar_assignment(self): + # issue #19843 df = pd.DataFrame(index=(0, 1, 2)) - df['now'] = pd.Timestamp('20130101', tz='UTC') - assert isinstance(df.dtypes[0], DatetimeTZDtype) def test_datetime_index_assignment(self): + # issue #19843 df = pd.DataFrame(index=(0, 1, 2)) - di = pd.DatetimeIndex( [pd.Timestamp('20130101', tz='UTC')]).repeat(len(df)) df['now'] = di - assert isinstance(df.dtypes[0], DatetimeTZDtype) From 59069b934cc4972cccb8337617eec955efe50eb4 Mon Sep 17 00:00:00 2001 From: Dylan Date: Sat, 3 Mar 2018 11:22:11 -0600 Subject: [PATCH 4/6] added whatsnew --- doc/source/whatsnew/v0.23.0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index cf2a5de583878..3c643e2459684 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -854,6 +854,7 @@ Datetimelike - Bug in :func:`to_datetime` where passing an out-of-bounds datetime with ``errors='coerce'`` and ``utc=True`` would raise ``OutOfBoundsDatetime`` instead of parsing to ``NaT`` (:issue:`19612`) - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` addition and subtraction where name of the returned object was not always set consistently. (:issue:`19744`) - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` addition and subtraction where operations with numpy arrays raised ``TypeError`` (:issue:`19847`) +- Bug in `DataFrame` assignment with a timezone-aware object (:issue:`19843`) Timedelta ^^^^^^^^^ From c48fbe9a726a0f9c0ad29115d96cd1f6daacbd7d Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Thu, 2 Aug 2018 06:51:29 -0400 Subject: [PATCH 5/6] update docs --- doc/source/whatsnew/v0.23.0.txt | 4 ---- doc/source/whatsnew/v0.24.0.txt | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/doc/source/whatsnew/v0.23.0.txt b/doc/source/whatsnew/v0.23.0.txt index ef9dfae38c624..473a4bb72e6d9 100644 --- a/doc/source/whatsnew/v0.23.0.txt +++ b/doc/source/whatsnew/v0.23.0.txt @@ -1198,11 +1198,7 @@ Datetimelike - Bug in :func:`to_datetime` where passing an out-of-bounds datetime with ``errors='coerce'`` and ``utc=True`` would raise ``OutOfBoundsDatetime`` instead of parsing to ``NaT`` (:issue:`19612`) - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` addition and subtraction where name of the returned object was not always set consistently. (:issue:`19744`) - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` addition and subtraction where operations with numpy arrays raised ``TypeError`` (:issue:`19847`) -<<<<<<< HEAD -- Bug in `DataFrame` assignment with a timezone-aware object (:issue:`19843`) -======= - Bug in :class:`DatetimeIndex` and :class:`TimedeltaIndex` where setting the ``freq`` attribute was not fully supported (:issue:`20678`) ->>>>>>> master Timedelta ^^^^^^^^^ diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 3cff1522274ef..81b36572c80b2 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -559,6 +559,7 @@ Timezones - Bug in :class:`DatetimeIndex` where constructing with an integer and tz would not localize correctly (:issue:`12619`) - Fixed bug where :meth:`DataFrame.describe` and :meth:`Series.describe` on tz-aware datetimes did not show `first` and `last` result (:issue:`21328`) - Bug in :class:`DatetimeIndex` comparisons failing to raise ``TypeError`` when comparing timezone-aware ``DatetimeIndex`` against ``np.datetime64`` (:issue:`22074`) +- Bug in ``DataFrame`` assignment with a timezone-aware object (:issue:`19843`) Offsets ^^^^^^^ From 1b9649c8957a9e0fdc25a8a1a2a4039eedfeba7e Mon Sep 17 00:00:00 2001 From: Jeff Reback Date: Thu, 2 Aug 2018 06:57:39 -0400 Subject: [PATCH 6/6] clean --- doc/source/whatsnew/v0.24.0.txt | 2 +- pandas/core/frame.py | 9 ++++----- pandas/tests/frame/test_indexing.py | 14 +++----------- 3 files changed, 8 insertions(+), 17 deletions(-) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index 81b36572c80b2..9fc087dce752f 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -559,7 +559,7 @@ Timezones - Bug in :class:`DatetimeIndex` where constructing with an integer and tz would not localize correctly (:issue:`12619`) - Fixed bug where :meth:`DataFrame.describe` and :meth:`Series.describe` on tz-aware datetimes did not show `first` and `last` result (:issue:`21328`) - Bug in :class:`DatetimeIndex` comparisons failing to raise ``TypeError`` when comparing timezone-aware ``DatetimeIndex`` against ``np.datetime64`` (:issue:`22074`) -- Bug in ``DataFrame`` assignment with a timezone-aware object (:issue:`19843`) +- Bug in ``DataFrame`` assignment with a timezone-aware scalar (:issue:`19843`) Offsets ^^^^^^^ diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 4928203634cd3..b7894881feb40 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -27,6 +27,7 @@ maybe_upcast, cast_scalar_to_array, construct_1d_arraylike_from_scalar, + infer_dtype_from_scalar, maybe_cast_to_datetime, maybe_infer_to_datetimelike, maybe_convert_platform, @@ -3508,14 +3509,12 @@ def reindexer(value): else: # cast ignores pandas dtypes. so save the dtype first - from pandas.core.dtypes.cast import infer_dtype_from_scalar - pd_dtype, _ = infer_dtype_from_scalar(value, pandas_dtype=True) + infer_dtype, _ = infer_dtype_from_scalar( + value, pandas_dtype=True) # upcast value = cast_scalar_to_array(len(self.index), value) - - # then add dtype back in - value = maybe_cast_to_datetime(value, pd_dtype) + value = maybe_cast_to_datetime(value, infer_dtype) # return internal types directly if is_extension_type(value) or is_extension_array_dtype(value): diff --git a/pandas/tests/frame/test_indexing.py b/pandas/tests/frame/test_indexing.py index 26c3bb98e9859..d885df76967b8 100644 --- a/pandas/tests/frame/test_indexing.py +++ b/pandas/tests/frame/test_indexing.py @@ -37,8 +37,6 @@ from pandas.tests.frame.common import TestData -from pandas.core.dtypes.dtypes import DatetimeTZDtype - class TestDataFrameIndexing(TestData): @@ -3141,15 +3139,9 @@ def test_scalar_assignment(self): # issue #19843 df = pd.DataFrame(index=(0, 1, 2)) df['now'] = pd.Timestamp('20130101', tz='UTC') - assert isinstance(df.dtypes[0], DatetimeTZDtype) - - def test_datetime_index_assignment(self): - # issue #19843 - df = pd.DataFrame(index=(0, 1, 2)) - di = pd.DatetimeIndex( - [pd.Timestamp('20130101', tz='UTC')]).repeat(len(df)) - df['now'] = di - assert isinstance(df.dtypes[0], DatetimeTZDtype) + expected = pd.DataFrame( + {'now': pd.Timestamp('20130101', tz='UTC')}, index=[0, 1, 2]) + tm.assert_frame_equal(df, expected) class TestDataFrameIndexingUInt64(TestData):