Skip to content

Commit

Permalink
DEPR: remove deprecated units ‘H’, ’T’, and smaller from Timedelta, T…
Browse files Browse the repository at this point in the history
…imedeltaIndex (#57627)
  • Loading branch information
natmokval authored Mar 21, 2024
1 parent 8704cfa commit 41383cf
Show file tree
Hide file tree
Showing 11 changed files with 106 additions and 115 deletions.
2 changes: 1 addition & 1 deletion asv_bench/benchmarks/timeseries.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def setup(self):
self.dt_ts = Series(5, rng3, dtype="datetime64[ns]")

def time_resample(self):
self.dt_ts.resample("1S").last()
self.dt_ts.resample("1s").last()


class AsOf:
Expand Down
2 changes: 2 additions & 0 deletions doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ Removal of prior version deprecations/changes
- Enforced deprecation of string ``A`` denoting frequency in :class:`YearEnd` and strings ``A-DEC``, ``A-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`57699`)
- Enforced deprecation of string ``BAS`` denoting frequency in :class:`BYearBegin` and strings ``BAS-DEC``, ``BAS-JAN``, etc. denoting annual frequencies with various fiscal year starts (:issue:`57793`)
- Enforced deprecation of string ``BA`` denoting frequency in :class:`BYearEnd` and strings ``BA-DEC``, ``BA-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`57793`)
- Enforced deprecation of strings ``T``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Second`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`57627`)
- Enforced deprecation of strings ``T``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`57627`)
- Enforced deprecation of the behavior of :func:`concat` when ``len(keys) != len(objs)`` would truncate to the shorter of the two. Now this raises a ``ValueError`` (:issue:`43485`)
- Enforced silent-downcasting deprecation for :ref:`all relevant methods <whatsnew_220.silent_downcasting>` (:issue:`54710`)
- In :meth:`DataFrame.stack`, the default value of ``future_stack`` is now ``True``; specifying ``False`` will raise a ``FutureWarning`` (:issue:`55448`)
Expand Down
14 changes: 5 additions & 9 deletions pandas/_libs/tslibs/dtypes.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -313,15 +313,7 @@ cdef dict c_DEPR_ABBREVS = {
"H": "h",
"BH": "bh",
"CBH": "cbh",
"T": "min",
"t": "min",
"S": "s",
"L": "ms",
"l": "ms",
"U": "us",
"u": "us",
"N": "ns",
"n": "ns",
}


Expand Down Expand Up @@ -415,13 +407,17 @@ class Resolution(Enum):
"""
cdef:
str abbrev
if freq in {"T", "t", "L", "l", "U", "u", "N", "n"}:
raise ValueError(
f"Frequency \'{freq}\' is no longer supported."
)
try:
if freq in c_DEPR_ABBREVS:
abbrev = c_DEPR_ABBREVS[freq]
warnings.warn(
f"\'{freq}\' is deprecated and will be removed in a future "
f"version. Please use \'{abbrev}\' "
"instead of \'{freq}\'.",
f"instead of \'{freq}\'.",
FutureWarning,
stacklevel=find_stack_level(),
)
Expand Down
13 changes: 6 additions & 7 deletions pandas/core/tools/timedeltas.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,18 +112,17 @@ def to_timedelta(
* 'W'
* 'D' / 'days' / 'day'
* 'hours' / 'hour' / 'hr' / 'h' / 'H'
* 'm' / 'minute' / 'min' / 'minutes' / 'T'
* 'm' / 'minute' / 'min' / 'minutes'
* 's' / 'seconds' / 'sec' / 'second' / 'S'
* 'ms' / 'milliseconds' / 'millisecond' / 'milli' / 'millis' / 'L'
* 'us' / 'microseconds' / 'microsecond' / 'micro' / 'micros' / 'U'
* 'ns' / 'nanoseconds' / 'nano' / 'nanos' / 'nanosecond' / 'N'
* 'ms' / 'milliseconds' / 'millisecond' / 'milli' / 'millis'
* 'us' / 'microseconds' / 'microsecond' / 'micro' / 'micros'
* 'ns' / 'nanoseconds' / 'nano' / 'nanos' / 'nanosecond'
Must not be specified when `arg` contains strings and ``errors="raise"``.
.. deprecated:: 2.2.0
Units 'H', 'T', 'S', 'L', 'U' and 'N' are deprecated and will be removed
in a future version. Please use 'h', 'min', 's', 'ms', 'us', and 'ns'
instead of 'H', 'T', 'S', 'L', 'U' and 'N'.
Units 'H'and 'S' are deprecated and will be removed
in a future version. Please use 'h' and 's'.
errors : {'raise', 'coerce'}, default 'raise'
- If 'raise', then invalid parsing will raise an exception.
Expand Down
29 changes: 5 additions & 24 deletions pandas/tests/indexes/datetimes/test_date_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -772,30 +772,11 @@ def test_freq_dateoffset_with_relateivedelta_nanos(self):
)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize(
"freq,freq_depr",
[
("h", "H"),
("2min", "2T"),
("1s", "1S"),
("2ms", "2L"),
("1us", "1U"),
("2ns", "2N"),
],
)
def test_frequencies_H_T_S_L_U_N_deprecated(self, freq, freq_depr):
# GH#52536
freq_msg = re.split("[0-9]*", freq, maxsplit=1)[1]
freq_depr_msg = re.split("[0-9]*", freq_depr, maxsplit=1)[1]
msg = (
f"'{freq_depr_msg}' is deprecated and will be removed in a future version, "
)
f"please use '{freq_msg}' instead"

expected = date_range("1/1/2000", periods=2, freq=freq)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = date_range("1/1/2000", periods=2, freq=freq_depr)
tm.assert_index_equal(result, expected)
@pytest.mark.parametrize("freq", ["2T", "2L", "1l", "1U", "2N", "2n"])
def test_frequency_H_T_S_L_U_N_raises(self, freq):
msg = f"Invalid frequency: {freq}"
with pytest.raises(ValueError, match=msg):
date_range("1/1/2000", periods=2, freq=freq)

@pytest.mark.parametrize(
"freq,freq_depr",
Expand Down
10 changes: 10 additions & 0 deletions pandas/tests/indexes/period/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ def test_period_index_from_datetime_index_invalid_freq(self, freq):
with pytest.raises(ValueError, match=msg):
rng.to_period()

@pytest.mark.parametrize("freq_depr", ["2T", "1l", "2U", "n"])
def test_period_index_T_L_U_N_raises(self, freq_depr):
# GH#9586
msg = f"Invalid frequency: {freq_depr}"

with pytest.raises(ValueError, match=msg):
period_range("2020-01", "2020-05", freq=freq_depr)
with pytest.raises(ValueError, match=msg):
PeriodIndex(["2020-01", "2020-05"], freq=freq_depr)


class TestPeriodIndex:
def test_from_ordinals(self):
Expand Down
71 changes: 38 additions & 33 deletions pandas/tests/indexes/timedeltas/test_timedelta_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,32 +43,24 @@ def test_timedelta_range(self):
result = timedelta_range("0 days", freq="30min", periods=50)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize(
"depr_unit, unit",
[
("H", "hour"),
("T", "minute"),
("t", "minute"),
("S", "second"),
("L", "millisecond"),
("l", "millisecond"),
("U", "microsecond"),
("u", "microsecond"),
("N", "nanosecond"),
("n", "nanosecond"),
],
)
def test_timedelta_units_H_T_S_L_U_N_deprecated(self, depr_unit, unit):
@pytest.mark.parametrize("depr_unit, unit", [("H", "hour"), ("S", "second")])
def test_timedelta_units_H_S_deprecated(self, depr_unit, unit):
# GH#52536
depr_msg = (
f"'{depr_unit}' is deprecated and will be removed in a future version."
)

expected = to_timedelta(np.arange(5), unit=unit)
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
result = to_timedelta(np.arange(5), unit=depr_unit)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize("unit", ["T", "t", "L", "l", "U", "u", "N", "n"])
def test_timedelta_unit_T_L_U_N_raises(self, unit):
msg = f"invalid unit abbreviation: {unit}"

with pytest.raises(ValueError, match=msg):
to_timedelta(np.arange(5), unit=unit)

@pytest.mark.parametrize(
"periods, freq", [(3, "2D"), (5, "D"), (6, "19h12min"), (7, "16h"), (9, "12h")]
)
Expand All @@ -78,16 +70,21 @@ def test_linspace_behavior(self, periods, freq):
expected = timedelta_range(start="0 days", end="4 days", freq=freq)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize("msg_freq, freq", [("H", "19H12min"), ("T", "19h12T")])
def test_timedelta_range_H_T_deprecated(self, freq, msg_freq):
def test_timedelta_range_H_deprecated(self):
# GH#52536
msg = f"'{msg_freq}' is deprecated and will be removed in a future version."
msg = "'H' is deprecated and will be removed in a future version."

result = timedelta_range(start="0 days", end="4 days", periods=6)
with tm.assert_produces_warning(FutureWarning, match=msg):
expected = timedelta_range(start="0 days", end="4 days", freq=freq)
expected = timedelta_range(start="0 days", end="4 days", freq="19H12min")
tm.assert_index_equal(result, expected)

def test_timedelta_range_T_raises(self):
msg = "Invalid frequency: T"

with pytest.raises(ValueError, match=msg):
timedelta_range(start="0 days", end="4 days", freq="19h12T")

def test_errors(self):
# not enough params
msg = (
Expand Down Expand Up @@ -143,18 +140,6 @@ def test_timedelta_range_infer_freq(self):
["0 days 05:03:01", "0 days 05:03:04.500000", "0 days 05:03:08"],
"3500ms",
),
(
"2.5T",
"5 hours",
"5 hours 8 minutes",
[
"0 days 05:00:00",
"0 days 05:02:30",
"0 days 05:05:00",
"0 days 05:07:30",
],
"150s",
),
],
)
def test_timedelta_range_deprecated_freq(
Expand All @@ -171,3 +156,23 @@ def test_timedelta_range_deprecated_freq(
expected_values, dtype="timedelta64[ns]", freq=expected_freq
)
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize(
"freq_depr, start, end",
[
(
"3.5l",
"05:03:01",
"05:03:10",
),
(
"2.5T",
"5 hours",
"5 hours 8 minutes",
),
],
)
def test_timedelta_range_removed_freq(self, freq_depr, start, end):
msg = f"Invalid frequency: {freq_depr}"
with pytest.raises(ValueError, match=msg):
timedelta_range(start=start, end=end, freq=freq_depr)
20 changes: 9 additions & 11 deletions pandas/tests/resample/test_period_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -982,22 +982,20 @@ def test_sum_min_count(self):

def test_resample_t_l_deprecated(self):
# GH#52536
msg_t = "'T' is deprecated and will be removed in a future version."
msg_l = "'L' is deprecated and will be removed in a future version."
msg_t = "Invalid frequency: T"
msg_l = "Invalid frequency: L"

with tm.assert_produces_warning(FutureWarning, match=msg_l):
rng_l = period_range(
with pytest.raises(ValueError, match=msg_l):
period_range(
"2020-01-01 00:00:00 00:00", "2020-01-01 00:00:00 00:01", freq="L"
)
rng_l = period_range(
"2020-01-01 00:00:00 00:00", "2020-01-01 00:00:00 00:01", freq="ms"
)
ser = Series(np.arange(len(rng_l)), index=rng_l)

rng = period_range(
"2020-01-01 00:00:00 00:00", "2020-01-01 00:00:00 00:01", freq="min"
)
expected = Series([29999.5, 60000.0], index=rng)
with tm.assert_produces_warning(FutureWarning, match=msg_t):
result = ser.resample("T").mean()
tm.assert_series_equal(result, expected)
with pytest.raises(ValueError, match=msg_t):
ser.resample("T").mean()

@pytest.mark.parametrize(
"freq, freq_depr, freq_res, freq_depr_res, data",
Expand Down
4 changes: 2 additions & 2 deletions pandas/tests/scalar/period/test_asfreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ def test_conv_annual(self):
assert ival_A.asfreq("H", "E") == ival_A_to_H_end
assert ival_A.asfreq("min", "s") == ival_A_to_T_start
assert ival_A.asfreq("min", "E") == ival_A_to_T_end
msg = "'T' is deprecated and will be removed in a future version."
with tm.assert_produces_warning(FutureWarning, match=msg):
msg = "Invalid frequency: T"
with pytest.raises(ValueError, match=msg):
assert ival_A.asfreq("T", "s") == ival_A_to_T_start
assert ival_A.asfreq("T", "E") == ival_A_to_T_end
msg = "'S' is deprecated and will be removed in a future version."
Expand Down
45 changes: 19 additions & 26 deletions pandas/tests/scalar/timedelta/test_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,14 @@ def test_unit_m_y_raises(self, unit):
with pytest.raises(ValueError, match=msg):
to_timedelta([1, 2], unit)

@pytest.mark.parametrize(
"unit,unit_depr",
[
("h", "H"),
("min", "T"),
("s", "S"),
("ms", "L"),
("ns", "N"),
("us", "U"),
],
)
def test_units_H_T_S_L_N_U_deprecated(self, unit, unit_depr):
@pytest.mark.parametrize("unit", ["h", "s"])
def test_units_H_S_deprecated(self, unit):
# GH#52536
msg = f"'{unit_depr}' is deprecated and will be removed in a future version."
msg = f"'{unit.upper()}' is deprecated and will be removed in a future version."

expected = Timedelta(1, unit=unit)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = Timedelta(1, unit=unit_depr)
result = Timedelta(1, unit=unit.upper())
tm.assert_equal(result, expected)

@pytest.mark.parametrize(
Expand Down Expand Up @@ -103,13 +93,11 @@ def test_units_H_T_S_L_N_U_deprecated(self, unit, unit_depr):
"microsecond",
"micro",
"micros",
"u",
"US",
"Microseconds",
"Microsecond",
"Micro",
"Micros",
"U",
]
]
+ [
Expand All @@ -120,13 +108,11 @@ def test_units_H_T_S_L_N_U_deprecated(self, unit, unit_depr):
"nanosecond",
"nano",
"nanos",
"n",
"NS",
"Nanoseconds",
"Nanosecond",
"Nano",
"Nanos",
"N",
]
],
)
Expand All @@ -139,14 +125,9 @@ def test_unit_parser(self, unit, np_unit, wrapper):
dtype="m8[ns]",
)
# TODO(2.0): the desired output dtype may have non-nano resolution
msg = f"'{unit}' is deprecated and will be removed in a future version."

if (unit, np_unit) in (("u", "us"), ("U", "us"), ("n", "ns"), ("N", "ns")):
warn = FutureWarning
else:
warn = FutureWarning
msg = "The 'unit' keyword in TimedeltaIndex construction is deprecated"
with tm.assert_produces_warning(warn, match=msg):

msg = "The 'unit' keyword in TimedeltaIndex construction is deprecated"
with tm.assert_produces_warning(FutureWarning, match=msg):
result = to_timedelta(wrapper(range(5)), unit=unit)
tm.assert_index_equal(result, expected)
result = TimedeltaIndex(wrapper(range(5)), unit=unit)
Expand All @@ -170,6 +151,18 @@ def test_unit_parser(self, unit, np_unit, wrapper):
result = Timedelta(f"2{unit}")
assert result == expected

@pytest.mark.parametrize("unit", ["T", "t", "L", "l", "U", "u", "N", "n"])
def test_unit_T_L_N_U_raises(self, unit):
msg = f"invalid unit abbreviation: {unit}"
with pytest.raises(ValueError, match=msg):
Timedelta(1, unit=unit)

with pytest.raises(ValueError, match=msg):
to_timedelta(10, unit)

with pytest.raises(ValueError, match=msg):
to_timedelta([1, 2], unit)


def test_construct_from_kwargs_overflow():
# GH#55503
Expand Down
11 changes: 9 additions & 2 deletions pandas/tests/tslibs/test_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,17 @@ def test_get_attrname_from_abbrev(freqstr, expected):
assert reso.attrname == expected


@pytest.mark.parametrize("freq", ["H", "T", "S", "L", "U", "N"])
def test_units_H_T_S_L_U_N_deprecated_from_attrname_to_abbrevs(freq):
@pytest.mark.parametrize("freq", ["H", "S"])
def test_units_H_S_deprecated_from_attrname_to_abbrevs(freq):
# GH#52536
msg = f"'{freq}' is deprecated and will be removed in a future version."

with tm.assert_produces_warning(FutureWarning, match=msg):
Resolution.get_reso_from_freqstr(freq)


@pytest.mark.parametrize("freq", ["T", "t", "L", "U", "N", "n"])
def test_reso_abbrev_T_L_U_N_raises(freq):
msg = f"Frequency '{freq}' is no longer supported."
with pytest.raises(ValueError, match=msg):
Resolution.get_reso_from_freqstr(freq)

0 comments on commit 41383cf

Please sign in to comment.