Skip to content

TYP: offsets #30897

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

Merged
merged 7 commits into from
Jan 10, 2020
Merged
Changes from all commits
Commits
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
90 changes: 45 additions & 45 deletions pandas/tseries/offsets.py
Original file line number Diff line number Diff line change
@@ -365,7 +365,7 @@ def apply_index(self, i):
"applied vectorized"
)

def is_anchored(self):
def is_anchored(self) -> bool:
# TODO: Does this make sense for the general case? It would help
# if there were a canonical docstring for what is_anchored means.
return self.n == 1
@@ -378,7 +378,7 @@ def onOffset(self, dt):
)
return self.is_on_offset(dt)

def isAnchored(self):
def isAnchored(self) -> bool:
warnings.warn(
"isAnchored is a deprecated, use is_anchored instead",
FutureWarning,
@@ -389,7 +389,7 @@ def isAnchored(self):
# TODO: Combine this with BusinessMixin version by defining a whitelisted
# set of attributes on each object rather than the existing behavior of
# iterating over internal ``__dict__``
def _repr_attrs(self):
def _repr_attrs(self) -> str:
exclude = {"n", "inc", "normalize"}
attrs = []
for attr in sorted(self.__dict__):
@@ -405,7 +405,7 @@ def _repr_attrs(self):
return out

@property
def name(self):
def name(self) -> str:
return self.rule_code

def rollback(self, dt):
@@ -452,15 +452,15 @@ def is_on_offset(self, dt):

# way to get around weirdness with rule_code
@property
def _prefix(self):
def _prefix(self) -> str:
raise NotImplementedError("Prefix not defined")

@property
def rule_code(self):
def rule_code(self) -> str:
return self._prefix

@cache_readonly
def freqstr(self):
def freqstr(self) -> str:
try:
code = self.rule_code
except NotImplementedError:
@@ -480,7 +480,7 @@ def freqstr(self):

return fstr

def _offset_str(self):
def _offset_str(self) -> str:
return ""

@property
@@ -529,11 +529,11 @@ def offset(self):
# Alias for backward compat
return self._offset

def _repr_attrs(self):
def _repr_attrs(self) -> str:
if self.offset:
attrs = [f"offset={repr(self.offset)}"]
else:
attrs = None
attrs = []
out = ""
if attrs:
out += ": " + ", ".join(attrs)
@@ -553,7 +553,7 @@ def __init__(self, n=1, normalize=False, offset=timedelta(0)):
BaseOffset.__init__(self, n, normalize)
object.__setattr__(self, "_offset", offset)

def _offset_str(self):
def _offset_str(self) -> str:
def get_str(td):
off_str = ""
if td.days > 0:
@@ -649,7 +649,7 @@ def apply_index(self, i):
result = shifted.to_timestamp() + time
return result

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
return dt.weekday() < 5
@@ -1087,7 +1087,7 @@ def apply(self, other):
def apply_index(self, i):
raise NotImplementedError

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
day64 = _to_dt64(dt, "datetime64[D]")
@@ -1134,14 +1134,14 @@ class MonthOffset(SingleConstructorOffset):
__init__ = BaseOffset.__init__

@property
def name(self):
def name(self) -> str:
if self.is_anchored:
return self.rule_code
else:
month = ccalendar.MONTH_ALIASES[self.n]
return f"{self.code_rule}-{month}"

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
return dt.day == self._get_offset_day(dt)
@@ -1333,7 +1333,7 @@ def _from_name(cls, suffix=None):
return cls(day_of_month=suffix)

@property
def rule_code(self):
def rule_code(self) -> str:
suffix = f"-{self.day_of_month}"
return self._prefix + suffix

@@ -1429,7 +1429,7 @@ class SemiMonthEnd(SemiMonthOffset):
_prefix = "SM"
_min_day_of_month = 1

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
days_in_month = ccalendar.get_days_in_month(dt.year, dt.month)
@@ -1487,7 +1487,7 @@ class SemiMonthBegin(SemiMonthOffset):

_prefix = "SMS"

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
return dt.day in (1, self.day_of_month)
@@ -1556,7 +1556,7 @@ def __init__(self, n=1, normalize=False, weekday=None):
if self.weekday < 0 or self.weekday > 6:
raise ValueError(f"Day must be 0<=day<=6, got {self.weekday}")

def is_anchored(self):
def is_anchored(self) -> bool:
return self.n == 1 and self.weekday is not None

@apply_wraps
@@ -1632,15 +1632,15 @@ def _end_apply_index(self, dtindex):

return base + off + Timedelta(1, "ns") - Timedelta(1, "D")

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
elif self.weekday is None:
return True
return dt.weekday() == self.weekday

@property
def rule_code(self):
def rule_code(self) -> str:
suffix = ""
if self.weekday is not None:
weekday = ccalendar.int_to_weekday[self.weekday]
@@ -1717,7 +1717,7 @@ def __init__(self, n=1, normalize=False, week=0, weekday=0):
if self.week < 0 or self.week > 3:
raise ValueError(f"Week must be 0<=week<=3, got {self.week}")

def _get_offset_day(self, other):
def _get_offset_day(self, other: datetime) -> int:
"""
Find the day in the same month as other that has the same
weekday as self.weekday and is the self.week'th such day in the month.
@@ -1736,7 +1736,7 @@ def _get_offset_day(self, other):
return 1 + shift_days + self.week * 7

@property
def rule_code(self):
def rule_code(self) -> str:
weekday = ccalendar.int_to_weekday.get(self.weekday, "")
return f"{self._prefix}-{self.week + 1}{weekday}"

@@ -1785,7 +1785,7 @@ def __init__(self, n=1, normalize=False, weekday=0):
if self.weekday < 0 or self.weekday > 6:
raise ValueError(f"Day must be 0<=day<=6, got {self.weekday}")

def _get_offset_day(self, other):
def _get_offset_day(self, other: datetime) -> int:
"""
Find the day in the same month as other that has the same
weekday as self.weekday and is the last such day in the month.
@@ -1805,7 +1805,7 @@ def _get_offset_day(self, other):
return dim - shift_days

@property
def rule_code(self):
def rule_code(self) -> str:
weekday = ccalendar.int_to_weekday.get(self.weekday, "")
return f"{self._prefix}-{weekday}"

@@ -1842,7 +1842,7 @@ def __init__(self, n=1, normalize=False, startingMonth=None):
startingMonth = self._default_startingMonth
object.__setattr__(self, "startingMonth", startingMonth)

def is_anchored(self):
def is_anchored(self) -> bool:
return self.n == 1 and self.startingMonth is not None

@classmethod
@@ -1856,7 +1856,7 @@ def _from_name(cls, suffix=None):
return cls(**kwargs)

@property
def rule_code(self):
def rule_code(self) -> str:
month = ccalendar.MONTH_ALIASES[self.startingMonth]
return f"{self._prefix}-{month}"

@@ -1874,7 +1874,7 @@ def apply(self, other):
months = qtrs * 3 - months_since
return shift_month(other, months, self._day_opt)

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
mod_month = (dt.month - self.startingMonth) % 3
@@ -1953,7 +1953,7 @@ class YearOffset(DateOffset):
_adjust_dst = True
_attributes = frozenset(["n", "normalize", "month"])

def _get_offset_day(self, other):
def _get_offset_day(self, other: datetime) -> int:
# override BaseOffset method to use self.month instead of other.month
# TODO: there may be a more performant way to do this
return liboffsets.get_day_of_month(
@@ -1977,7 +1977,7 @@ def apply_index(self, dtindex):
shifted, freq=dtindex.freq, dtype=dtindex.dtype
)

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
return dt.month == self.month and dt.day == self._get_offset_day(dt)
@@ -1999,7 +1999,7 @@ def _from_name(cls, suffix=None):
return cls(**kwargs)

@property
def rule_code(self):
def rule_code(self) -> str:
month = ccalendar.MONTH_ALIASES[self.month]
return f"{self._prefix}-{month}"

@@ -2117,12 +2117,12 @@ def __init__(
if self.variation not in ["nearest", "last"]:
raise ValueError(f"{self.variation} is not a valid variation")

def is_anchored(self):
def is_anchored(self) -> bool:
return (
self.n == 1 and self.startingMonth is not None and self.weekday is not None
)

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
dt = datetime(dt.year, dt.month, dt.day)
@@ -2217,18 +2217,18 @@ def get_year_end(self, dt):
return target_date + timedelta(days_forward - 7)

@property
def rule_code(self):
def rule_code(self) -> str:
prefix = self._prefix
suffix = self.get_rule_code_suffix()
return f"{prefix}-{suffix}"

def _get_suffix_prefix(self):
def _get_suffix_prefix(self) -> str:
if self.variation == "nearest":
return "N"
else:
return "L"

def get_rule_code_suffix(self):
def get_rule_code_suffix(self) -> str:
prefix = self._get_suffix_prefix()
month = ccalendar.MONTH_ALIASES[self.startingMonth]
weekday = ccalendar.int_to_weekday[self.weekday]
@@ -2346,7 +2346,7 @@ def _offset(self):
variation=self.variation,
)

def is_anchored(self):
def is_anchored(self) -> bool:
return self.n == 1 and self._offset.is_anchored()

def _rollback_to_year(self, other):
@@ -2434,7 +2434,7 @@ def get_weeks(self, dt):

return ret

def year_has_extra_week(self, dt):
def year_has_extra_week(self, dt: datetime) -> bool:
# Avoid round-down errors --> normalize to get
# e.g. '370D' instead of '360D23H'
norm = Timestamp(dt).normalize().tz_localize(None)
@@ -2445,7 +2445,7 @@ def year_has_extra_week(self, dt):
assert weeks_in_year in [52, 53], weeks_in_year
return weeks_in_year == 53

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
if self._offset.is_on_offset(dt):
@@ -2463,7 +2463,7 @@ def is_on_offset(self, dt):
return False

@property
def rule_code(self):
def rule_code(self) -> str:
suffix = self._offset.get_rule_code_suffix()
qtr = self.qtr_with_extra_week
return f"{self._prefix}-{suffix}-{qtr}"
@@ -2516,7 +2516,7 @@ def apply(self, other):
)
return new

def is_on_offset(self, dt):
def is_on_offset(self, dt: datetime) -> bool:
if self.normalize and not _is_normalized(dt):
return False
return date(dt.year, dt.month, dt.day) == easter(dt.year)
@@ -2596,7 +2596,7 @@ def __eq__(self, other: Any) -> bool:

# This is identical to DateOffset.__hash__, but has to be redefined here
# for Python 3, because we've redefined __eq__.
def __hash__(self):
def __hash__(self) -> int:
return hash(self._params)

def __ne__(self, other):
@@ -2617,7 +2617,7 @@ def __ne__(self, other):
return True

@property
def delta(self):
def delta(self) -> Timedelta:
return self.n * self._inc

@property
@@ -2648,11 +2648,11 @@ def apply(self, other):

raise ApplyTypeError(f"Unhandled type: {type(other).__name__}")

def is_anchored(self):
def is_anchored(self) -> bool:
return False


def _delta_to_tick(delta):
def _delta_to_tick(delta: timedelta) -> Tick:
if delta.microseconds == 0 and getattr(delta, "nanoseconds", 0) == 0:
# nanoseconds only for pd.Timedelta
if delta.seconds == 0: