Skip to content

Commit 1d56672

Browse files
authored
DEPR: rename BQ to BQE for offsets (#55978)
1 parent 41bb434 commit 1d56672

File tree

17 files changed

+87
-42
lines changed

17 files changed

+87
-42
lines changed

doc/source/user_guide/timeseries.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -886,7 +886,7 @@ into ``freq`` keyword arguments. The available date offsets and associated frequ
886886
:class:`~pandas.tseries.offsets.SemiMonthBegin`, ``'SMS'``, "15th (or other day_of_month) and calendar month begin"
887887
:class:`~pandas.tseries.offsets.QuarterEnd`, ``'QE'``, "calendar quarter end"
888888
:class:`~pandas.tseries.offsets.QuarterBegin`, ``'QS'``, "calendar quarter begin"
889-
:class:`~pandas.tseries.offsets.BQuarterEnd`, ``'BQ``, "business quarter end"
889+
:class:`~pandas.tseries.offsets.BQuarterEnd`, ``'BQE``, "business quarter end"
890890
:class:`~pandas.tseries.offsets.BQuarterBegin`, ``'BQS'``, "business quarter begin"
891891
:class:`~pandas.tseries.offsets.FY5253Quarter`, ``'REQ'``, "retail (aka 52-53 week) quarter"
892892
:class:`~pandas.tseries.offsets.YearEnd`, ``'YE'``, "calendar year end"
@@ -1249,7 +1249,7 @@ frequencies. We will refer to these aliases as *offset aliases*.
12491249
"BMS", "business month start frequency"
12501250
"CBMS", "custom business month start frequency"
12511251
"QE", "quarter end frequency"
1252-
"BQ", "business quarter end frequency"
1252+
"BQE", "business quarter end frequency"
12531253
"QS", "quarter start frequency"
12541254
"BQS", "business quarter start frequency"
12551255
"YE", "year end frequency"
@@ -1686,7 +1686,7 @@ the end of the interval.
16861686
.. warning::
16871687

16881688
The default values for ``label`` and ``closed`` is '**left**' for all
1689-
frequency offsets except for 'ME', 'YE', 'QE', 'BME', 'BY', 'BQ', and 'W'
1689+
frequency offsets except for 'ME', 'YE', 'QE', 'BME', 'BY', 'BQE', and 'W'
16901690
which all have a default of 'right'.
16911691

16921692
This might unintendedly lead to looking ahead, where the value for a later

doc/source/whatsnew/v2.2.0.rst

+1
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ Other Deprecations
289289
- Deprecated string ``A`` denoting frequency in :class:`YearEnd` and strings ``A-DEC``, ``A-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`54275`)
290290
- Deprecated string ``BAS`` denoting frequency in :class:`BYearBegin` and strings ``BAS-DEC``, ``BAS-JAN``, etc. denoting annual frequencies with various fiscal year starts (:issue:`54275`)
291291
- Deprecated string ``BA`` denoting frequency in :class:`BYearEnd` and strings ``BA-DEC``, ``BA-JAN``, etc. denoting annual frequencies with various fiscal year ends (:issue:`54275`)
292+
- Deprecated string ``BQ`` denoting frequency in :class:`BQuarterEnd` (:issue:`52064`)
292293
- Deprecated strings ``BM``, and ``CBM`` denoting frequencies in :class:`BusinessMonthEnd`, :class:`CustomBusinessMonthEnd` (:issue:`52064`)
293294
- Deprecated strings ``H``, ``BH``, and ``CBH`` denoting frequencies in :class:`Hour`, :class:`BusinessHour`, :class:`CustomBusinessHour` (:issue:`52536`)
294295
- Deprecated strings ``H``, ``S``, ``U``, and ``N`` denoting units in :func:`to_timedelta` (:issue:`52536`)

pandas/_libs/tslibs/dtypes.pyx

+28-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,19 @@ OFFSET_TO_PERIOD_FREQSTR: dict = {
177177
"BME": "M",
178178
"BQS": "Q",
179179
"QS": "Q",
180-
"BQ": "Q",
180+
"BQE": "Q",
181+
"BQE-DEC": "Q-DEC",
182+
"BQE-JAN": "Q-JAN",
183+
"BQE-FEB": "Q-FEB",
184+
"BQE-MAR": "Q-MAR",
185+
"BQE-APR": "Q-APR",
186+
"BQE-MAY": "Q-MAY",
187+
"BQE-JUN": "Q-JUN",
188+
"BQE-JUL": "Q-JUL",
189+
"BQE-AUG": "Q-AUG",
190+
"BQE-SEP": "Q-SEP",
191+
"BQE-OCT": "Q-OCT",
192+
"BQE-NOV": "Q-NOV",
181193
"MS": "M",
182194
"D": "D",
183195
"B": "B",
@@ -261,6 +273,21 @@ cdef dict c_OFFSET_DEPR_FREQSTR = {
261273
"A-SEP": "YE-SEP",
262274
"A-OCT": "YE-OCT",
263275
"A-NOV": "YE-NOV",
276+
"BM": "BME",
277+
"CBM": "CBME",
278+
"BQ": "BQE",
279+
"BQ-DEC": "BQE-DEC",
280+
"BQ-JAN": "BQE-JAN",
281+
"BQ-FEB": "BQE-FEB",
282+
"BQ-MAR": "BQE-MAR",
283+
"BQ-APR": "BQE-APR",
284+
"BQ-MAY": "BQE-MAY",
285+
"BQ-JUN": "BQE-JUN",
286+
"BQ-JUL": "BQE-JUL",
287+
"BQ-AUG": "BQE-AUG",
288+
"BQ-SEP": "BQE-SEP",
289+
"BQ-OCT": "BQE-OCT",
290+
"BQ-NOV": "BQE-NOV",
264291
}
265292
cdef dict c_OFFSET_TO_PERIOD_FREQSTR = OFFSET_TO_PERIOD_FREQSTR
266293
cdef dict c_REVERSE_OFFSET_DEPR_FREQSTR = {

pandas/_libs/tslibs/offsets.pyx

+3-3
Original file line numberDiff line numberDiff line change
@@ -2670,7 +2670,7 @@ cdef class BQuarterEnd(QuarterOffset):
26702670
_output_name = "BusinessQuarterEnd"
26712671
_default_starting_month = 3
26722672
_from_name_starting_month = 12
2673-
_prefix = "BQ"
2673+
_prefix = "BQE"
26742674
_day_opt = "business_end"
26752675

26762676

@@ -4545,7 +4545,7 @@ prefix_mapping = {
45454545
BusinessDay, # 'B'
45464546
BusinessMonthBegin, # 'BMS'
45474547
BusinessMonthEnd, # 'BME'
4548-
BQuarterEnd, # 'BQ'
4548+
BQuarterEnd, # 'BQE'
45494549
BQuarterBegin, # 'BQS'
45504550
BusinessHour, # 'bh'
45514551
CustomBusinessDay, # 'C'
@@ -4729,7 +4729,7 @@ cpdef to_offset(freq, bint is_period=False):
47294729
for n, (sep, stride, name) in enumerate(tups):
47304730
if is_period is False and name in c_OFFSET_DEPR_FREQSTR:
47314731
warnings.warn(
4732-
f"\'{name}\' will be deprecated, please use "
4732+
f"\'{name}\' is deprecated, please use "
47334733
f"\'{c_OFFSET_DEPR_FREQSTR.get(name)}\' instead.",
47344734
FutureWarning,
47354735
stacklevel=find_stack_level(),

pandas/core/generic.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -9200,11 +9200,11 @@ def resample(
92009200
closed : {{'right', 'left'}}, default None
92019201
Which side of bin interval is closed. The default is 'left'
92029202
for all frequency offsets except for 'ME', 'YE', 'QE', 'BME',
9203-
'BA', 'BQ', and 'W' which all have a default of 'right'.
9203+
'BA', 'BQE', and 'W' which all have a default of 'right'.
92049204
label : {{'right', 'left'}}, default None
92059205
Which bin edge label to label bucket with. The default is 'left'
92069206
for all frequency offsets except for 'ME', 'YE', 'QE', 'BME',
9207-
'BA', 'BQ', and 'W' which all have a default of 'right'.
9207+
'BA', 'BQE', and 'W' which all have a default of 'right'.
92089208
convention : {{'start', 'end', 's', 'e'}}, default 'start'
92099209
For `PeriodIndex` only, controls whether to use the start or
92109210
end of `rule`.

pandas/core/resample.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -2130,7 +2130,7 @@ def __init__(
21302130
else:
21312131
freq = to_offset(freq)
21322132

2133-
end_types = {"ME", "YE", "QE", "BME", "BY", "BQ", "W"}
2133+
end_types = {"ME", "YE", "QE", "BME", "BY", "BQE", "W"}
21342134
rule = freq.rule_code
21352135
if rule in end_types or ("-" in rule and rule[: rule.find("-")] in end_types):
21362136
if closed is None:
@@ -2327,7 +2327,7 @@ def _adjust_bin_edges(
23272327
# Some hacks for > daily data, see #1471, #1458, #1483
23282328

23292329
if self.freq.name in ("BME", "ME", "W") or self.freq.name.split("-")[0] in (
2330-
"BQ",
2330+
"BQE",
23312331
"BY",
23322332
"QE",
23332333
"YE",

pandas/tests/arrays/test_datetimes.py

+1-3
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,7 @@ def test_iter_zoneinfo_fold(self, tz):
772772
)
773773
def test_date_range_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
774774
# GH#9586, GH#54275
775-
depr_msg = (
776-
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
777-
)
775+
depr_msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
778776

779777
expected = pd.date_range("1/1/2000", periods=4, freq=freq)
780778
with tm.assert_produces_warning(FutureWarning, match=depr_msg):

pandas/tests/frame/methods/test_asfreq.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -240,17 +240,17 @@ def test_asfreq_2ME(self, freq, freq_half):
240240
("2ME", "2M"),
241241
("2QE", "2Q"),
242242
("2QE-SEP", "2Q-SEP"),
243+
("1BQE", "1BQ"),
244+
("2BQE-SEP", "2BQ-SEP"),
243245
("1YE", "1Y"),
244246
("2YE-MAR", "2Y-MAR"),
245247
("1YE", "1A"),
246248
("2YE-MAR", "2A-MAR"),
247249
],
248250
)
249251
def test_asfreq_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
250-
# GH#9586
251-
depr_msg = (
252-
f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
253-
)
252+
# GH#9586, #55978
253+
depr_msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
254254

255255
index = date_range("1/1/2000", periods=4, freq=f"{freq[1:]}")
256256
df = DataFrame({"s": Series([0.0, 1.0, 2.0, 3.0], index=index)})

pandas/tests/indexes/datetimes/methods/test_to_period.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def test_to_period_quarterly(self, month):
5050
result = stamps.to_period(freq)
5151
tm.assert_index_equal(rng, result)
5252

53-
@pytest.mark.parametrize("off", ["BQ", "QS", "BQS"])
53+
@pytest.mark.parametrize("off", ["BQE", "QS", "BQS"])
5454
def test_to_period_quarterlyish(self, off):
5555
rng = date_range("01-Jan-2012", periods=8, freq=off)
5656
prng = rng.to_period()
@@ -103,7 +103,7 @@ def test_dti_to_period_2monthish(self, freq_offset, freq_period):
103103
)
104104
def test_to_period_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
105105
# GH#9586
106-
msg = f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
106+
msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
107107

108108
rng = date_range("01-Jan-2012", periods=8, freq=freq)
109109
prng = rng.to_period()

pandas/tests/indexes/datetimes/test_date_range.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def test_date_range_float_periods(self):
146146
tm.assert_index_equal(rng, exp)
147147

148148
def test_date_range_frequency_M_deprecated(self):
149-
depr_msg = "'M' will be deprecated, please use 'ME' instead."
149+
depr_msg = "'M' is deprecated, please use 'ME' instead."
150150

151151
expected = date_range("1/1/2000", periods=4, freq="2ME")
152152
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
@@ -797,7 +797,7 @@ def test_frequencies_A_deprecated_Y_renamed(self, freq, freq_depr):
797797
# GH#9586, GH#54275
798798
freq_msg = re.split("[0-9]*", freq, maxsplit=1)[1]
799799
freq_depr_msg = re.split("[0-9]*", freq_depr, maxsplit=1)[1]
800-
msg = f"'{freq_depr_msg}' will be deprecated, please use '{freq_msg}' instead."
800+
msg = f"'{freq_depr_msg}' is deprecated, please use '{freq_msg}' instead."
801801

802802
expected = date_range("1/1/2000", periods=2, freq=freq)
803803
with tm.assert_produces_warning(FutureWarning, match=msg):
@@ -1678,7 +1678,7 @@ def test_date_range_fy5253(self, unit):
16781678
"freqstr,offset",
16791679
[
16801680
("QS", offsets.QuarterBegin(startingMonth=1)),
1681-
("BQ", offsets.BQuarterEnd(startingMonth=12)),
1681+
("BQE", offsets.BQuarterEnd(startingMonth=12)),
16821682
("W-SUN", offsets.Week(weekday=6)),
16831683
],
16841684
)

pandas/tests/indexes/datetimes/test_datetime.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -195,16 +195,24 @@ def test_AS_BA_BAS_deprecated(self, freq_depr, expected_values, expected_freq):
195195

196196
tm.assert_index_equal(result, expected)
197197

198-
def test_BM_deprecated(self):
198+
@pytest.mark.parametrize(
199+
"freq, expected_values, freq_depr",
200+
[
201+
("2BME", ["2016-02-29", "2016-04-29", "2016-06-30"], "2BM"),
202+
("2BQE", ["2016-03-31"], "2BQ"),
203+
("1BQE-MAR", ["2016-03-31", "2016-06-30"], "1BQ-MAR"),
204+
],
205+
)
206+
def test_BM_BQ_deprecated(self, freq, expected_values, freq_depr):
199207
# GH#52064
200-
msg = "'BM' is deprecated and will be removed in a future version."
208+
msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
201209

202210
with tm.assert_produces_warning(FutureWarning, match=msg):
203-
expected = date_range(start="2016-02-21", end="2016-08-21", freq="2BM")
211+
expected = date_range(start="2016-02-21", end="2016-08-21", freq=freq_depr)
204212
result = DatetimeIndex(
205-
["2016-02-29", "2016-04-29", "2016-06-30"],
213+
data=expected_values,
206214
dtype="datetime64[ns]",
207-
freq="2BME",
215+
freq=freq,
208216
)
209217

210218
tm.assert_index_equal(result, expected)

pandas/tests/indexes/datetimes/test_scalar_compat.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def test_dti_fields(self, tz):
308308
tm.assert_index_equal(res, exp)
309309

310310
def test_dti_is_year_quarter_start(self):
311-
dti = date_range(freq="BQ-FEB", start=datetime(1998, 1, 1), periods=4)
311+
dti = date_range(freq="BQE-FEB", start=datetime(1998, 1, 1), periods=4)
312312

313313
assert sum(dti.is_quarter_start) == 0
314314
assert sum(dti.is_quarter_end) == 4

pandas/tests/indexes/period/test_period.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ def test_a_deprecated_from_time_series(self, freq_depr):
308308
series = Series(1, index=index)
309309
assert isinstance(series, Series)
310310

311-
@pytest.mark.parametrize("freq_depr", ["2ME", "2QE", "2YE"])
311+
@pytest.mark.parametrize("freq_depr", ["2ME", "2QE", "2BQE", "2YE"])
312312
def test_period_index_frequency_error_message(self, freq_depr):
313313
# GH#9586
314314
msg = f"for Period, please use '{freq_depr[1:-1]}' "

pandas/tests/resample/test_datetime_index.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -2060,7 +2060,7 @@ def test_resample_empty_series_with_tz():
20602060
)
20612061
def test_resample_M_Q_Y_A_deprecated(freq, freq_depr):
20622062
# GH#9586
2063-
depr_msg = f"'{freq_depr[1:]}' will be deprecated, please use '{freq[1:]}' instead."
2063+
depr_msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
20642064

20652065
s = Series(range(10), index=date_range("20130101", freq="d", periods=10))
20662066
expected = s.resample(freq).mean()
@@ -2069,14 +2069,22 @@ def test_resample_M_Q_Y_A_deprecated(freq, freq_depr):
20692069
tm.assert_series_equal(result, expected)
20702070

20712071

2072-
def test_resample_BM_deprecated():
2072+
@pytest.mark.parametrize(
2073+
"freq, freq_depr",
2074+
[
2075+
("2BME", "2BM"),
2076+
("2BQE", "2BQ"),
2077+
("2BQE-MAR", "2BQ-MAR"),
2078+
],
2079+
)
2080+
def test_resample_BM_BQ_deprecated(freq, freq_depr):
20732081
# GH#52064
2074-
depr_msg = "'BM' is deprecated and will be removed in a future version."
2082+
depr_msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead."
20752083

20762084
s = Series(range(10), index=date_range("20130101", freq="d", periods=10))
2077-
expected = s.resample("2BME").mean()
2085+
expected = s.resample(freq).mean()
20782086
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
2079-
result = s.resample("2BM").mean()
2087+
result = s.resample(freq_depr).mean()
20802088
tm.assert_series_equal(result, expected)
20812089

20822090

pandas/tests/resample/test_period_index.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -928,10 +928,13 @@ def test_resample_t_l_deprecated(self):
928928
tm.assert_series_equal(result, expected)
929929

930930

931-
@pytest.mark.parametrize("freq_depr", ["2ME", "2QE", "2QE-FEB", "2YE", "2YE-MAR"])
931+
@pytest.mark.parametrize(
932+
"freq_depr", ["2ME", "2QE", "2QE-FEB", "2BQE", "2BQE-FEB", "2YE", "2YE-MAR"]
933+
)
932934
def test_resample_frequency_ME_QE_error_message(series_and_frame, freq_depr):
933935
# GH#9586
934-
msg = f"for Period, please use '{freq_depr[1:2]}{freq_depr[3:]}' "
936+
pos_e = freq_depr.index("E")
937+
msg = f"for Period, please use '{freq_depr[1:pos_e]}{freq_depr[pos_e+1:]}' "
935938
f"instead of '{freq_depr[1:]}'"
936939

937940
obj = series_and_frame

pandas/tests/tseries/offsets/test_offsets.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -838,7 +838,7 @@ def test_rule_code(self):
838838
"NOV",
839839
"DEC",
840840
]
841-
base_lst = ["YE", "YS", "BY", "BYS", "QE", "QS", "BQ", "BQS"]
841+
base_lst = ["YE", "YS", "BY", "BYS", "QE", "QS", "BQE", "BQS"]
842842
for base in base_lst:
843843
for v in suffix_lst:
844844
alias = "-".join([base, v])
@@ -857,7 +857,7 @@ def test_freq_offsets():
857857
class TestReprNames:
858858
def test_str_for_named_is_name(self):
859859
# look at all the amazing combinations!
860-
month_prefixes = ["YE", "YS", "BY", "BYS", "QE", "BQ", "BQS", "QS"]
860+
month_prefixes = ["YE", "YS", "BY", "BYS", "QE", "BQE", "BQS", "QS"]
861861
names = [
862862
prefix + "-" + month
863863
for prefix in month_prefixes
@@ -1122,7 +1122,7 @@ def test_is_yqm_start_end():
11221122
bm = to_offset("BME")
11231123
qfeb = to_offset("QE-FEB")
11241124
qsfeb = to_offset("QS-FEB")
1125-
bq = to_offset("BQ")
1125+
bq = to_offset("BQE")
11261126
bqs_apr = to_offset("BQS-APR")
11271127
as_nov = to_offset("YS-NOV")
11281128

pandas/tseries/frequencies.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
# --------------------------------------------------------------------
6060
# Offset related functions
6161

62-
_need_suffix = ["QS", "BQ", "BQS", "YS", "BY", "BYS"]
62+
_need_suffix = ["QS", "BQE", "BQS", "YS", "BY", "BYS"]
6363

6464
for _prefix in _need_suffix:
6565
for _m in MONTHS:
@@ -359,7 +359,7 @@ def _get_quarterly_rule(self) -> str | None:
359359
if pos_check is None:
360360
return None
361361
else:
362-
return {"cs": "QS", "bs": "BQS", "ce": "QE", "be": "BQ"}.get(pos_check)
362+
return {"cs": "QS", "bs": "BQS", "ce": "QE", "be": "BQE"}.get(pos_check)
363363

364364
def _get_monthly_rule(self) -> str | None:
365365
if len(self.mdiffs) > 1:

0 commit comments

Comments
 (0)