Skip to content
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

CLN: enforce deprecation of frequencies deprecated for offsets #57986

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
10f8ba6
enforce deprecation of offset deprecated freqstr
natmokval Mar 24, 2024
428fd06
fix tests
natmokval Mar 25, 2024
363395a
fix mypy error
natmokval Mar 25, 2024
bba27f4
Merge branch 'main' into depr-enforce-deprecation-offset-depr-freqstr
natmokval Mar 25, 2024
d6092b3
add a note to v3.0.0
natmokval Mar 25, 2024
f5fd5ff
remove c_REVERSE_OFFSET_REMOVED_FREQSTR, correct tests
natmokval Mar 28, 2024
6a124ae
fix test_to_period_offsets_not_supported
natmokval Mar 28, 2024
19f35cc
correct to_offset, fix tests
natmokval Apr 1, 2024
8b9edf4
add dict PERIOD_TO_OFFSET_FREQSTR, corect meth to_offset, fix tests
natmokval Apr 12, 2024
df65a84
Merge branch 'main' into depr-enforce-deprecation-offset-depr-freqstr
natmokval Apr 12, 2024
30b7765
add a comment
natmokval Apr 12, 2024
49af3e7
Merge branch 'main' into depr-enforce-deprecation-offset-depr-freqstr
natmokval May 2, 2024
81fe8f0
create dictionary PERIOD_AND_OFFSET_ALIASES
natmokval May 2, 2024
727c6ae
correct def to_offset
natmokval May 2, 2024
2ae8533
Merge branch 'main' into depr-enforce-deprecation-offset-depr-freqstr
natmokval May 15, 2024
c730be0
fixup
natmokval May 17, 2024
81ad386
fixup
natmokval May 21, 2024
dcc1c92
replace c_OFFSET_RENAMED_FREQSTR with c_PERIOD_TO_OFFSET_FREQSTR
natmokval May 31, 2024
5616c3d
add cimport c_PERIOD_TO_OFFSET_FREQSTR
natmokval May 31, 2024
163d05b
Merge branch 'main' into depr-enforce-deprecation-offset-depr-freqstr
natmokval May 31, 2024
be6c0bc
resolve conflict
natmokval Jun 1, 2024
74ae136
Merge branch 'depr-enforce-deprecation-offset-depr-freqstr' of https:…
natmokval Jun 1, 2024
d7a5037
add a helper function for error reporting
natmokval Jun 1, 2024
d9b3a5e
minor whatsnew fix
MarcoGorelli Jun 1, 2024
46bcd86
Merge remote-tracking branch 'upstream/main' into depr-enforce-deprec…
MarcoGorelli Jun 6, 2024
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
30 changes: 29 additions & 1 deletion doc/source/whatsnew/v3.0.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,34 @@ Other Deprecations

Removal of prior version deprecations/changes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Enforced deprecation of aliases ``M``, ``Q``, ``Y``, etc. in favour of ``ME``, ``QE``, ``YE``, etc. for offsets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Removed the following frequency aliases (:issue:`57986`):

+-------------------------------+------------------+------------------+
|offsets |removed aliases |new aliases |
+===============================+==================+==================+
|:class:`MonthEnd` | ``M`` | ``ME`` |
+-------------------------------+------------------+------------------+
|:class:`BusinessMonthEnd` | ``BM`` | ``BME`` |
+-------------------------------+------------------+------------------+
|:class:`SemiMonthEnd` | ``SM`` | ``SME`` |
+-------------------------------+------------------+------------------+
|:class:`CustomBusinessMonthEnd`| ``CBM`` | ``CBME`` |
+-------------------------------+------------------+------------------+
|:class:`QuarterEnd` | ``Q`` | ``QE`` |
+-------------------------------+------------------+------------------+
|:class:`BQuarterEnd` | ``BQ`` | ``BQE`` |
+-------------------------------+------------------+------------------+
|:class:`YearEnd` | ``Y`` | ``YE`` |
+-------------------------------+------------------+------------------+
|:class:`BYearEnd` | ``BY`` | ``BYE`` |
+-------------------------------+------------------+------------------+

Other Removal
^^^^^^^^^^^^^
- :class:`.DataFrameGroupBy.idxmin`, :class:`.DataFrameGroupBy.idxmax`, :class:`.SeriesGroupBy.idxmin`, and :class:`.SeriesGroupBy.idxmax` will now raise a ``ValueError`` when used with ``skipna=False`` and an NA value is encountered (:issue:`10694`)
- :func:`read_excel`, :func:`read_json`, :func:`read_html`, and :func:`read_xml` no longer accept raw string or byte representation of the data. That type of data must be wrapped in a :py:class:`StringIO` or :py:class:`BytesIO` (:issue:`53767`)
- :meth:`DataFrame.groupby` with ``as_index=False`` and aggregation methods will no longer exclude from the result the groupings that do not arise from the input (:issue:`49519`)
Expand All @@ -208,7 +236,7 @@ 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 frequencies in :class:`Minute`, :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 deprecation of values "pad", "ffill", "bfill", and "backfill" for :meth:`Series.interpolate` and :meth:`DataFrame.interpolate` (:issue:`57869`)
Expand Down
3 changes: 1 addition & 2 deletions pandas/_libs/tslibs/dtypes.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ cdef NPY_DATETIMEUNIT get_supported_reso(NPY_DATETIMEUNIT reso)
cdef bint is_supported_unit(NPY_DATETIMEUNIT reso)

cdef dict c_OFFSET_TO_PERIOD_FREQSTR
cdef dict c_OFFSET_DEPR_FREQSTR
cdef dict c_REVERSE_OFFSET_DEPR_FREQSTR
cdef dict c_OFFSET_REMOVED_FREQSTR
cdef dict c_DEPR_ABBREVS
cdef dict attrname_to_abbrevs
cdef dict npy_unit_to_attrname
Expand Down
5 changes: 1 addition & 4 deletions pandas/_libs/tslibs/dtypes.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ OFFSET_TO_PERIOD_FREQSTR: dict = {
"YS": "Y",
"BYS": "Y",
}
cdef dict c_OFFSET_DEPR_FREQSTR = {
cdef dict c_OFFSET_REMOVED_FREQSTR = {
"M": "ME",
"Q": "QE",
"Q-DEC": "QE-DEC",
Expand Down Expand Up @@ -304,9 +304,6 @@ cdef dict c_OFFSET_DEPR_FREQSTR = {
"BQ-NOV": "BQE-NOV",
}
cdef dict c_OFFSET_TO_PERIOD_FREQSTR = OFFSET_TO_PERIOD_FREQSTR
cdef dict c_REVERSE_OFFSET_DEPR_FREQSTR = {
v: k for k, v in c_OFFSET_DEPR_FREQSTR.items()
}

# Map deprecated resolution abbreviations to correct resolution abbreviations
cdef dict c_DEPR_ABBREVS = {
Expand Down
57 changes: 20 additions & 37 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ from pandas._libs.tslibs.ccalendar cimport (
from pandas._libs.tslibs.conversion cimport localize_pydatetime
from pandas._libs.tslibs.dtypes cimport (
c_DEPR_ABBREVS,
c_OFFSET_DEPR_FREQSTR,
c_REVERSE_OFFSET_DEPR_FREQSTR,
c_OFFSET_REMOVED_FREQSTR,
c_OFFSET_TO_PERIOD_FREQSTR,
periods_per_day,
)
from pandas._libs.tslibs.nattype cimport (
Expand Down Expand Up @@ -4847,53 +4847,36 @@ cpdef to_offset(freq, bint is_period=False):

tups = zip(split[0::4], split[1::4], split[2::4])
for n, (sep, stride, name) in enumerate(tups):
if not is_period and name.upper() in c_OFFSET_DEPR_FREQSTR:
warnings.warn(
f"\'{name}\' is deprecated and will be removed "
f"in a future version, please use "
f"\'{c_OFFSET_DEPR_FREQSTR.get(name.upper())}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
if not is_period and name.upper() in c_OFFSET_REMOVED_FREQSTR:
raise ValueError(
f"\'{name}\' is no longer supported for offsets. Please use "
f"\'{c_OFFSET_REMOVED_FREQSTR.get(name.upper())}\' instead."
)
name = c_OFFSET_DEPR_FREQSTR[name.upper()]
if (not is_period and
name != name.upper() and
name.lower() not in {"s", "ms", "us", "ns"} and
name.upper().split("-")[0].endswith(("S", "E"))):
warnings.warn(
f"\'{name}\' is deprecated and will be removed "
f"in a future version, please use "
f"\'{name.upper()}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
name = name.upper()
if is_period and name.upper() in c_REVERSE_OFFSET_DEPR_FREQSTR:
if name.upper().startswith("Y"):
if name.upper() in c_OFFSET_TO_PERIOD_FREQSTR:
raise ValueError(
f"for Period, please use \'Y{name.upper()[2:]}\' "
f"instead of \'{name}\'"
f"\'{name}\' is no longer supported for offsets. Please "
f"use \'{name.upper()}\' instead."
)
if (name.upper().startswith("B") or
name.upper().startswith("S") or
name.upper().startswith("C")):
else:
raise ValueError(INVALID_FREQ_ERR_MSG.format(name))
if (is_period and
name.upper().split("-")[0].endswith(("E")) and
name.upper() in c_OFFSET_TO_PERIOD_FREQSTR):
if name.upper().startswith("B"):
raise ValueError(INVALID_FREQ_ERR_MSG.format(name))
else:
raise ValueError(
f"for Period, please use "
f"\'{c_REVERSE_OFFSET_DEPR_FREQSTR.get(name.upper())}\' "
f"instead of \'{name}\'"
f"{name} is not supported as period frequency"
)
elif is_period and name.upper() in c_OFFSET_DEPR_FREQSTR:

elif is_period and name.upper() in c_OFFSET_REMOVED_FREQSTR:
MarcoGorelli marked this conversation as resolved.
Show resolved Hide resolved
if name.upper() != name:
warnings.warn(
f"\'{name}\' is deprecated and will be removed in "
f"a future version, please use \'{name.upper()}\' "
f"instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
name = c_OFFSET_DEPR_FREQSTR.get(name.upper())
raise ValueError(INVALID_FREQ_ERR_MSG.format(name))
name = c_OFFSET_REMOVED_FREQSTR.get(name.upper())
MarcoGorelli marked this conversation as resolved.
Show resolved Hide resolved

if sep != "" and not sep.isspace():
raise ValueError("separator must be spaces")
Expand Down
45 changes: 17 additions & 28 deletions pandas/tests/arrays/test_datetimes.py
Original file line number Diff line number Diff line change
Expand Up @@ -764,29 +764,14 @@ def test_iter_zoneinfo_fold(self, tz):
assert left.utcoffset() == right2.utcoffset()

@pytest.mark.parametrize(
"freq, freq_depr",
[
("2ME", "2M"),
("2SME", "2SM"),
("2SME", "2sm"),
("2QE", "2Q"),
("2QE-SEP", "2Q-SEP"),
("1YE", "1Y"),
("2YE-MAR", "2Y-MAR"),
("2ME", "2m"),
("2QE-SEP", "2q-sep"),
("2YE", "2y"),
],
"freq",
["2M", "2SM", "2sm", "2Q", "2Q-SEP", "1Y", "2Y-MAR", "2m", "2q-sep", "2y"],
)
def test_date_range_frequency_M_Q_Y_A_deprecated(self, freq, freq_depr):
# GH#9586, GH#54275
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed "
f"in a future version, please use '{freq[1:]}' instead."
def test_date_range_frequency_M_Q_Y_raises(self, freq):
msg = f"Invalid frequency: {freq}"

expected = pd.date_range("1/1/2000", periods=4, freq=freq)
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
result = pd.date_range("1/1/2000", periods=4, freq=freq_depr)
tm.assert_index_equal(result, expected)
with pytest.raises(ValueError, match=msg):
pd.date_range("1/1/2000", periods=4, freq=freq)

@pytest.mark.parametrize("freq_depr", ["2H", "2CBH", "2MIN", "2S", "2mS", "2Us"])
def test_date_range_uppercase_frequency_deprecated(self, freq_depr):
Expand All @@ -800,7 +785,7 @@ def test_date_range_uppercase_frequency_deprecated(self, freq_depr):
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize(
"freq_depr",
"freq",
[
"2ye-mar",
"2ys",
Expand All @@ -811,17 +796,21 @@ def test_date_range_uppercase_frequency_deprecated(self, freq_depr):
"2bms",
"2cbme",
"2me",
"2w",
],
)
def test_date_range_lowercase_frequency_deprecated(self, freq_depr):
def test_date_range_lowercase_frequency_raises(self, freq):
msg = f"Invalid frequency: {freq}"

with pytest.raises(ValueError, match=msg):
pd.date_range("1/1/2000", periods=4, freq=freq)

def test_date_range_lowercase_frequency_deprecated(self):
# GH#9586, GH#54939
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed in a "
f"future version, please use '{freq_depr.upper()[1:]}' instead."
depr_msg = "'w' is deprecated and will be removed in a future version"

expected = pd.date_range("1/1/2000", periods=4, freq=freq_depr.upper())
expected = pd.date_range("1/1/2000", periods=4, freq="2W")
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
result = pd.date_range("1/1/2000", periods=4, freq=freq_depr)
result = pd.date_range("1/1/2000", periods=4, freq="2w")
tm.assert_index_equal(result, expected)

@pytest.mark.parametrize("freq", ["1A", "2A-MAR", "2a-mar"])
Expand Down
16 changes: 7 additions & 9 deletions pandas/tests/frame/methods/test_asfreq.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,25 +236,23 @@ def test_asfreq_2ME(self, freq, freq_half):
"freq, freq_depr",
[
("2ME", "2M"),
("2ME", "2m"),
("2QE", "2Q"),
("2QE-SEP", "2Q-SEP"),
("1BQE", "1BQ"),
("2BQE-SEP", "2BQ-SEP"),
("1YE", "1Y"),
("2BQE-SEP", "2bq-sep"),
("1YE", "1y"),
("2YE-MAR", "2Y-MAR"),
],
)
def test_asfreq_frequency_M_Q_Y_deprecated(self, freq, freq_depr):
# GH#9586, #55978
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed "
f"in a future version, please use '{freq[1:]}' instead."
def test_asfreq_frequency_M_Q_Y_raises(self, freq, freq_depr):
msg = f"Invalid frequency: {freq_depr}"

index = date_range("1/1/2000", periods=4, freq=f"{freq[1:]}")
df = DataFrame({"s": Series([0.0, 1.0, 2.0, 3.0], index=index)})
expected = df.asfreq(freq=freq)
with tm.assert_produces_warning(FutureWarning, match=depr_msg):
result = df.asfreq(freq=freq_depr)
tm.assert_frame_equal(result, expected)
with pytest.raises(ValueError, match=msg):
df.asfreq(freq=freq_depr)

@pytest.mark.parametrize(
"freq, error_msg",
Expand Down
34 changes: 15 additions & 19 deletions pandas/tests/indexes/datetimes/methods/test_to_period.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,24 +90,14 @@ def test_dti_to_period_2monthish(self, freq_offset, freq_period):
tm.assert_index_equal(pi, period_range("2020-01", "2020-05", freq=freq_period))

@pytest.mark.parametrize(
"freq, freq_depr",
[
("2ME", "2M"),
("2QE", "2Q"),
("2QE-SEP", "2Q-SEP"),
("1YE", "1Y"),
("2YE-MAR", "2Y-MAR"),
],
"freq", ["2ME", "1me", "2QE", "2QE-SEP", "1YE", "ye", "2YE-MAR"]
)
def test_to_period_frequency_M_Q_Y_deprecated(self, freq, freq_depr):
# GH#9586
msg = f"'{freq_depr[1:]}' is deprecated and will be removed "
f"in a future version, please use '{freq[1:]}' instead."
def test_to_period_frequency_M_Q_Y_raises(self, freq):
msg = f"Invalid frequency: {freq}"

rng = date_range("01-Jan-2012", periods=8, freq=freq)
prng = rng.to_period()
with tm.assert_produces_warning(FutureWarning, match=msg):
assert prng.freq == freq_depr
rng = date_range("01-Jan-2012", periods=8, freq="ME")
with pytest.raises(ValueError, match=msg):
rng.to_period(freq)

def test_to_period_infer(self):
# https://github.com/pandas-dev/pandas/issues/33358
Expand Down Expand Up @@ -214,10 +204,16 @@ def test_to_period_nofreq(self):
assert idx.freqstr is None
tm.assert_index_equal(idx.to_period(), expected)

@pytest.mark.parametrize("freq", ["2BMS", "1SME-15"])
def test_to_period_offsets_not_supported(self, freq):
@pytest.mark.parametrize(
"freq, msg",
[
("2BME", "Invalid frequency: 2BME"),
("1SME-15", "SME-15 is not supported as period frequency"),
("2BMS", "BMS is not supported as period frequency"),
],
)
def test_to_period_offsets_not_supported(self, freq, msg):
# GH#56243
msg = f"{freq[1:]} is not supported as period frequency"
ts = date_range("1/1/2012", periods=4, freq=freq)
with pytest.raises(ValueError, match=msg):
ts.to_period()
55 changes: 11 additions & 44 deletions pandas/tests/indexes/datetimes/test_date_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,24 +146,12 @@ def test_date_range_fractional_period(self):
exp = date_range("1/1/2000", periods=10)
tm.assert_index_equal(rng, exp)

@pytest.mark.parametrize(
"freq,freq_depr",
[
("2ME", "2M"),
("2SME", "2SM"),
("2BQE", "2BQ"),
("2BYE", "2BY"),
],
)
def test_date_range_frequency_M_SM_BQ_BY_deprecated(self, freq, freq_depr):
# GH#52064
depr_msg = f"'{freq_depr[1:]}' is deprecated and will be removed "
f"in a future version, please use '{freq[1:]}' instead."

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=freq_depr)
tm.assert_index_equal(result, expected)
@pytest.mark.parametrize("freq", ["2M", "1m", "2SM", "2BQ", "1bq", "2BY"])
def test_date_range_frequency_M_SM_BQ_BY_raises(self, freq):
msg = f"Invalid frequency: {freq}"

with pytest.raises(ValueError, match=msg):
date_range("1/1/2000", periods=4, freq=freq)

def test_date_range_tuple_freq_raises(self):
# GH#34703
Expand Down Expand Up @@ -779,34 +767,13 @@ def test_frequency_H_T_S_L_U_N_raises(self, freq):
date_range("1/1/2000", periods=2, freq=freq)

@pytest.mark.parametrize(
"freq,freq_depr",
[
("YE", "Y"),
("YE-MAY", "Y-MAY"),
],
"freq_depr", ["m", "bm", "CBM", "SM", "BQ", "q-feb", "y-may", "Y-MAY"]
)
def test_frequencies_Y_renamed(self, freq, freq_depr):
# GH#9586, GH#54275
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 "
f"in a future version, please use '{freq_msg}' instead."
def test_frequency_raises(self, freq_depr):
msg = f"Invalid frequency: {freq_depr}"

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)

def test_to_offset_with_lowercase_deprecated_freq(self) -> None:
# https://github.com/pandas-dev/pandas/issues/56847
msg = (
"'m' is deprecated and will be removed in a future version, please use "
"'ME' instead."
)
with tm.assert_produces_warning(FutureWarning, match=msg):
result = date_range("2010-01-01", periods=2, freq="m")
expected = DatetimeIndex(["2010-01-31", "2010-02-28"], freq="ME")
tm.assert_index_equal(result, expected)
with pytest.raises(ValueError, match=msg):
date_range("1/1/2000", periods=2, freq=freq_depr)

def test_date_range_bday(self):
sdate = datetime(1999, 12, 25)
Expand Down
Loading
Loading