diff --git a/pandas/_testing/asserters.py b/pandas/_testing/asserters.py index dbc26d6e61d01..08f92698ed9a0 100644 --- a/pandas/_testing/asserters.py +++ b/pandas/_testing/asserters.py @@ -1385,7 +1385,8 @@ def assert_equal(left, right, **kwargs): assert kwargs == {} assert left == right else: - raise NotImplementedError(type(left)) + assert kwargs == {} + assert_almost_equal(left, right) def assert_sp_array_equal(left, right): diff --git a/pandas/tests/frame/methods/test_convert.py b/pandas/tests/frame/methods/test_convert.py index 13fec9829c3db..118af9f532abe 100644 --- a/pandas/tests/frame/methods/test_convert.py +++ b/pandas/tests/frame/methods/test_convert.py @@ -45,6 +45,8 @@ def test_convert_objects(self, float_string_frame): with pytest.raises(ValueError, match="invalid literal"): converted["H"].astype("int32") + def test_convert_mixed_single_column(self): + # GH#4119, not converting a mixed type (e.g.floats and object) # mixed in a single column df = DataFrame({"s": Series([1, "na", 3, 4])}) result = df._convert(datetime=True, numeric=True) diff --git a/pandas/tests/series/accessors/test_cat_accessor.py b/pandas/tests/series/accessors/test_cat_accessor.py index 9dfb36a71c861..1a038839a67c9 100644 --- a/pandas/tests/series/accessors/test_cat_accessor.py +++ b/pandas/tests/series/accessors/test_cat_accessor.py @@ -14,11 +14,6 @@ timedelta_range, ) import pandas._testing as tm -from pandas.core.arrays import ( - DatetimeArray, - PeriodArray, - TimedeltaArray, -) from pandas.core.arrays.categorical import CategoricalAccessor from pandas.core.indexes.accessors import Properties @@ -163,86 +158,84 @@ def test_categorical_delegations(self): ) tm.assert_series_equal(result, expected) - def test_dt_accessor_api_for_categorical(self): + @pytest.mark.parametrize( + "idx", + [ + date_range("1/1/2015", periods=5), + date_range("1/1/2015", periods=5, tz="MET"), + period_range("1/1/2015", freq="D", periods=5), + timedelta_range("1 days", "10 days"), + ], + ) + def test_dt_accessor_api_for_categorical(self, idx): # https://github.com/pandas-dev/pandas/issues/10661 - s_dr = Series(date_range("1/1/2015", periods=5, tz="MET")) - c_dr = s_dr.astype("category") - - s_pr = Series(period_range("1/1/2015", freq="D", periods=5)) - c_pr = s_pr.astype("category") - - s_tdr = Series(timedelta_range("1 days", "10 days")) - c_tdr = s_tdr.astype("category") + ser = Series(idx) + cat = ser.astype("category") # only testing field (like .day) # and bool (is_month_start) - get_ops = lambda x: x._datetimelike_ops - - test_data = [ - ("Datetime", get_ops(DatetimeArray), s_dr, c_dr), - ("Period", get_ops(PeriodArray), s_pr, c_pr), - ("Timedelta", get_ops(TimedeltaArray), s_tdr, c_tdr), - ] + attr_names = type(ser._values)._datetimelike_ops - assert isinstance(c_dr.dt, Properties) + assert isinstance(cat.dt, Properties) special_func_defs = [ ("strftime", ("%Y-%m-%d",), {}), - ("tz_convert", ("EST",), {}), ("round", ("D",), {}), ("floor", ("D",), {}), ("ceil", ("D",), {}), ("asfreq", ("D",), {}), - # FIXME: don't leave commented-out - # ('tz_localize', ("UTC",), {}), ] + if idx.dtype == "M8[ns]": + # exclude dt64tz since that is already localized and would raise + tup = ("tz_localize", ("UTC",), {}) + special_func_defs.append(tup) + elif idx.dtype.kind == "M": + # exclude dt64 since that is not localized so would raise + tup = ("tz_convert", ("EST",), {}) + special_func_defs.append(tup) + _special_func_names = [f[0] for f in special_func_defs] - # the series is already localized - _ignore_names = ["tz_localize", "components"] - - for name, attr_names, s, c in test_data: - func_names = [ - f - for f in dir(s.dt) - if not ( - f.startswith("_") - or f in attr_names - or f in _special_func_names - or f in _ignore_names - ) - ] - - func_defs = [(f, (), {}) for f in func_names] - for f_def in special_func_defs: - if f_def[0] in dir(s.dt): - func_defs.append(f_def) - - for func, args, kwargs in func_defs: - with warnings.catch_warnings(): - if func == "to_period": - # dropping TZ - warnings.simplefilter("ignore", UserWarning) - res = getattr(c.dt, func)(*args, **kwargs) - exp = getattr(s.dt, func)(*args, **kwargs) - - tm.assert_equal(res, exp) - - for attr in attr_names: - if attr in ["week", "weekofyear"]: - # GH#33595 Deprecate week and weekofyear - continue - res = getattr(c.dt, attr) - exp = getattr(s.dt, attr) - - if isinstance(res, DataFrame): - tm.assert_frame_equal(res, exp) - elif isinstance(res, Series): - tm.assert_series_equal(res, exp) - else: - tm.assert_almost_equal(res, exp) + _ignore_names = ["components", "tz_localize", "tz_convert"] + + func_names = [ + fname + for fname in dir(ser.dt) + if not ( + fname.startswith("_") + or fname in attr_names + or fname in _special_func_names + or fname in _ignore_names + ) + ] + + func_defs = [(fname, (), {}) for fname in func_names] + + for f_def in special_func_defs: + if f_def[0] in dir(ser.dt): + func_defs.append(f_def) + + for func, args, kwargs in func_defs: + with warnings.catch_warnings(): + if func == "to_period": + # dropping TZ + warnings.simplefilter("ignore", UserWarning) + res = getattr(cat.dt, func)(*args, **kwargs) + exp = getattr(ser.dt, func)(*args, **kwargs) + + tm.assert_equal(res, exp) + + for attr in attr_names: + if attr in ["week", "weekofyear"]: + # GH#33595 Deprecate week and weekofyear + continue + res = getattr(cat.dt, attr) + exp = getattr(ser.dt, attr) + + tm.assert_equal(res, exp) + def test_dt_accessor_api_for_categorical_invalid(self): invalid = Series([1, 2, 3]).astype("category") msg = "Can only use .dt accessor with datetimelike" diff --git a/pandas/tests/series/methods/test_convert.py b/pandas/tests/series/methods/test_convert.py index 346f74d798de9..4832780e6d0d3 100644 --- a/pandas/tests/series/methods/test_convert.py +++ b/pandas/tests/series/methods/test_convert.py @@ -32,6 +32,7 @@ def test_convert(self): results = ser._convert(timedelta=True) tm.assert_series_equal(results, ser) + def test_convert_numeric_strings_with_other_true_args(self): # test pass-through and non-conversion when other types selected ser = Series(["1.0", "2.0", "3.0"]) results = ser._convert(datetime=True, numeric=True, timedelta=True) @@ -40,6 +41,7 @@ def test_convert(self): results = ser._convert(True, False, True) tm.assert_series_equal(results, ser) + def test_convert_datetime_objects(self): ser = Series( [datetime(2001, 1, 1, 0, 0), datetime(2001, 1, 1, 0, 0)], dtype="O" ) @@ -49,6 +51,27 @@ def test_convert(self): results = ser._convert(datetime=False, numeric=True, timedelta=True) tm.assert_series_equal(results, ser) + def test_convert_datetime64(self): + # no-op if already dt64 dtype + ser = Series( + [ + datetime(2001, 1, 1, 0, 0), + datetime(2001, 1, 2, 0, 0), + datetime(2001, 1, 3, 0, 0), + ] + ) + + result = ser._convert(datetime=True) + expected = Series( + [Timestamp("20010101"), Timestamp("20010102"), Timestamp("20010103")], + dtype="M8[ns]", + ) + tm.assert_series_equal(result, expected) + + result = ser._convert(datetime=True) + tm.assert_series_equal(result, expected) + + def test_convert_timedeltas(self): td = datetime(2001, 1, 1, 0, 0) - datetime(2000, 1, 1, 0, 0) ser = Series([td, td], dtype="O") results = ser._convert(datetime=True, numeric=True, timedelta=True) @@ -57,6 +80,7 @@ def test_convert(self): results = ser._convert(True, True, False) tm.assert_series_equal(results, ser) + def test_convert_numeric_strings(self): ser = Series([1.0, 2, 3], index=["a", "b", "c"]) result = ser._convert(numeric=True) tm.assert_series_equal(result, ser) @@ -79,6 +103,7 @@ def test_convert(self): expected["a"] = np.nan tm.assert_series_equal(result, expected) + def test_convert_mixed_type_noop(self): # GH 4119, not converting a mixed type (e.g.floats and object) ser = Series([1, "na", 3, 4]) result = ser._convert(datetime=True, numeric=True) @@ -89,25 +114,7 @@ def test_convert(self): result = ser._convert(datetime=True, numeric=True) tm.assert_series_equal(result, expected) - # dates - ser = Series( - [ - datetime(2001, 1, 1, 0, 0), - datetime(2001, 1, 2, 0, 0), - datetime(2001, 1, 3, 0, 0), - ] - ) - - result = ser._convert(datetime=True) - expected = Series( - [Timestamp("20010101"), Timestamp("20010102"), Timestamp("20010103")], - dtype="M8[ns]", - ) - tm.assert_series_equal(result, expected) - - result = ser._convert(datetime=True) - tm.assert_series_equal(result, expected) - + def test_convert_preserve_non_object(self): # preserve if non-object ser = Series([1], dtype="float32") result = ser._convert(datetime=True)