Skip to content

Commit

Permalink
deprecate is_anchored, fix tests
Browse files Browse the repository at this point in the history
  • Loading branch information
natmokval committed Dec 21, 2023
1 parent 8ce6740 commit 900c44c
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 42 deletions.
129 changes: 90 additions & 39 deletions pandas/_libs/tslibs/offsets.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,12 @@ cdef class BaseOffset:
>>> pd.DateOffset(2).is_anchored()
False
"""
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1

# ------------------------------------------------------------------
Expand Down Expand Up @@ -954,6 +960,12 @@ cdef class Tick(SingleConstructorOffset):
return True

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use False instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return False

# This is identical to BaseOffset.__hash__, but has to be redefined here
Expand Down Expand Up @@ -1766,7 +1778,7 @@ cdef class BusinessDay(BusinessMixin):
s -= hrs * 3600
mts = int(s / 60)
if mts != 0:
off_str += str(mts) + "Min"
off_str += str(mts) + "min"
s -= mts * 60
if s != 0:
off_str += str(s) + "s"
Expand Down Expand Up @@ -2663,6 +2675,13 @@ cdef class QuarterOffset(SingleConstructorOffset):
return f"{self._prefix}-{month}"

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 "
f" and {type(self).__name__}.startingMonth is not None instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1 and self.startingMonth is not None

def is_on_offset(self, dt: datetime) -> bool:
Expand Down Expand Up @@ -3308,6 +3327,13 @@ cdef class Week(SingleConstructorOffset):
self._cache = state.pop("_cache", {})

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 "
f" and {type(self).__name__}.weekday is not None instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return self.n == 1 and self.weekday is not None

@apply_wraps
Expand Down Expand Up @@ -3597,6 +3623,12 @@ cdef class FY5253Mixin(SingleConstructorOffset):
self.variation = state.pop("variation")

def is_anchored(self) -> bool:
warnings.warn(
f"{type(self).__name__}.is_anchored() is deprecated and will be removed "
f"in a future version, please use {type(self).__name__}.n == 1 instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
return (
self.n == 1 and self.startingMonth is not None and self.weekday is not None
)
Expand Down Expand Up @@ -4654,36 +4686,13 @@ _lite_rule_alias = {
"BYE": "BYE-DEC", # BYearEnd(month=12),
"BYS": "BYS-JAN", # BYearBegin(month=1),

"Min": "min",
"min": "min",
"ms": "ms",
"us": "us",
"ns": "ns",
}

_dont_uppercase = {
"h",
"bh",
"cbh",
"MS",
"ms",
"s",
"me",
"qe",
"qe-dec",
"qe-jan",
"qe-feb",
"qe-mar",
"qe-apr",
"qe-may",
"qe-jun",
"qe-jul",
"qe-aug",
"qe-sep",
"qe-oct",
"qe-nov",
"ye",
}
_dont_uppercase = {"h", "bh", "cbh", "MS", "ms", "s"}


INVALID_FREQ_ERR_MSG = "Invalid frequency: {0}"
Expand All @@ -4702,7 +4711,29 @@ def _get_offset(name: str) -> BaseOffset:
--------
_get_offset('EOM') --> BMonthEnd(1)
"""
if name.lower() not in _dont_uppercase:
if (
name not in _lite_rule_alias
and (name.upper() in _lite_rule_alias)
and name != "ms"
):
warnings.warn(
f"\'{name}\' is deprecated and will be removed "
f"in a future version, please use \'{name.upper()}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
elif (
name not in _lite_rule_alias
and (name.lower() in _lite_rule_alias)
and name != "MS"
):
warnings.warn(
f"\'{name}\' is deprecated and will be removed "
f"in a future version, please use \'{name.lower()}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
if name not in _dont_uppercase:
name = name.upper()
name = _lite_rule_alias.get(name, name)
name = _lite_rule_alias.get(name.lower(), name)
Expand Down Expand Up @@ -4795,40 +4826,60 @@ 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 is_period is False and name in c_OFFSET_DEPR_FREQSTR:
if is_period is False 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)}\' instead.",
f"\'{c_OFFSET_DEPR_FREQSTR.get(name.upper())}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
name = c_OFFSET_DEPR_FREQSTR[name]
if is_period is True and name in c_REVERSE_OFFSET_DEPR_FREQSTR:
if name.startswith("Y"):
name = c_OFFSET_DEPR_FREQSTR[name.upper()]
elif (is_period is False and
name != name.upper() and
name.upper() in c_REVERSE_OFFSET_DEPR_FREQSTR):
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 is True and name.upper() in c_REVERSE_OFFSET_DEPR_FREQSTR:
if name.upper().startswith("Y"):
raise ValueError(
f"for Period, please use \'Y{name[2:]}\' "
f"for Period, please use \'Y{name.upper()[2:]}\' "
f"instead of \'{name}\'"
)
if (name.startswith("B") or
name.startswith("S") or name.startswith("C")):
if (name.upper().startswith("B") or
name.upper().startswith("S") or
name.upper().startswith("C")):
raise ValueError(INVALID_FREQ_ERR_MSG.format(name))
else:
raise ValueError(
f"for Period, please use "
f"\'{c_REVERSE_OFFSET_DEPR_FREQSTR.get(name)}\' "
f"\'{c_REVERSE_OFFSET_DEPR_FREQSTR.get(name.upper())}\' "
f"instead of \'{name}\'"
)
elif is_period is True and name in c_OFFSET_DEPR_FREQSTR:
if name.startswith("A"):
elif is_period is True and name.upper() in c_OFFSET_DEPR_FREQSTR:
if name.upper().startswith("A"):
warnings.warn(
f"\'{name}\' is deprecated and will be removed in a future "
f"version, please use \'{c_DEPR_ABBREVS.get(name)}\' "
f"version, please use "
f"\'{c_DEPR_ABBREVS.get(name.upper())}\' instead.",
FutureWarning,
stacklevel=find_stack_level(),
)
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)
name = c_OFFSET_DEPR_FREQSTR.get(name.upper())

if sep != "" and not sep.isspace():
raise ValueError("separator must be spaces")
Expand Down
2 changes: 1 addition & 1 deletion pandas/tests/indexes/interval/test_interval_range.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def test_constructor_timestamp(self, closed, name, freq, periods, tz):
tm.assert_index_equal(result, expected)

# GH 20976: linspace behavior defined from start/end/periods
if not breaks.freq.is_anchored() and tz is None:
if not breaks.freq.n == 1 and tz is None:
# matches expected only for non-anchored offsets and tz naive
# (anchored/DST transitions cause unequal spacing in expected)
result = interval_range(
Expand Down
7 changes: 5 additions & 2 deletions pandas/tests/tseries/offsets/test_offsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,11 @@ def test_default_constructor(self, dt):
assert (dt + DateOffset(2)) == datetime(2008, 1, 4)

def test_is_anchored(self):
assert not DateOffset(2).is_anchored()
assert DateOffset(1).is_anchored()
msg = "DateOffset.is_anchored() is deprecated"

with tm.assert_produces_warning(FutureWarning, match=msg):
DateOffset(2).is_anchored()
DateOffset(1).is_anchored()

def test_copy(self):
assert DateOffset(months=2).copy() == DateOffset(months=2)
Expand Down

0 comments on commit 900c44c

Please sign in to comment.