Skip to content

Commit d966462

Browse files
authored
CLN: enforced the deprecation of strings 'H', 'BH', 'CBH' in favor of 'h', 'bh', 'cbh' (#59143)
* CLN: enforced the deprecation of strings ‘H’, ‘BH’, ‘CBH’ in favour of ‘h’, ‘bh’, ‘cbh’ * fix tests * add a note to v3.0.0 * fixup * add def INVALID_FREQ_ERR_MSG to dtypes.pxd * Revert "add def INVALID_FREQ_ERR_MSG to dtypes.pxd" This reverts commit 4085d5c. * remove dict c_REMOVED_ABBREVS, add msg if raise KeyError in get_reso_from_freqstr
1 parent 3a34e07 commit d966462

File tree

11 files changed

+50
-130
lines changed

11 files changed

+50
-130
lines changed

doc/source/whatsnew/v3.0.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ Other Removals
383383
- 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`)
384384
- 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`)
385385
- 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`)
386+
- Enforced deprecation of strings ``H``, ``BH``, and ``CBH`` denoting frequencies in :class:`Hour`, :class:`BusinessHour`, :class:`CustomBusinessHour` (:issue:`59143`)
387+
- Enforced deprecation of strings ``H``, ``BH``, and ``CBH`` denoting units in :class:`Timedelta` (:issue:`59143`)
386388
- Enforced deprecation of strings ``T``, ``L``, ``U``, and ``N`` denoting frequencies in :class:`Minute`, :class:`Milli`, :class:`Micro`, :class:`Nano` (:issue:`57627`)
387389
- Enforced deprecation of strings ``T``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`57627`)
388390
- 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`)

pandas/_libs/tslibs/dtypes.pxd

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ cdef bint is_supported_unit(NPY_DATETIMEUNIT reso)
1414
cdef dict c_OFFSET_TO_PERIOD_FREQSTR
1515
cdef dict c_PERIOD_TO_OFFSET_FREQSTR
1616
cdef dict c_OFFSET_RENAMED_FREQSTR
17-
cdef dict c_DEPR_ABBREVS
1817
cdef dict c_DEPR_UNITS
1918
cdef dict c_PERIOD_AND_OFFSET_DEPR_FREQSTR
2019
cdef dict attrname_to_abbrevs
2120
cdef dict npy_unit_to_attrname
2221
cdef dict attrname_to_npy_unit
22+
cdef str INVALID_FREQ_ERR_MSG
2323

2424
cdef enum c_FreqGroup:
2525
# Mirrors FreqGroup in the .pyx file

pandas/_libs/tslibs/dtypes.pyx

+6-36
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
# period frequency constants corresponding to scikits timeseries
22
# originals
33
from enum import Enum
4-
import warnings
5-
6-
from pandas.util._exceptions import find_stack_level
74

85
from pandas._libs.tslibs.ccalendar cimport c_MONTH_NUMBERS
96
from pandas._libs.tslibs.np_datetime cimport (
@@ -338,14 +335,6 @@ PERIOD_TO_OFFSET_FREQSTR = {
338335
cdef dict c_OFFSET_TO_PERIOD_FREQSTR = OFFSET_TO_PERIOD_FREQSTR
339336
cdef dict c_PERIOD_TO_OFFSET_FREQSTR = PERIOD_TO_OFFSET_FREQSTR
340337

341-
# Map deprecated resolution abbreviations to correct resolution abbreviations
342-
cdef dict c_DEPR_ABBREVS = {
343-
"H": "h",
344-
"BH": "bh",
345-
"CBH": "cbh",
346-
"S": "s",
347-
}
348-
349338
cdef dict c_DEPR_UNITS = {
350339
"w": "W",
351340
"d": "D",
@@ -372,6 +361,8 @@ cdef dict c_PERIOD_AND_OFFSET_DEPR_FREQSTR = {
372361
"MIN": "min",
373362
}
374363

364+
cdef str INVALID_FREQ_ERR_MSG = "Invalid frequency: {0}"
365+
375366

376367
class FreqGroup(Enum):
377368
# Mirrors c_FreqGroup in the .pxd file
@@ -461,39 +452,18 @@ class Resolution(Enum):
461452
>>> Resolution.get_reso_from_freqstr('h') == Resolution.RESO_HR
462453
True
463454
"""
464-
cdef:
465-
str abbrev
466455
try:
467-
if freq in c_DEPR_ABBREVS:
468-
abbrev = c_DEPR_ABBREVS[freq]
469-
warnings.warn(
470-
f"\'{freq}\' is deprecated and will be removed in a future "
471-
f"version. Please use \'{abbrev}\' "
472-
f"instead of \'{freq}\'.",
473-
FutureWarning,
474-
stacklevel=find_stack_level(),
475-
)
476-
freq = abbrev
477456
attr_name = _abbrev_to_attrnames[freq]
478-
except KeyError:
457+
except KeyError as exc:
458+
msg = INVALID_FREQ_ERR_MSG.format(freq)
479459
# For quarterly and yearly resolutions, we need to chop off
480460
# a month string.
481461
split_freq = freq.split("-")
482462
if len(split_freq) != 2:
483-
raise
463+
raise ValueError(msg) from exc
484464
if split_freq[1] not in _month_names:
485465
# i.e. we want e.g. "Q-DEC", not "Q-INVALID"
486-
raise
487-
if split_freq[0] in c_DEPR_ABBREVS:
488-
abbrev = c_DEPR_ABBREVS[split_freq[0]]
489-
warnings.warn(
490-
f"\'{split_freq[0]}\' is deprecated and will be removed in a "
491-
f"future version. Please use \'{abbrev}\' "
492-
f"instead of \'{split_freq[0]}\'.",
493-
FutureWarning,
494-
stacklevel=find_stack_level(),
495-
)
496-
split_freq[0] = abbrev
466+
raise ValueError(msg) from exc
497467
attr_name = _abbrev_to_attrnames[split_freq[0]]
498468

499469
return cls.from_attrname(attr_name)

pandas/_libs/tslibs/offsets.pyx

-11
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@ from pandas._libs.tslibs.ccalendar cimport (
5656
)
5757
from pandas._libs.tslibs.conversion cimport localize_pydatetime
5858
from pandas._libs.tslibs.dtypes cimport (
59-
c_DEPR_ABBREVS,
6059
c_OFFSET_RENAMED_FREQSTR,
6160
c_OFFSET_TO_PERIOD_FREQSTR,
6261
c_PERIOD_AND_OFFSET_DEPR_FREQSTR,
@@ -4908,16 +4907,6 @@ cpdef to_offset(freq, bint is_period=False):
49084907
if not stride:
49094908
stride = 1
49104909

4911-
if prefix in c_DEPR_ABBREVS:
4912-
warnings.warn(
4913-
f"\'{prefix}\' is deprecated and will be removed "
4914-
f"in a future version, please use "
4915-
f"\'{c_DEPR_ABBREVS.get(prefix)}\' instead.",
4916-
FutureWarning,
4917-
stacklevel=find_stack_level(),
4918-
)
4919-
prefix = c_DEPR_ABBREVS[prefix]
4920-
49214910
if prefix in {"D", "h", "min", "s", "ms", "us", "ns"}:
49224911
# For these prefixes, we have something like "3h" or
49234912
# "2.5min", so we can construct a Timedelta with the

pandas/tests/arrays/test_datetimes.py

+8-1
Original file line numberDiff line numberDiff line change
@@ -760,7 +760,7 @@ def test_date_range_frequency_M_Q_Y_raises(self, freq):
760760
with pytest.raises(ValueError, match=msg):
761761
pd.date_range("1/1/2000", periods=4, freq=freq)
762762

763-
@pytest.mark.parametrize("freq_depr", ["2H", "2CBH", "2MIN", "2S", "2mS", "2Us"])
763+
@pytest.mark.parametrize("freq_depr", ["2MIN", "2mS", "2Us"])
764764
def test_date_range_uppercase_frequency_deprecated(self, freq_depr):
765765
# GH#9586, GH#54939
766766
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
@@ -807,6 +807,13 @@ def test_date_range_frequency_A_raises(self, freq):
807807
with pytest.raises(ValueError, match=msg):
808808
pd.date_range("1/1/2000", periods=4, freq=freq)
809809

810+
@pytest.mark.parametrize("freq", ["2H", "2CBH", "2S"])
811+
def test_date_range_uppercase_frequency_raises(self, freq):
812+
msg = f"Invalid frequency: {freq}"
813+
814+
with pytest.raises(ValueError, match=msg):
815+
pd.date_range("1/1/2000", periods=4, freq=freq)
816+
810817

811818
def test_factorize_sort_without_freq():
812819
dta = DatetimeArray._from_sequence([0, 2, 1], dtype="M8[ns]")

pandas/tests/indexes/datetimes/test_datetime.py

+5-22
Original file line numberDiff line numberDiff line change
@@ -133,29 +133,12 @@ def test_asarray_tz_aware(self):
133133

134134
tm.assert_numpy_array_equal(result, expected)
135135

136-
def test_CBH_deprecated(self):
137-
msg = "'CBH' is deprecated and will be removed in a future version."
138-
139-
with tm.assert_produces_warning(FutureWarning, match=msg):
140-
expected = date_range(
141-
dt.datetime(2022, 12, 11), dt.datetime(2022, 12, 13), freq="CBH"
142-
)
143-
result = DatetimeIndex(
144-
[
145-
"2022-12-12 09:00:00",
146-
"2022-12-12 10:00:00",
147-
"2022-12-12 11:00:00",
148-
"2022-12-12 12:00:00",
149-
"2022-12-12 13:00:00",
150-
"2022-12-12 14:00:00",
151-
"2022-12-12 15:00:00",
152-
"2022-12-12 16:00:00",
153-
],
154-
dtype="datetime64[ns]",
155-
freq="cbh",
156-
)
136+
@pytest.mark.parametrize("freq", ["2H", "2BH", "2S"])
137+
def test_CBH_raises(self, freq):
138+
msg = f"Invalid frequency: {freq}"
157139

158-
tm.assert_index_equal(result, expected)
140+
with pytest.raises(ValueError, match=msg):
141+
date_range(dt.datetime(2022, 12, 11), dt.datetime(2022, 12, 13), freq=freq)
159142

160143
@pytest.mark.parametrize("freq", ["2BM", "1bm", "2BQ", "1BQ-MAR", "2BY-JUN", "1by"])
161144
def test_BM_BQ_BY_raises(self, freq):

pandas/tests/indexes/period/test_period_range.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def test_constructor_U(self):
203203
with pytest.raises(ValueError, match="Invalid frequency: X"):
204204
period_range("2007-1-1", periods=500, freq="X")
205205

206-
@pytest.mark.parametrize("freq_depr", ["2H", "2MIN", "2S", "2US", "2NS"])
206+
@pytest.mark.parametrize("freq_depr", ["2MIN", "2US", "2NS"])
207207
def test_uppercase_freq_deprecated_from_time_series(self, freq_depr):
208208
# GH#52536, GH#54939
209209
msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
@@ -212,9 +212,9 @@ def test_uppercase_freq_deprecated_from_time_series(self, freq_depr):
212212
with tm.assert_produces_warning(FutureWarning, match=msg):
213213
period_range("2020-01-01 00:00:00 00:00", periods=2, freq=freq_depr)
214214

215-
@pytest.mark.parametrize("freq", ["2m", "2q-sep", "2y"])
216-
def test_lowercase_freq_from_time_series_raises(self, freq):
217-
# GH#52536, GH#54939
215+
@pytest.mark.parametrize("freq", ["2m", "2q-sep", "2y", "2H", "2S"])
216+
def test_incorrect_case_freq_from_time_series_raises(self, freq):
217+
# GH#52536, GH#54939, GH#59143
218218
msg = f"Invalid frequency: {freq}"
219219

220220
with pytest.raises(ValueError, match=msg):

pandas/tests/indexes/timedeltas/test_timedelta_range.py

+10-34
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
from pandas import (
55
Timedelta,
6-
TimedeltaIndex,
76
timedelta_range,
87
to_timedelta,
98
)
@@ -70,14 +69,12 @@ def test_linspace_behavior(self, periods, freq):
7069
expected = timedelta_range(start="0 days", end="4 days", freq=freq)
7170
tm.assert_index_equal(result, expected)
7271

73-
def test_timedelta_range_H_deprecated(self):
72+
def test_timedelta_range_H_raises(self):
7473
# GH#52536
75-
msg = "'H' is deprecated and will be removed in a future version."
74+
msg = "Invalid frequency: H"
7675

77-
result = timedelta_range(start="0 days", end="4 days", periods=6)
78-
with tm.assert_produces_warning(FutureWarning, match=msg):
79-
expected = timedelta_range(start="0 days", end="4 days", freq="19H12min")
80-
tm.assert_index_equal(result, expected)
76+
with pytest.raises(ValueError, match=msg):
77+
timedelta_range(start="0 days", end="4 days", freq="19H12min")
8178

8279
def test_timedelta_range_T_raises(self):
8380
msg = "Invalid frequency: T"
@@ -130,33 +127,6 @@ def test_timedelta_range_infer_freq(self):
130127
result = timedelta_range("0s", "1s", periods=31)
131128
assert result.freq is None
132129

133-
@pytest.mark.parametrize(
134-
"freq_depr, start, end, expected_values, expected_freq",
135-
[
136-
(
137-
"3.5S",
138-
"05:03:01",
139-
"05:03:10",
140-
["0 days 05:03:01", "0 days 05:03:04.500000", "0 days 05:03:08"],
141-
"3500ms",
142-
),
143-
],
144-
)
145-
def test_timedelta_range_deprecated_freq(
146-
self, freq_depr, start, end, expected_values, expected_freq
147-
):
148-
# GH#52536
149-
msg = (
150-
f"'{freq_depr[-1]}' is deprecated and will be removed in a future version."
151-
)
152-
153-
with tm.assert_produces_warning(FutureWarning, match=msg):
154-
result = timedelta_range(start=start, end=end, freq=freq_depr)
155-
expected = TimedeltaIndex(
156-
expected_values, dtype="timedelta64[ns]", freq=expected_freq
157-
)
158-
tm.assert_index_equal(result, expected)
159-
160130
@pytest.mark.parametrize(
161131
"freq_depr, start, end",
162132
[
@@ -170,9 +140,15 @@ def test_timedelta_range_deprecated_freq(
170140
"5 hours",
171141
"5 hours 8 minutes",
172142
),
143+
(
144+
"3.5S",
145+
"05:03:01",
146+
"05:03:10",
147+
),
173148
],
174149
)
175150
def test_timedelta_range_removed_freq(self, freq_depr, start, end):
151+
# GH#59143
176152
msg = f"Invalid frequency: {freq_depr}"
177153
with pytest.raises(ValueError, match=msg):
178154
timedelta_range(start=start, end=end, freq=freq_depr)

pandas/tests/scalar/period/test_asfreq.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -111,17 +111,14 @@ def test_conv_annual(self):
111111
assert ival_A.asfreq("B", "E") == ival_A_to_B_end
112112
assert ival_A.asfreq("D", "s") == ival_A_to_D_start
113113
assert ival_A.asfreq("D", "E") == ival_A_to_D_end
114-
msg_depr = "'H' is deprecated and will be removed in a future version."
115-
with tm.assert_produces_warning(FutureWarning, match=msg_depr):
114+
with pytest.raises(ValueError, match=msg):
116115
assert ival_A.asfreq("H", "s") == ival_A_to_H_start
117116
assert ival_A.asfreq("H", "E") == ival_A_to_H_end
118117
assert ival_A.asfreq("min", "s") == ival_A_to_T_start
119118
assert ival_A.asfreq("min", "E") == ival_A_to_T_end
120119
with pytest.raises(ValueError, match=msg):
121120
assert ival_A.asfreq("T", "s") == ival_A_to_T_start
122121
assert ival_A.asfreq("T", "E") == ival_A_to_T_end
123-
msg_depr = "'S' is deprecated and will be removed in a future version."
124-
with tm.assert_produces_warning(FutureWarning, match=msg_depr):
125122
assert ival_A.asfreq("S", "S") == ival_A_to_S_start
126123
assert ival_A.asfreq("S", "E") == ival_A_to_S_end
127124

pandas/tests/tslibs/test_resolution.py

+4-6
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
)
1010
from pandas._libs.tslibs.dtypes import NpyDatetimeUnit
1111

12-
import pandas._testing as tm
13-
1412

1513
def test_get_resolution_nano():
1614
# don't return the fallback RESO_DAY
@@ -50,9 +48,9 @@ def test_get_attrname_from_abbrev(freqstr, expected):
5048

5149

5250
@pytest.mark.parametrize("freq", ["H", "S"])
53-
def test_units_H_S_deprecated_from_attrname_to_abbrevs(freq):
54-
# GH#52536
55-
msg = f"'{freq}' is deprecated and will be removed in a future version."
51+
def test_unit_H_S_raises(freq):
52+
# GH#59143
53+
msg = f"Invalid frequency: {freq}"
5654

57-
with tm.assert_produces_warning(FutureWarning, match=msg):
55+
with pytest.raises(ValueError, match=msg):
5856
Resolution.get_reso_from_freqstr(freq)

pandas/tests/tslibs/test_to_offset.py

+9-11
Original file line numberDiff line numberDiff line change
@@ -203,17 +203,7 @@ def test_to_offset_lowercase_frequency_raises(freq_depr):
203203
to_offset(freq_depr)
204204

205205

206-
@pytest.mark.parametrize(
207-
"freq_depr",
208-
[
209-
"2H",
210-
"2BH",
211-
"2MIN",
212-
"2S",
213-
"2Us",
214-
"2NS",
215-
],
216-
)
206+
@pytest.mark.parametrize("freq_depr", ["2MIN", "2Us", "2NS"])
217207
def test_to_offset_uppercase_frequency_deprecated(freq_depr):
218208
# GH#54939
219209
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
@@ -238,3 +228,11 @@ def test_to_offset_lowercase_frequency_deprecated(freq_depr, expected):
238228
with tm.assert_produces_warning(FutureWarning, match=msg):
239229
result = to_offset(freq_depr)
240230
assert result == expected
231+
232+
233+
@pytest.mark.parametrize("freq", ["2H", "2BH", "2S"])
234+
def test_to_offset_uppercase_frequency_raises(freq):
235+
msg = f"Invalid frequency: {freq}"
236+
237+
with pytest.raises(ValueError, match=msg):
238+
to_offset(freq)

0 commit comments

Comments
 (0)