From 552cf719c98929670f28052d4cf5754f279217ae Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 15 Feb 2021 17:40:09 -0800 Subject: [PATCH 1/3] TST/REF: share dt64/td64 NA SetitemCastingEquivalents tests --- pandas/tests/series/indexing/test_setitem.py | 56 ++++++-------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git a/pandas/tests/series/indexing/test_setitem.py b/pandas/tests/series/indexing/test_setitem.py index 36948c3dc05f3..e8521ad9dd5c6 100644 --- a/pandas/tests/series/indexing/test_setitem.py +++ b/pandas/tests/series/indexing/test_setitem.py @@ -640,47 +640,23 @@ def is_inplace(self): return True -class TestSetitemNATimedelta64Dtype(SetitemCastingEquivalents): - # some nat-like values should be cast to timedelta64 when inserting - # into a timedelta64 series. Others should coerce to object - # and retain their dtypes. - - @pytest.fixture - def obj(self): - return Series([0, 1, 2], dtype="m8[ns]") +class TestSetitemNADatetimeLikeDtype(SetitemCastingEquivalents): + # some nat-like values should be cast to datetime64/timedelta64 when + # inserting into a datetime64/timedelta64 series. Others should coerce + # to object and retain their dtypes. @pytest.fixture( - params=[NaT, np.timedelta64("NaT", "ns"), np.datetime64("NaT", "ns")] + params=["m8[ns]", "M8[ns]", "datetime64[ns, UTC]", "datetime64[ns, US/Central]"] ) - def val(self, request): + def dtype(self, request): return request.param @pytest.fixture - def is_inplace(self, val): - # cast to object iff val is datetime64("NaT") - return val is NaT or val.dtype.kind == "m" - - @pytest.fixture - def expected(self, obj, val, is_inplace): - dtype = obj.dtype if is_inplace else object - expected = Series([val] + list(obj[1:]), dtype=dtype) - return expected - - @pytest.fixture - def key(self): - return 0 - - -class TestSetitemNADatetime64Dtype(SetitemCastingEquivalents): - # some nat-like values should be cast to datetime64 when inserting - # into a datetime64 series. Others should coerce to object - # and retain their dtypes. - - @pytest.fixture(params=[None, "UTC", "US/Central"]) - def obj(self, request): - tz = request.param - dti = date_range("2016-01-01", periods=3, tz=tz) - return Series(dti) + def obj(self, dtype): + i8vals = date_range("2016-01-01", periods=3).asi8 + idx = Index(i8vals, dtype=dtype) + assert idx.dtype == dtype + return Series(idx) @pytest.fixture( params=[NaT, np.timedelta64("NaT", "ns"), np.datetime64("NaT", "ns")] @@ -690,12 +666,10 @@ def val(self, request): @pytest.fixture def is_inplace(self, val, obj): - if obj._values.tz is None: - # cast to object iff val is timedelta64("NaT") - return val is NaT or val.dtype.kind == "M" - - # otherwise we have to exclude tznaive dt64("NaT") - return val is NaT + # td64 -> cast to object iff val is datetime64("NaT") + # dt64 -> cast to object iff val is timedelta64("NaT") + # dt64tz -> cast to object with anything _but_ NaT + return val is NaT or obj.dtype == val.dtype @pytest.fixture def expected(self, obj, val, is_inplace): From 3a6f753c966f581bd610fd039e239b8c905cb89c Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 15 Feb 2021 17:40:40 -0800 Subject: [PATCH 2/3] TST/REF: remove tests now moved to test_setitem --- pandas/tests/series/indexing/test_indexing.py | 50 ------------------- 1 file changed, 50 deletions(-) diff --git a/pandas/tests/series/indexing/test_indexing.py b/pandas/tests/series/indexing/test_indexing.py index e047317acd24d..7889d46f66c99 100644 --- a/pandas/tests/series/indexing/test_indexing.py +++ b/pandas/tests/series/indexing/test_indexing.py @@ -542,56 +542,6 @@ def test_setitem_td64_non_nano(): tm.assert_series_equal(ser, expected) -@pytest.mark.parametrize( - "nat_val", - [ - pd.NaT, - np.timedelta64("NaT", "ns"), - np.datetime64("NaT", "ns"), - ], -) -@pytest.mark.parametrize("tz", [None, "UTC"]) -def test_dt64_series_assign_nat(nat_val, tz, indexer_sli): - # some nat-like values should be cast to datetime64 when inserting - # into a datetime64 series. Others should coerce to object - # and retain their dtypes. - dti = pd.date_range("2016-01-01", periods=3, tz=tz) - base = Series(dti) - expected = Series([pd.NaT] + list(dti[1:]), dtype=dti.dtype) - - should_cast = nat_val is pd.NaT or base.dtype == nat_val.dtype - if not should_cast: - expected = expected.astype(object) - - ser = base.copy(deep=True) - indexer_sli(ser)[0] = nat_val - tm.assert_series_equal(ser, expected) - - -@pytest.mark.parametrize( - "nat_val", - [ - pd.NaT, - np.timedelta64("NaT", "ns"), - np.datetime64("NaT", "ns"), - ], -) -def test_td64_series_assign_nat(nat_val, indexer_sli): - # some nat-like values should be cast to timedelta64 when inserting - # into a timedelta64 series. Others should coerce to object - # and retain their dtypes. - base = Series([0, 1, 2], dtype="m8[ns]") - expected = Series([pd.NaT, 1, 2], dtype="m8[ns]") - - should_cast = nat_val is pd.NaT or base.dtype == nat_val.dtype - if not should_cast: - expected = expected.astype(object) - - ser = base.copy(deep=True) - indexer_sli(ser)[0] = nat_val - tm.assert_series_equal(ser, expected) - - def test_underlying_data_conversion(): # GH 4080 df = DataFrame({c: [1, 2, 3] for c in ["a", "b", "c"]}) From d024f83685a1c33b8ed86b047bd6af5f1480403e Mon Sep 17 00:00:00 2001 From: Brock Date: Mon, 15 Feb 2021 18:23:47 -0800 Subject: [PATCH 3/3] TST: cram more tests into SetitemCastingEquivalents --- pandas/tests/series/indexing/test_setitem.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/pandas/tests/series/indexing/test_setitem.py b/pandas/tests/series/indexing/test_setitem.py index e8521ad9dd5c6..18a870b1b0b9c 100644 --- a/pandas/tests/series/indexing/test_setitem.py +++ b/pandas/tests/series/indexing/test_setitem.py @@ -167,15 +167,6 @@ def test_setitem_boolean_python_list(self, func): expected = Series(["a", "b", "c"]) tm.assert_series_equal(ser, expected) - @pytest.mark.parametrize("value", [None, NaT, np.nan]) - def test_setitem_boolean_td64_values_cast_na(self, value): - # GH#18586 - series = Series([0, 1, 2], dtype="timedelta64[ns]") - mask = series == series[0] - series[mask] = value - expected = Series([NaT, 1, 2], dtype="timedelta64[ns]") - tm.assert_series_equal(series, expected) - def test_setitem_boolean_nullable_int_types(self, any_nullable_numeric_dtype): # GH: 26468 ser = Series([5, 6, 7, 8], dtype=any_nullable_numeric_dtype) @@ -644,6 +635,7 @@ class TestSetitemNADatetimeLikeDtype(SetitemCastingEquivalents): # some nat-like values should be cast to datetime64/timedelta64 when # inserting into a datetime64/timedelta64 series. Others should coerce # to object and retain their dtypes. + # GH#18586 for td64 and boolean mask case @pytest.fixture( params=["m8[ns]", "M8[ns]", "datetime64[ns, UTC]", "datetime64[ns, US/Central]"] @@ -659,7 +651,13 @@ def obj(self, dtype): return Series(idx) @pytest.fixture( - params=[NaT, np.timedelta64("NaT", "ns"), np.datetime64("NaT", "ns")] + params=[ + None, + np.nan, + NaT, + np.timedelta64("NaT", "ns"), + np.datetime64("NaT", "ns"), + ] ) def val(self, request): return request.param @@ -669,7 +667,7 @@ def is_inplace(self, val, obj): # td64 -> cast to object iff val is datetime64("NaT") # dt64 -> cast to object iff val is timedelta64("NaT") # dt64tz -> cast to object with anything _but_ NaT - return val is NaT or obj.dtype == val.dtype + return val is NaT or val is None or val is np.nan or obj.dtype == val.dtype @pytest.fixture def expected(self, obj, val, is_inplace):