From 4e8b42bd3707158596b91233d4e97c85021cddeb Mon Sep 17 00:00:00 2001 From: Natalia Mokeeva Date: Sat, 18 Nov 2023 19:06:14 +0100 Subject: [PATCH 1/3] rename SM to SME for offsets, fix teests --- pandas/_libs/tslibs/dtypes.pyx | 4 ++-- pandas/_libs/tslibs/offsets.pyx | 4 ++-- .../indexes/datetimes/test_date_range.py | 4 ++-- pandas/tests/tseries/offsets/test_month.py | 4 ++-- pandas/tests/tslibs/test_to_offset.py | 24 +++++++++---------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/pandas/_libs/tslibs/dtypes.pyx b/pandas/_libs/tslibs/dtypes.pyx index 75558ea73831b..ffb1afe8720e1 100644 --- a/pandas/_libs/tslibs/dtypes.pyx +++ b/pandas/_libs/tslibs/dtypes.pyx @@ -175,6 +175,7 @@ OFFSET_TO_PERIOD_FREQSTR: dict = { "WEEKDAY": "D", "EOM": "M", "BME": "M", + "SME": "M", "BQS": "Q", "QS": "Q", "BQE": "Q", @@ -275,6 +276,7 @@ cdef dict c_OFFSET_DEPR_FREQSTR = { "A-NOV": "YE-NOV", "BM": "BME", "CBM": "CBME", + "SM": "SME", "BQ": "BQE", "BQ-DEC": "BQE-DEC", "BQ-JAN": "BQE-JAN", @@ -358,8 +360,6 @@ cdef dict c_DEPR_ABBREVS = { "BAS-SEP": "BYS-SEP", "BAS-OCT": "BYS-OCT", "BAS-NOV": "BYS-NOV", - "BM": "BME", - "CBM": "CBME", "H": "h", "BH": "bh", "CBH": "cbh", diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index 69156ca561508..b79b8b23118a6 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -3129,7 +3129,7 @@ cdef class SemiMonthEnd(SemiMonthOffset): >>> pd.offsets.SemiMonthEnd().rollforward(ts) Timestamp('2022-01-15 00:00:00') """ - _prefix = "SM" + _prefix = "SME" _min_day_of_month = 1 def is_on_offset(self, dt: datetime) -> bool: @@ -4549,7 +4549,7 @@ prefix_mapping = { MonthEnd, # 'ME' MonthBegin, # 'MS' Nano, # 'ns' - SemiMonthEnd, # 'SM' + SemiMonthEnd, # 'SME' SemiMonthBegin, # 'SMS' Week, # 'W' Second, # 's' diff --git a/pandas/tests/indexes/datetimes/test_date_range.py b/pandas/tests/indexes/datetimes/test_date_range.py index 4043faada44a8..9175a96b912fa 100644 --- a/pandas/tests/indexes/datetimes/test_date_range.py +++ b/pandas/tests/indexes/datetimes/test_date_range.py @@ -1624,8 +1624,8 @@ def test_date_range_semi_month_end(self, unit): datetime(2008, 12, 31), ] # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SM", unit=unit) - exp = DatetimeIndex(dates, dtype=f"M8[{unit}]", freq="SM") + result = date_range(start=dates[0], end=dates[-1], freq="SME", unit=unit) + exp = DatetimeIndex(dates, dtype=f"M8[{unit}]", freq="SME") tm.assert_index_equal(result, exp) def test_date_range_week_of_month(self, unit): diff --git a/pandas/tests/tseries/offsets/test_month.py b/pandas/tests/tseries/offsets/test_month.py index fc12510369245..bd3f674c8455f 100644 --- a/pandas/tests/tseries/offsets/test_month.py +++ b/pandas/tests/tseries/offsets/test_month.py @@ -75,8 +75,8 @@ def test_offset_whole_year(self): tm.assert_index_equal(result, exp) # ensure generating a range with DatetimeIndex gives same result - result = date_range(start=dates[0], end=dates[-1], freq="SM") - exp = DatetimeIndex(dates, freq="SM") + result = date_range(start=dates[0], end=dates[-1], freq="SME") + exp = DatetimeIndex(dates, freq="SME") tm.assert_index_equal(result, exp) offset_cases = [] diff --git a/pandas/tests/tslibs/test_to_offset.py b/pandas/tests/tslibs/test_to_offset.py index 3fb205f21a857..ef68408305232 100644 --- a/pandas/tests/tslibs/test_to_offset.py +++ b/pandas/tests/tslibs/test_to_offset.py @@ -26,8 +26,8 @@ ("1s0.25ms", offsets.Micro(1000250)), ("1s0.25ms", offsets.Micro(1000250)), ("2800ns", offsets.Nano(2800)), - ("2SM", offsets.SemiMonthEnd(2)), - ("2SM-16", offsets.SemiMonthEnd(2, day_of_month=16)), + ("2SME", offsets.SemiMonthEnd(2)), + ("2SME-16", offsets.SemiMonthEnd(2, day_of_month=16)), ("2SMS-14", offsets.SemiMonthBegin(2, day_of_month=14)), ("2SMS-15", offsets.SemiMonthBegin(2)), ], @@ -38,7 +38,7 @@ def test_to_offset(freq_input, expected): @pytest.mark.parametrize( - "freqstr,expected", [("-1s", -1), ("-2SM", -2), ("-1SMS", -1), ("-5min10s", -310)] + "freqstr,expected", [("-1s", -1), ("-2SME", -2), ("-1SMS", -1), ("-5min10s", -310)] ) def test_to_offset_negative(freqstr, expected): result = to_offset(freqstr) @@ -66,12 +66,12 @@ def test_to_offset_negative(freqstr, expected): "+d", "-m", # Invalid shortcut anchors. - "SM-0", - "SM-28", - "SM-29", - "SM-FOO", + "SME-0", + "SME-28", + "SME-29", + "SME-FOO", "BSM", - "SM--1", + "SME--1", "SMS-1", "SMS-28", "SMS-30", @@ -161,10 +161,10 @@ def test_to_offset_pd_timedelta(kwargs, expected): ("QE", offsets.QuarterEnd(startingMonth=12)), ("QE-DEC", offsets.QuarterEnd(startingMonth=12)), ("QE-MAY", offsets.QuarterEnd(startingMonth=5)), - ("SM", offsets.SemiMonthEnd(day_of_month=15)), - ("SM-15", offsets.SemiMonthEnd(day_of_month=15)), - ("SM-1", offsets.SemiMonthEnd(day_of_month=1)), - ("SM-27", offsets.SemiMonthEnd(day_of_month=27)), + ("SME", offsets.SemiMonthEnd(day_of_month=15)), + ("SME-15", offsets.SemiMonthEnd(day_of_month=15)), + ("SME-1", offsets.SemiMonthEnd(day_of_month=1)), + ("SME-27", offsets.SemiMonthEnd(day_of_month=27)), ("SMS-2", offsets.SemiMonthBegin(day_of_month=2)), ("SMS-27", offsets.SemiMonthBegin(day_of_month=27)), ], From 902df752f519b4d36e2e557c80823e0ccbe44b2b Mon Sep 17 00:00:00 2001 From: Natalia Mokeeva Date: Sat, 18 Nov 2023 22:11:23 +0100 Subject: [PATCH 2/3] correct timeseries user_guide, fix errors in v0.19.0 --- doc/source/user_guide/timeseries.rst | 4 ++-- doc/source/whatsnew/v0.19.0.rst | 16 ++++++++++------ 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/doc/source/user_guide/timeseries.rst b/doc/source/user_guide/timeseries.rst index 22e3921bbf06b..ca57e68d76015 100644 --- a/doc/source/user_guide/timeseries.rst +++ b/doc/source/user_guide/timeseries.rst @@ -882,7 +882,7 @@ into ``freq`` keyword arguments. The available date offsets and associated frequ :class:`~pandas.tseries.offsets.BMonthBegin` or :class:`~pandas.tseries.offsets.BusinessMonthBegin`, ``'BMS'``, "business month begin" :class:`~pandas.tseries.offsets.CBMonthEnd` or :class:`~pandas.tseries.offsets.CustomBusinessMonthEnd`, ``'CBME'``, "custom business month end" :class:`~pandas.tseries.offsets.CBMonthBegin` or :class:`~pandas.tseries.offsets.CustomBusinessMonthBegin`, ``'CBMS'``, "custom business month begin" - :class:`~pandas.tseries.offsets.SemiMonthEnd`, ``'SM'``, "15th (or other day_of_month) and calendar month end" + :class:`~pandas.tseries.offsets.SemiMonthEnd`, ``'SME'``, "15th (or other day_of_month) and calendar month end" :class:`~pandas.tseries.offsets.SemiMonthBegin`, ``'SMS'``, "15th (or other day_of_month) and calendar month begin" :class:`~pandas.tseries.offsets.QuarterEnd`, ``'QE'``, "calendar quarter end" :class:`~pandas.tseries.offsets.QuarterBegin`, ``'QS'``, "calendar quarter begin" @@ -1241,7 +1241,7 @@ frequencies. We will refer to these aliases as *offset aliases*. "D", "calendar day frequency" "W", "weekly frequency" "ME", "month end frequency" - "SM", "semi-month end frequency (15th and end of month)" + "SME", "semi-month end frequency (15th and end of month)" "BME", "business month end frequency" "CBME", "custom business month end frequency" "MS", "month start frequency" diff --git a/doc/source/whatsnew/v0.19.0.rst b/doc/source/whatsnew/v0.19.0.rst index 32b3ced4f9d39..1ae711113773f 100644 --- a/doc/source/whatsnew/v0.19.0.rst +++ b/doc/source/whatsnew/v0.19.0.rst @@ -329,11 +329,13 @@ These provide date offsets anchored (by default) to the 15th and end of month, a **SemiMonthEnd**: -.. ipython:: python +.. code-block:: python - pd.Timestamp("2016-01-01") + SemiMonthEnd() + In [46]: pd.Timestamp("2016-01-01") + SemiMonthEnd() + Out[46]: Timestamp('2016-01-15 00:00:00') - pd.date_range("2015-01-01", freq="SM", periods=4) + In [47]: pd.date_range("2015-01-01", freq="SM", periods=4) + Out[47]: DatetimeIndex(['2015-01-15', '2015-01-31', '2015-02-15', '2015-02-28'], dtype='datetime64[ns]', freq='SM-15') **SemiMonthBegin**: @@ -345,11 +347,13 @@ These provide date offsets anchored (by default) to the 15th and end of month, a Using the anchoring suffix, you can also specify the day of month to use instead of the 15th. -.. ipython:: python +.. code-block:: python - pd.date_range("2015-01-01", freq="SMS-16", periods=4) + In [50]: pd.date_range("2015-01-01", freq="SMS-16", periods=4) + Out[50]: DatetimeIndex(['2015-01-01', '2015-01-16', '2015-02-01', '2015-02-16'], dtype='datetime64[ns]', freq='SMS-16') - pd.date_range("2015-01-01", freq="SM-14", periods=4) + In [51]: pd.date_range("2015-01-01", freq="SM-14", periods=4) + Out[51]: DatetimeIndex(['2015-01-14', '2015-01-31', '2015-02-14', '2015-02-28'], dtype='datetime64[ns]', freq='SM-14') .. _whatsnew_0190.enhancements.index: From 4be073d8fc8e8e8e0c2e345553c6a07010df860f Mon Sep 17 00:00:00 2001 From: Natalia Mokeeva Date: Sun, 19 Nov 2023 15:34:45 +0100 Subject: [PATCH 3/3] add tests, add notes to v2.2.0 --- doc/source/whatsnew/v2.2.0.rst | 10 +++++++--- .../tests/indexes/datetimes/test_date_range.py | 16 ++++++++++++---- pandas/tests/indexes/period/test_period.py | 14 +++++++++++--- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/doc/source/whatsnew/v2.2.0.rst b/doc/source/whatsnew/v2.2.0.rst index a33322aebab34..fca1eada92cec 100644 --- a/doc/source/whatsnew/v2.2.0.rst +++ b/doc/source/whatsnew/v2.2.0.rst @@ -233,13 +233,17 @@ Other API changes Deprecations ~~~~~~~~~~~~ -Deprecate aliases ``M``, ``Q``, and ``Y`` in favour of ``ME``, ``QE``, and ``YE`` for offsets -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Deprecate aliases ``M``, ``SM``, ``BM``, ``CBM``, ``Q``, ``BQ``, and ``Y`` in favour of ``ME``, ``SME``, ``BME``, ``CBME``, ``QE``, ``BQE``, and ``YE`` for offsets +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Deprecated the following frequency aliases (:issue:`9586`): - ``M`` (month end) has been renamed ``ME`` for offsets +- ``SM`` (semi month end) has been renamed ``SME`` for offsets +- ``BM`` (business month end) has been renamed ``BME`` for offsets +- ``CBM`` (custom business month end) has been renamed ``CBME`` for offsets - ``Q`` (quarter end) has been renamed ``QE`` for offsets +- ``BQ`` (business quarter end) has been renamed ``BQE`` for offsets - ``Y`` (year end) has been renamed ``YE`` for offsets For example: @@ -291,7 +295,7 @@ Other Deprecations - 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`) - 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`) - Deprecated string ``BQ`` denoting frequency in :class:`BQuarterEnd` (:issue:`52064`) -- Deprecated strings ``BM``, and ``CBM`` denoting frequencies in :class:`BusinessMonthEnd`, :class:`CustomBusinessMonthEnd` (:issue:`52064`) +- Deprecated strings ``BM``, ``CBM``, and ``SM`` denoting frequencies in :class:`BusinessMonthEnd`, :class:`CustomBusinessMonthEnd, :class:`SemiMonthEnd` (:issue:`52064`) - Deprecated strings ``H``, ``BH``, and ``CBH`` denoting frequencies in :class:`Hour`, :class:`BusinessHour`, :class:`CustomBusinessHour` (:issue:`52536`) - Deprecated strings ``H``, ``S``, ``U``, and ``N`` denoting units in :func:`to_timedelta` (:issue:`52536`) - Deprecated strings ``H``, ``T``, ``S``, ``L``, ``U``, and ``N`` denoting units in :class:`Timedelta` (:issue:`52536`) diff --git a/pandas/tests/indexes/datetimes/test_date_range.py b/pandas/tests/indexes/datetimes/test_date_range.py index 9175a96b912fa..80b5880257483 100644 --- a/pandas/tests/indexes/datetimes/test_date_range.py +++ b/pandas/tests/indexes/datetimes/test_date_range.py @@ -145,12 +145,20 @@ def test_date_range_float_periods(self): exp = date_range("1/1/2000", periods=10) tm.assert_index_equal(rng, exp) - def test_date_range_frequency_M_deprecated(self): - depr_msg = "'M' is deprecated, please use 'ME' instead." + @pytest.mark.parametrize( + "freq,freq_depr", + [ + ("2ME", "2M"), + ("2SME", "2SM"), + ], + ) + def test_date_range_frequency_M_SM_deprecated(self, freq, freq_depr): + # GH#52064 + depr_msg = f"'{freq_depr[1:]}' is deprecated, please use '{freq[1:]}' instead." - expected = date_range("1/1/2000", periods=4, freq="2ME") + expected = date_range("1/1/2000", periods=4, freq=freq) with tm.assert_produces_warning(FutureWarning, match=depr_msg): - result = date_range("1/1/2000", periods=4, freq="2M") + result = date_range("1/1/2000", periods=4, freq=freq_depr) tm.assert_index_equal(result, expected) def test_date_range_tuple_freq_raises(self): diff --git a/pandas/tests/indexes/period/test_period.py b/pandas/tests/indexes/period/test_period.py index fa85b7ea45abd..7b7baab112264 100644 --- a/pandas/tests/indexes/period/test_period.py +++ b/pandas/tests/indexes/period/test_period.py @@ -281,11 +281,19 @@ def test_map(self): exp = Index([x.ordinal for x in index]) tm.assert_index_equal(result, exp) - def test_period_index_frequency_ME_error_message(self): - msg = "for Period, please use 'M' instead of 'ME'" + @pytest.mark.parametrize( + "freq,freq_depr", + [ + ("2M", "2ME"), + ("2SM", "2SME"), + ], + ) + def test_period_index_frequency_ME_SME_error_message(self, freq, freq_depr): + # GH#52064 + msg = f"for Period, please use '{freq[1:]}' instead of '{freq_depr[1:]}'" with pytest.raises(ValueError, match=msg): - PeriodIndex(["2020-01-01", "2020-01-02"], freq="2ME") + PeriodIndex(["2020-01-01", "2020-01-02"], freq=freq_depr) def test_H_deprecated_from_time_series(self): # GH#52536