Skip to content

WIP/TST/ENH: require freq match in assert_index_equal #31195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions pandas/_testing.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ def assert_index_equal(
check_less_precise: Union[bool, int] = False,
check_exact: bool = True,
check_categorical: bool = True,
check_freq: bool = True,
obj: str = "Index",
) -> None:
"""
Expand All @@ -612,6 +613,8 @@ def assert_index_equal(
Whether to compare number exactly.
check_categorical : bool, default True
Whether to compare internal Categorical exactly.
check_freq : bool, default True
Whether to check the freq attribute on DatetimeIndex/TimedeltaIndex.
obj : str, default 'Index'
Specify object name being compared, internally used to show appropriate
assertion message.
Expand Down Expand Up @@ -703,7 +706,11 @@ def _get_ilevel_values(index, level):
# metadata comparison
if check_names:
assert_attr_equal("names", left, right, obj=obj)
if isinstance(left, pd.PeriodIndex) or isinstance(right, pd.PeriodIndex):

freq_classes = (pd.PeriodIndex, pd.DatetimeIndex, pd.TimedeltaIndex)
if check_freq and (
isinstance(left, freq_classes) or isinstance(right, freq_classes)
):
assert_attr_equal("freq", left, right, obj=obj)
if isinstance(left, pd.IntervalIndex) or isinstance(right, pd.IntervalIndex):
assert_interval_array_equal(left.values, right.values)
Expand Down Expand Up @@ -742,8 +749,9 @@ def repr_class(x):
raise_assert_detail(obj, msg, repr_class(left), repr_class(right))


def assert_attr_equal(attr, left, right, obj="Attributes"):
"""checks attributes are equal. Both objects must have attribute.
def assert_attr_equal(attr: str, left, right, obj="Attributes"):
"""
Check attributes are equal. Both objects must have attribute.

Parameters
----------
Expand Down Expand Up @@ -876,8 +884,13 @@ def assert_interval_array_equal(left, right, exact="equiv", obj="IntervalArray")
"""
_check_isinstance(left, right, IntervalArray)

assert_index_equal(left.left, right.left, exact=exact, obj=f"{obj}.left")
assert_index_equal(left.right, right.right, exact=exact, obj=f"{obj}.left")
# TODO: re-enable check_freq?
assert_index_equal(
left.left, right.left, exact=exact, obj=f"{obj}.left", check_freq=False
)
assert_index_equal(
left.right, right.right, exact=exact, obj=f"{obj}.left", check_freq=False
)
assert_attr_equal("closed", left, right, obj=obj)


Expand Down Expand Up @@ -1070,6 +1083,7 @@ def assert_series_equal(
check_exact=False,
check_datetimelike_compat=False,
check_categorical=True,
check_freq: bool = True,
obj="Series",
):
"""
Expand Down Expand Up @@ -1104,6 +1118,8 @@ def assert_series_equal(
Compare datetime-like which is comparable ignoring dtype.
check_categorical : bool, default True
Whether to compare internal Categorical exactly.
check_freq : bool, default True
Whether to check the freq attribute on a DatetimeIndex/TimedeltaIndex
obj : str, default 'Series'
Specify object name being compared, internally used to show appropriate
assertion message.
Expand Down Expand Up @@ -1134,6 +1150,7 @@ def assert_series_equal(
check_less_precise=check_less_precise,
check_exact=check_exact,
check_categorical=check_categorical,
check_freq=check_freq,
obj=f"{obj}.index",
)

Expand Down
3 changes: 3 additions & 0 deletions pandas/core/arrays/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ def _generate_range(cls, start, end, periods, freq, closed=None):
index = _generate_regular_range(start, end, periods, freq)
else:
index = np.linspace(start.value, end.value, periods).astype("i8")
if len(index) >= 2:
td = Timedelta(index[1] - index[0])
freq = to_offset(td)

if not left_closed:
index = index[1:]
Expand Down
2 changes: 1 addition & 1 deletion pandas/core/indexes/datetimelike.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,7 @@ def _fast_union(self, other, sort=None):
loc = right.searchsorted(left_start, side="left")
right_chunk = right.values[:loc]
dates = concat_compat((left.values, right_chunk))
return self._shallow_copy(dates)
return self._shallow_copy(dates, freq=None)
else:
left, right = other, self

Expand Down
9 changes: 6 additions & 3 deletions pandas/core/tools/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from pandas.core.dtypes.common import is_list_like
from pandas.core.dtypes.generic import ABCIndexClass, ABCSeries

from pandas.core.arrays.timedeltas import sequence_to_td64ns
from pandas.core.arrays.timedeltas import TimedeltaArray, sequence_to_td64ns


def to_timedelta(arg, unit="ns", errors="raise"):
Expand Down Expand Up @@ -136,7 +136,9 @@ def _convert_listlike(arg, unit="ns", errors="raise", name=None):
arg = np.array(list(arg), dtype=object)

try:
value = sequence_to_td64ns(arg, unit=unit, errors=errors, copy=False)[0]
value, inferred_freq = sequence_to_td64ns(
arg, unit=unit, errors=errors, copy=False
)
except ValueError:
if errors == "ignore":
return arg
Expand All @@ -152,5 +154,6 @@ def _convert_listlike(arg, unit="ns", errors="raise", name=None):

from pandas import TimedeltaIndex

value = TimedeltaIndex(value, unit="ns", name=name)
tda = TimedeltaArray._simple_new(value, freq=inferred_freq)
value = TimedeltaIndex(tda, name=name)
return value
2 changes: 1 addition & 1 deletion pandas/tests/indexes/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -443,7 +443,7 @@ def test_where(self, klass):
cond = [False] + [True] * len(i[1:])
expected = pd.Index([i._na_value] + i[1:].tolist(), dtype=i.dtype)
result = i.where(klass(cond))
tm.assert_index_equal(result, expected)
tm.assert_index_equal(result, expected, check_freq=False)

@pytest.mark.parametrize("case", [0.5, "xxx"])
@pytest.mark.parametrize(
Expand Down
5 changes: 3 additions & 2 deletions pandas/tests/indexes/timedeltas/test_setops.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ def test_intersection(self, rng, expected, sort):
TimedeltaIndex(["2 hour", "5 hour", "5 hour", "1 hour"], name="other"),
TimedeltaIndex(["1 hour", "2 hour"], name=None),
),
# reveresed index
# reversed index
(
TimedeltaIndex(["1 hour", "2 hour", "4 hour", "3 hour"], name="idx")[
::-1
Expand All @@ -202,10 +202,11 @@ def test_intersection_non_monotonic(self, rng, expected, sort):
result = base.intersection(rng, sort=sort)
if sort is None:
expected = expected.sort_values()
expected._set_freq("infer")
tm.assert_index_equal(result, expected)
assert result.name == expected.name

# if reveresed order, frequency is still the same
# if reversed order, frequency is still the same
if all(base == rng[::-1]) and sort is None:
assert isinstance(result.freq, Hour)
else:
Expand Down
10 changes: 10 additions & 0 deletions pandas/tests/indexes/timedeltas/test_timedelta_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,32 @@ class TestTimedeltas:
def test_timedelta_range(self):

expected = to_timedelta(np.arange(5), unit="D")
expected._set_freq("infer")

result = timedelta_range("0 days", periods=5, freq="D")
tm.assert_index_equal(result, expected)

expected = to_timedelta(np.arange(11), unit="D")
expected._set_freq("infer")

result = timedelta_range("0 days", "10 days", freq="D")
tm.assert_index_equal(result, expected)

expected = to_timedelta(np.arange(5), unit="D") + Second(2) + Day()
expected._set_freq("infer")

result = timedelta_range("1 days, 00:00:02", "5 days, 00:00:02", freq="D")
tm.assert_index_equal(result, expected)

expected = to_timedelta([1, 3, 5, 7, 9], unit="D") + Second(2)
expected._set_freq("infer")

result = timedelta_range("1 days, 00:00:02", periods=5, freq="2D")
tm.assert_index_equal(result, expected)

expected = to_timedelta(np.arange(50), unit="T") * 30
expected._set_freq("infer")

result = timedelta_range("0 days", freq="30T", periods=50)
tm.assert_index_equal(result, expected)

Expand Down
9 changes: 7 additions & 2 deletions pandas/tests/indexing/test_datetime.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,11 @@ def test_indexing_with_datetimeindex_tz(self):

for sel in (index, list(index)):
# getitem
tm.assert_series_equal(ser[sel], ser)

# list(index) loses the freq
check_freq = True if sel is index else False

tm.assert_series_equal(ser[sel], ser, check_freq=check_freq)

# setitem
result = ser.copy()
Expand All @@ -154,7 +158,7 @@ def test_indexing_with_datetimeindex_tz(self):
tm.assert_series_equal(result, expected)

# .loc getitem
tm.assert_series_equal(ser.loc[sel], ser)
tm.assert_series_equal(ser.loc[sel], ser, check_freq=check_freq)

# .loc setitem
result = ser.copy()
Expand Down Expand Up @@ -222,6 +226,7 @@ def test_series_partial_set_datetime(self):
# GH 11497

idx = date_range("2011-01-01", "2011-01-02", freq="D", name="idx")
idx._set_freq(None)
ser = Series([0.1, 0.2], index=idx, name="s")

result = ser.loc[[Timestamp("2011-01-01"), Timestamp("2011-01-02")]]
Expand Down
7 changes: 4 additions & 3 deletions pandas/tests/series/methods/test_to_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ class TestSeriesToDict:
)
def test_to_dict(self, mapping, datetime_series):
# GH#16122
tm.assert_series_equal(
Series(datetime_series.to_dict(mapping), name="ts"), datetime_series
)
result = Series(datetime_series.to_dict(mapping), name="ts")
expected = datetime_series.copy()
expected.index._set_freq(None)
tm.assert_series_equal(result, expected)
from_method = Series(datetime_series.to_dict(collections.Counter))
from_constructor = Series(collections.Counter(datetime_series.items()))
tm.assert_series_equal(from_method, from_constructor)
4 changes: 2 additions & 2 deletions pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -3501,7 +3501,7 @@ def test_offset_whole_year(self):

# ensure generating a range with DatetimeIndex gives same result
result = date_range(start=dates[0], end=dates[-1], freq="SM")
exp = DatetimeIndex(dates)
exp = DatetimeIndex(dates, freq="SM")
tm.assert_index_equal(result, exp)

offset_cases = []
Expand Down Expand Up @@ -3760,7 +3760,7 @@ def test_offset_whole_year(self):

# ensure generating a range with DatetimeIndex gives same result
result = date_range(start=dates[0], end=dates[-1], freq="SMS")
exp = DatetimeIndex(dates)
exp = DatetimeIndex(dates, freq="SMS")
tm.assert_index_equal(result, exp)

offset_cases = []
Expand Down