diff --git a/pandas/tests/indexes/datetimelike_/test_is_monotonic.py b/pandas/tests/indexes/datetimelike_/test_is_monotonic.py new file mode 100644 index 0000000000000..22247c982edbc --- /dev/null +++ b/pandas/tests/indexes/datetimelike_/test_is_monotonic.py @@ -0,0 +1,46 @@ +from pandas import ( + Index, + NaT, + date_range, +) + + +def test_is_monotonic_with_nat(): + # GH#31437 + # PeriodIndex.is_monotonic should behave analogously to DatetimeIndex, + # in particular never be monotonic when we have NaT + dti = date_range("2016-01-01", periods=3) + pi = dti.to_period("D") + tdi = Index(dti.view("timedelta64[ns]")) + + for obj in [pi, pi._engine, dti, dti._engine, tdi, tdi._engine]: + if isinstance(obj, Index): + # i.e. not Engines + assert obj.is_monotonic + assert obj.is_monotonic_increasing + assert not obj.is_monotonic_decreasing + assert obj.is_unique + + dti1 = dti.insert(0, NaT) + pi1 = dti1.to_period("D") + tdi1 = Index(dti1.view("timedelta64[ns]")) + + for obj in [pi1, pi1._engine, dti1, dti1._engine, tdi1, tdi1._engine]: + if isinstance(obj, Index): + # i.e. not Engines + assert not obj.is_monotonic + assert not obj.is_monotonic_increasing + assert not obj.is_monotonic_decreasing + assert obj.is_unique + + dti2 = dti.insert(3, NaT) + pi2 = dti2.to_period("H") + tdi2 = Index(dti2.view("timedelta64[ns]")) + + for obj in [pi2, pi2._engine, dti2, dti2._engine, tdi2, tdi2._engine]: + if isinstance(obj, Index): + # i.e. not Engines + assert not obj.is_monotonic + assert not obj.is_monotonic_increasing + assert not obj.is_monotonic_decreasing + assert obj.is_unique diff --git a/pandas/tests/indexes/datetimes/methods/test_isocalendar.py b/pandas/tests/indexes/datetimes/methods/test_isocalendar.py new file mode 100644 index 0000000000000..128a8b3e10eb3 --- /dev/null +++ b/pandas/tests/indexes/datetimes/methods/test_isocalendar.py @@ -0,0 +1,20 @@ +from pandas import ( + DataFrame, + DatetimeIndex, +) +import pandas._testing as tm + + +def test_isocalendar_returns_correct_values_close_to_new_year_with_tz(): + # GH#6538: Check that DatetimeIndex and its TimeStamp elements + # return the same weekofyear accessor close to new year w/ tz + dates = ["2013/12/29", "2013/12/30", "2013/12/31"] + dates = DatetimeIndex(dates, tz="Europe/Brussels") + result = dates.isocalendar() + expected_data_frame = DataFrame( + [[2013, 52, 7], [2014, 1, 1], [2014, 1, 2]], + columns=["year", "week", "day"], + index=dates, + dtype="UInt32", + ) + tm.assert_frame_equal(result, expected_data_frame) diff --git a/pandas/tests/indexes/datetimes/test_asof.py b/pandas/tests/indexes/datetimes/test_asof.py index c794aefc6a48b..7adc400302cb9 100644 --- a/pandas/tests/indexes/datetimes/test_asof.py +++ b/pandas/tests/indexes/datetimes/test_asof.py @@ -1,8 +1,12 @@ +from datetime import timedelta + from pandas import ( Index, Timestamp, date_range, + isna, ) +import pandas._testing as tm class TestAsOf: @@ -12,3 +16,16 @@ def test_asof_partial(self): result = index.asof("2010-02") assert result == expected assert not isinstance(result, Index) + + def test_asof(self): + index = tm.makeDateIndex(100) + + dt = index[0] + assert index.asof(dt) == dt + assert isna(index.asof(dt - timedelta(1))) + + dt = index[-1] + assert index.asof(dt + timedelta(1)) == dt + + dt = index[0].to_pydatetime() + assert isinstance(index.asof(dt), Timestamp) diff --git a/pandas/tests/indexes/datetimes/test_freq_attr.py b/pandas/tests/indexes/datetimes/test_freq_attr.py new file mode 100644 index 0000000000000..f5821a316358d --- /dev/null +++ b/pandas/tests/indexes/datetimes/test_freq_attr.py @@ -0,0 +1,61 @@ +import pytest + +from pandas import ( + DatetimeIndex, + date_range, +) + +from pandas.tseries.offsets import ( + BDay, + DateOffset, + Day, + Hour, +) + + +class TestFreq: + def test_freq_setter_errors(self): + # GH#20678 + idx = DatetimeIndex(["20180101", "20180103", "20180105"]) + + # setting with an incompatible freq + msg = ( + "Inferred frequency 2D from passed values does not conform to " + "passed frequency 5D" + ) + with pytest.raises(ValueError, match=msg): + idx._data.freq = "5D" + + # setting with non-freq string + with pytest.raises(ValueError, match="Invalid frequency"): + idx._data.freq = "foo" + + @pytest.mark.parametrize("values", [["20180101", "20180103", "20180105"], []]) + @pytest.mark.parametrize("freq", ["2D", Day(2), "2B", BDay(2), "48H", Hour(48)]) + @pytest.mark.parametrize("tz", [None, "US/Eastern"]) + def test_freq_setter(self, values, freq, tz): + # GH#20678 + idx = DatetimeIndex(values, tz=tz) + + # can set to an offset, converting from string if necessary + idx._data.freq = freq + assert idx.freq == freq + assert isinstance(idx.freq, DateOffset) + + # can reset to None + idx._data.freq = None + assert idx.freq is None + + def test_freq_view_safe(self): + # Setting the freq for one DatetimeIndex shouldn't alter the freq + # for another that views the same data + + dti = date_range("2016-01-01", periods=5) + dta = dti._data + + dti2 = DatetimeIndex(dta)._with_freq(None) + assert dti2.freq is None + + # Original was not altered + assert dti.freq == "D" + assert dta.freq == "D" diff --git a/pandas/tests/indexes/datetimes/test_misc.py b/pandas/tests/indexes/datetimes/test_misc.py index f0757d0ba555e..44c353315562a 100644 --- a/pandas/tests/indexes/datetimes/test_misc.py +++ b/pandas/tests/indexes/datetimes/test_misc.py @@ -297,21 +297,6 @@ def test_week_and_weekofyear_are_deprecated(): idx.weekofyear -def test_isocalendar_returns_correct_values_close_to_new_year_with_tz(): - # GH 6538: Check that DatetimeIndex and its TimeStamp elements - # return the same weekofyear accessor close to new year w/ tz - dates = ["2013/12/29", "2013/12/30", "2013/12/31"] - dates = DatetimeIndex(dates, tz="Europe/Brussels") - result = dates.isocalendar() - expected_data_frame = pd.DataFrame( - [[2013, 52, 7], [2014, 1, 1], [2014, 1, 2]], - columns=["year", "week", "day"], - index=dates, - dtype="UInt32", - ) - tm.assert_frame_equal(result, expected_data_frame) - - def test_add_timedelta_preserves_freq(): # GH#37295 should hold for any DTI with freq=None or Tick freq tz = "Canada/Eastern" diff --git a/pandas/tests/indexes/datetimes/test_ops.py b/pandas/tests/indexes/datetimes/test_ops.py index 7df94b5820e5d..d6ef4198fad2e 100644 --- a/pandas/tests/indexes/datetimes/test_ops.py +++ b/pandas/tests/indexes/datetimes/test_ops.py @@ -6,43 +6,17 @@ from pandas.compat import IS64 from pandas import ( - DateOffset, DatetimeIndex, Index, - Series, bdate_range, date_range, ) import pandas._testing as tm -from pandas.tseries.offsets import ( - BDay, - Day, - Hour, -) - START, END = datetime(2009, 1, 1), datetime(2010, 1, 1) class TestDatetimeIndexOps: - def test_ops_properties_basic(self, datetime_series): - - # sanity check that the behavior didn't change - # GH#7206 - for op in ["year", "day", "second", "weekday"]: - msg = f"'Series' object has no attribute '{op}'" - with pytest.raises(AttributeError, match=msg): - getattr(datetime_series, op) - - # attribute access should still work! - s = Series({"year": 2000, "month": 1, "day": 10}) - assert s.year == 2000 - assert s.month == 1 - assert s.day == 10 - msg = "'Series' object has no attribute 'weekday'" - with pytest.raises(AttributeError, match=msg): - s.weekday - @pytest.mark.parametrize( "freq,expected", [ @@ -74,72 +48,28 @@ def test_infer_freq(self, freq_sample): tm.assert_index_equal(idx, result) assert result.freq == freq_sample - @pytest.mark.parametrize("values", [["20180101", "20180103", "20180105"], []]) - @pytest.mark.parametrize("freq", ["2D", Day(2), "2B", BDay(2), "48H", Hour(48)]) - @pytest.mark.parametrize("tz", [None, "US/Eastern"]) - def test_freq_setter(self, values, freq, tz): - # GH 20678 - idx = DatetimeIndex(values, tz=tz) - - # can set to an offset, converting from string if necessary - idx._data.freq = freq - assert idx.freq == freq - assert isinstance(idx.freq, DateOffset) - - # can reset to None - idx._data.freq = None - assert idx.freq is None - - def test_freq_setter_errors(self): - # GH 20678 - idx = DatetimeIndex(["20180101", "20180103", "20180105"]) - - # setting with an incompatible freq - msg = ( - "Inferred frequency 2D from passed values does not conform to " - "passed frequency 5D" - ) - with pytest.raises(ValueError, match=msg): - idx._data.freq = "5D" - - # setting with non-freq string - with pytest.raises(ValueError, match="Invalid frequency"): - idx._data.freq = "foo" - - def test_freq_view_safe(self): - # Setting the freq for one DatetimeIndex shouldn't alter the freq - # for another that views the same data - - dti = date_range("2016-01-01", periods=5) - dta = dti._data - - dti2 = DatetimeIndex(dta)._with_freq(None) - assert dti2.freq is None - - # Original was not altered - assert dti.freq == "D" - assert dta.freq == "D" - +@pytest.mark.parametrize("freq", ["B", "C"]) class TestBusinessDatetimeIndex: - def setup_method(self, method): - self.rng = bdate_range(START, END) + @pytest.fixture + def rng(self, freq): + return bdate_range(START, END, freq=freq) - def test_comparison(self): - d = self.rng[10] + def test_comparison(self, rng): + d = rng[10] - comp = self.rng > d + comp = rng > d assert comp[11] assert not comp[9] - def test_copy(self): - cp = self.rng.copy() + def test_copy(self, rng): + cp = rng.copy() repr(cp) - tm.assert_index_equal(cp, self.rng) + tm.assert_index_equal(cp, rng) - def test_identical(self): - t1 = self.rng.copy() - t2 = self.rng.copy() + def test_identical(self, rng): + t1 = rng.copy() + t2 = rng.copy() assert t1.identical(t2) # name @@ -153,20 +83,3 @@ def test_identical(self): t2v = Index(t2.values) assert t1.equals(t2v) assert not t1.identical(t2v) - - -class TestCustomDatetimeIndex: - def setup_method(self, method): - self.rng = bdate_range(START, END, freq="C") - - def test_comparison(self): - d = self.rng[10] - - comp = self.rng > d - assert comp[11] - assert not comp[9] - - def test_copy(self): - cp = self.rng.copy() - repr(cp) - tm.assert_index_equal(cp, self.rng) diff --git a/pandas/tests/indexes/period/test_freq_attr.py b/pandas/tests/indexes/period/test_freq_attr.py new file mode 100644 index 0000000000000..3bf3e700e5e72 --- /dev/null +++ b/pandas/tests/indexes/period/test_freq_attr.py @@ -0,0 +1,21 @@ +import pytest + +from pandas import ( + offsets, + period_range, +) +import pandas._testing as tm + + +class TestFreq: + def test_freq_setter_deprecated(self): + # GH#20678 + idx = period_range("2018Q1", periods=4, freq="Q") + + # no warning for getter + with tm.assert_produces_warning(None): + idx.freq + + # warning for setter + with pytest.raises(AttributeError, match="can't set attribute"): + idx.freq = offsets.Day() diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index a7dad4e7f352c..f07107e9d3277 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -38,12 +38,6 @@ def index(self, request): def test_pickle_compat_construction(self): super().test_pickle_compat_construction() - @pytest.mark.parametrize("freq", ["D", "M", "A"]) - def test_pickle_round_trip(self, freq): - idx = PeriodIndex(["2016-05-16", "NaT", NaT, np.NaN], freq=freq) - result = tm.round_trip_pickle(idx) - tm.assert_index_equal(result, idx) - def test_where(self): # This is handled in test_indexing pass @@ -307,13 +301,6 @@ def test_with_multi_index(self): assert isinstance(s.index.values[0][0], Period) - def test_pickle_freq(self): - # GH2891 - prng = period_range("1/1/2011", "1/1/2012", freq="M") - new_prng = tm.round_trip_pickle(prng) - assert new_prng.freq == offsets.MonthEnd() - assert new_prng.freqstr == "M" - def test_map(self): # test_map_dictlike generally tests @@ -341,47 +328,6 @@ def test_maybe_convert_timedelta(): pi._maybe_convert_timedelta(offset) -def test_is_monotonic_with_nat(): - # GH#31437 - # PeriodIndex.is_monotonic should behave analogously to DatetimeIndex, - # in particular never be monotonic when we have NaT - dti = date_range("2016-01-01", periods=3) - pi = dti.to_period("D") - tdi = Index(dti.view("timedelta64[ns]")) - - for obj in [pi, pi._engine, dti, dti._engine, tdi, tdi._engine]: - if isinstance(obj, Index): - # i.e. not Engines - assert obj.is_monotonic - assert obj.is_monotonic_increasing - assert not obj.is_monotonic_decreasing - assert obj.is_unique - - dti1 = dti.insert(0, NaT) - pi1 = dti1.to_period("D") - tdi1 = Index(dti1.view("timedelta64[ns]")) - - for obj in [pi1, pi1._engine, dti1, dti1._engine, tdi1, tdi1._engine]: - if isinstance(obj, Index): - # i.e. not Engines - assert not obj.is_monotonic - assert not obj.is_monotonic_increasing - assert not obj.is_monotonic_decreasing - assert obj.is_unique - - dti2 = dti.insert(3, NaT) - pi2 = dti2.to_period("H") - tdi2 = Index(dti2.view("timedelta64[ns]")) - - for obj in [pi2, pi2._engine, dti2, dti2._engine, tdi2, tdi2._engine]: - if isinstance(obj, Index): - # i.e. not Engines - assert not obj.is_monotonic - assert not obj.is_monotonic_increasing - assert not obj.is_monotonic_decreasing - assert obj.is_unique - - @pytest.mark.parametrize("array", [True, False]) def test_dunder_array(array): obj = PeriodIndex(["2000-01-01", "2001-01-01"], freq="D") diff --git a/pandas/tests/indexes/period/test_pickle.py b/pandas/tests/indexes/period/test_pickle.py new file mode 100644 index 0000000000000..82f906d1e361f --- /dev/null +++ b/pandas/tests/indexes/period/test_pickle.py @@ -0,0 +1,26 @@ +import numpy as np +import pytest + +from pandas import ( + NaT, + PeriodIndex, + period_range, +) +import pandas._testing as tm + +from pandas.tseries import offsets + + +class TestPickle: + @pytest.mark.parametrize("freq", ["D", "M", "A"]) + def test_pickle_round_trip(self, freq): + idx = PeriodIndex(["2016-05-16", "NaT", NaT, np.NaN], freq=freq) + result = tm.round_trip_pickle(idx) + tm.assert_index_equal(result, idx) + + def test_pickle_freq(self): + # GH#2891 + prng = period_range("1/1/2011", "1/1/2012", freq="M") + new_prng = tm.round_trip_pickle(prng) + assert new_prng.freq == offsets.MonthEnd() + assert new_prng.freqstr == "M" diff --git a/pandas/tests/indexes/period/test_ops.py b/pandas/tests/indexes/period/test_resolution.py similarity index 56% rename from pandas/tests/indexes/period/test_ops.py rename to pandas/tests/indexes/period/test_resolution.py index 9ebe44fb16c8d..7ecbde75cfa47 100644 --- a/pandas/tests/indexes/period/test_ops.py +++ b/pandas/tests/indexes/period/test_resolution.py @@ -1,10 +1,9 @@ import pytest import pandas as pd -import pandas._testing as tm -class TestPeriodIndexOps: +class TestResolution: @pytest.mark.parametrize( "freq,expected", [ @@ -22,15 +21,3 @@ class TestPeriodIndexOps: def test_resolution(self, freq, expected): idx = pd.period_range(start="2013-04-01", periods=30, freq=freq) assert idx.resolution == expected - - def test_freq_setter_deprecated(self): - # GH 20678 - idx = pd.period_range("2018Q1", periods=4, freq="Q") - - # no warning for getter - with tm.assert_produces_warning(None): - idx.freq - - # warning for setter - with pytest.raises(AttributeError, match="can't set attribute"): - idx.freq = pd.offsets.Day() diff --git a/pandas/tests/indexes/test_any_index.py b/pandas/tests/indexes/test_any_index.py index 39a1ddcbc8a6a..f7dafd78a801f 100644 --- a/pandas/tests/indexes/test_any_index.py +++ b/pandas/tests/indexes/test_any_index.py @@ -84,6 +84,13 @@ def test_is_type_compatible_deprecation(index): index.is_type_compatible(index.inferred_type) +def test_is_mixed_deprecated(index): + # GH#32922 + msg = "Index.is_mixed is deprecated" + with tm.assert_produces_warning(FutureWarning, match=msg): + index.is_mixed() + + class TestConversion: def test_to_series(self, index): # assert that we are creating a copy of the index diff --git a/pandas/tests/indexes/test_base.py b/pandas/tests/indexes/test_base.py index 50be69fb93d7c..7f9a5c0b50595 100644 --- a/pandas/tests/indexes/test_base.py +++ b/pandas/tests/indexes/test_base.py @@ -29,7 +29,6 @@ TimedeltaIndex, Timestamp, date_range, - isna, period_range, ) import pandas._testing as tm @@ -395,15 +394,6 @@ def test_constructor_empty_special(self, empty, klass): assert isinstance(empty, klass) assert not len(empty) - def test_constructor_overflow_int64(self): - # see gh-15832 - msg = ( - "The elements provided in the data cannot " - "all be casted to the dtype int64" - ) - with pytest.raises(OverflowError, match=msg): - Index([np.iinfo(np.uint64).max - 1], dtype="int64") - @pytest.mark.parametrize( "index", [ @@ -502,18 +492,6 @@ def test_is_(self): ind2 = Index(arr, copy=False) assert not ind1.is_(ind2) - @pytest.mark.parametrize("index", ["datetime"], indirect=True) - def test_asof(self, index): - d = index[0] - assert index.asof(d) == d - assert isna(index.asof(d - timedelta(1))) - - d = index[-1] - assert index.asof(d + timedelta(1)) == d - - d = index[0].to_pydatetime() - assert isinstance(index.asof(d), Timestamp) - def test_asof_numeric_vs_bool_raises(self): left = Index([1, 2, 3]) right = Index([True, False]) @@ -699,12 +677,6 @@ def test_append_empty_preserve_name(self, name, expected): result = left.append(right) assert result.name == expected - def test_is_mixed_deprecated(self, simple_index): - # GH#32922 - index = simple_index - with tm.assert_produces_warning(FutureWarning): - index.is_mixed() - @pytest.mark.parametrize( "index, expected", [ diff --git a/pandas/tests/indexes/test_index_new.py b/pandas/tests/indexes/test_index_new.py index 293aa6dd57124..5c5ec7219d2d7 100644 --- a/pandas/tests/indexes/test_index_new.py +++ b/pandas/tests/indexes/test_index_new.py @@ -272,3 +272,14 @@ def __array__(self, dtype=None) -> np.ndarray: expected = Index(array) result = Index(ArrayLike(array)) tm.assert_index_equal(result, expected) + + +class TestIndexConstructionErrors: + def test_constructor_overflow_int64(self): + # see GH#15832 + msg = ( + "The elements provided in the data cannot " + "all be casted to the dtype int64" + ) + with pytest.raises(OverflowError, match=msg): + Index([np.iinfo(np.uint64).max - 1], dtype="int64") diff --git a/pandas/tests/indexes/timedeltas/test_freq_attr.py b/pandas/tests/indexes/timedeltas/test_freq_attr.py new file mode 100644 index 0000000000000..39b9c11aa833c --- /dev/null +++ b/pandas/tests/indexes/timedeltas/test_freq_attr.py @@ -0,0 +1,61 @@ +import pytest + +from pandas import TimedeltaIndex + +from pandas.tseries.offsets import ( + DateOffset, + Day, + Hour, +) + + +class TestFreq: + @pytest.mark.parametrize("values", [["0 days", "2 days", "4 days"], []]) + @pytest.mark.parametrize("freq", ["2D", Day(2), "48H", Hour(48)]) + def test_freq_setter(self, values, freq): + # GH#20678 + idx = TimedeltaIndex(values) + + # can set to an offset, converting from string if necessary + idx._data.freq = freq + assert idx.freq == freq + assert isinstance(idx.freq, DateOffset) + + # can reset to None + idx._data.freq = None + assert idx.freq is None + + def test_freq_setter_errors(self): + # GH#20678 + idx = TimedeltaIndex(["0 days", "2 days", "4 days"]) + + # setting with an incompatible freq + msg = ( + "Inferred frequency 2D from passed values does not conform to " + "passed frequency 5D" + ) + with pytest.raises(ValueError, match=msg): + idx._data.freq = "5D" + + # setting with a non-fixed frequency + msg = r"<2 \* BusinessDays> is a non-fixed frequency" + with pytest.raises(ValueError, match=msg): + idx._data.freq = "2B" + + # setting with non-freq string + with pytest.raises(ValueError, match="Invalid frequency"): + idx._data.freq = "foo" + + def test_freq_view_safe(self): + # Setting the freq for one TimedeltaIndex shouldn't alter the freq + # for another that views the same data + + tdi = TimedeltaIndex(["0 days", "2 days", "4 days"], freq="2D") + tda = tdi._data + + tdi2 = TimedeltaIndex(tda)._with_freq(None) + assert tdi2.freq is None + + # Original was not altered + assert tdi.freq == "2D" + assert tda.freq == "2D" diff --git a/pandas/tests/indexes/timedeltas/test_indexing.py b/pandas/tests/indexes/timedeltas/test_indexing.py index fc8abb83ed302..66fdaa2778600 100644 --- a/pandas/tests/indexes/timedeltas/test_indexing.py +++ b/pandas/tests/indexes/timedeltas/test_indexing.py @@ -340,3 +340,17 @@ def test_slice_invalid_str_with_timedeltaindex( indexer_sl(obj)[:"foo"] with pytest.raises(TypeError, match=msg): indexer_sl(obj)[tdi[0] : "foo"] + + +class TestContains: + def test_contains_nonunique(self): + # GH#9512 + for vals in ( + [0, 1, 0], + [0, 0, -1], + [0, -1, -1], + ["00:01:00", "00:01:00", "00:02:00"], + ["00:01:00", "00:01:00", "00:00:01"], + ): + idx = TimedeltaIndex(vals) + assert idx[0] in idx diff --git a/pandas/tests/indexes/timedeltas/test_ops.py b/pandas/tests/indexes/timedeltas/test_ops.py index f5d601bcfbcd1..f6013baf86edc 100644 --- a/pandas/tests/indexes/timedeltas/test_ops.py +++ b/pandas/tests/indexes/timedeltas/test_ops.py @@ -1,86 +1,14 @@ -import pytest - from pandas import ( TimedeltaIndex, timedelta_range, ) import pandas._testing as tm -from pandas.tseries.offsets import ( - DateOffset, - Day, - Hour, -) - class TestTimedeltaIndexOps: - def test_nonunique_contains(self): - # GH 9512 - for idx in map( - TimedeltaIndex, - ( - [0, 1, 0], - [0, 0, -1], - [0, -1, -1], - ["00:01:00", "00:01:00", "00:02:00"], - ["00:01:00", "00:01:00", "00:00:01"], - ), - ): - assert idx[0] in idx - def test_infer_freq(self, freq_sample): # GH#11018 idx = timedelta_range("1", freq=freq_sample, periods=10) result = TimedeltaIndex(idx.asi8, freq="infer") tm.assert_index_equal(idx, result) assert result.freq == freq_sample - - @pytest.mark.parametrize("values", [["0 days", "2 days", "4 days"], []]) - @pytest.mark.parametrize("freq", ["2D", Day(2), "48H", Hour(48)]) - def test_freq_setter(self, values, freq): - # GH 20678 - idx = TimedeltaIndex(values) - - # can set to an offset, converting from string if necessary - idx._data.freq = freq - assert idx.freq == freq - assert isinstance(idx.freq, DateOffset) - - # can reset to None - idx._data.freq = None - assert idx.freq is None - - def test_freq_setter_errors(self): - # GH 20678 - idx = TimedeltaIndex(["0 days", "2 days", "4 days"]) - - # setting with an incompatible freq - msg = ( - "Inferred frequency 2D from passed values does not conform to " - "passed frequency 5D" - ) - with pytest.raises(ValueError, match=msg): - idx._data.freq = "5D" - - # setting with a non-fixed frequency - msg = r"<2 \* BusinessDays> is a non-fixed frequency" - with pytest.raises(ValueError, match=msg): - idx._data.freq = "2B" - - # setting with non-freq string - with pytest.raises(ValueError, match="Invalid frequency"): - idx._data.freq = "foo" - - def test_freq_view_safe(self): - # Setting the freq for one TimedeltaIndex shouldn't alter the freq - # for another that views the same data - - tdi = TimedeltaIndex(["0 days", "2 days", "4 days"], freq="2D") - tda = tdi._data - - tdi2 = TimedeltaIndex(tda)._with_freq(None) - assert tdi2.freq is None - - # Original was not altered - assert tdi.freq == "2D" - assert tda.freq == "2D" diff --git a/pandas/tests/series/test_api.py b/pandas/tests/series/test_api.py index aaf98e46f2f09..4e4eb89328540 100644 --- a/pandas/tests/series/test_api.py +++ b/pandas/tests/series/test_api.py @@ -191,3 +191,20 @@ def test_unknown_attribute(self): msg = "'Series' object has no attribute 'foo'" with pytest.raises(AttributeError, match=msg): ser.foo + + def test_datetime_series_no_datelike_attrs(self, datetime_series): + # GH#7206 + for op in ["year", "day", "second", "weekday"]: + msg = f"'Series' object has no attribute '{op}'" + with pytest.raises(AttributeError, match=msg): + getattr(datetime_series, op) + + def test_series_datetimelike_attribute_access(self): + # attribute access should still work! + ser = Series({"year": 2000, "month": 1, "day": 10}) + assert ser.year == 2000 + assert ser.month == 1 + assert ser.day == 10 + msg = "'Series' object has no attribute 'weekday'" + with pytest.raises(AttributeError, match=msg): + ser.weekday