diff --git a/pandas/_libs/tslibs/offsets.pyx b/pandas/_libs/tslibs/offsets.pyx index be3f11ea4da1f..1b319e12f06d5 100644 --- a/pandas/_libs/tslibs/offsets.pyx +++ b/pandas/_libs/tslibs/offsets.pyx @@ -368,12 +368,31 @@ class _BaseOffset(object): if name not in ['n', 'normalize']} return {name: kwds[name] for name in kwds if kwds[name] is not None} + def __add__(self, other): + if getattr(other, "_typ", None) in ["datetimeindex", + "series", "period"]: + # defer to the other class's implementation + return other + self + try: + return self.apply(other) + except ApplyTypeError: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, datetime): + raise TypeError('Cannot subtract datetime from offset.') + elif type(other) == type(self): + return type(self)(self.n - other.n, normalize=self.normalize, + **self.kwds) + else: # pragma: no cover + return NotImplemented + def __call__(self, other): return self.apply(other) def __mul__(self, other): - return self.__class__(n=other * self.n, normalize=self.normalize, - **self.kwds) + return type(self)(n=other * self.n, normalize=self.normalize, + **self.kwds) def __neg__(self): # Note: we are defering directly to __mul__ instead of __rmul__, as @@ -495,6 +514,14 @@ class BaseOffset(_BaseOffset): return -self + other +class _Tick(object): + """ + dummy class to mix into tseries.offsets.Tick so that in tslibs.period we + can do isinstance checks on _Tick and avoid importing tseries.offsets + """ + pass + + # ---------------------------------------------------------------------- # RelativeDelta Arithmetic diff --git a/pandas/_libs/tslibs/period.pyx b/pandas/_libs/tslibs/period.pyx index 6e5794ef41757..3a29f9fb00865 100644 --- a/pandas/_libs/tslibs/period.pyx +++ b/pandas/_libs/tslibs/period.pyx @@ -52,8 +52,7 @@ from resolution import Resolution from nattype import nat_strings, NaT, iNaT from nattype cimport _nat_scalar_rules, NPY_NAT, is_null_datetimelike from offsets cimport to_offset - -from pandas.tseries import offsets +from offsets import _Tick cdef bint PY2 = str == bytes @@ -1060,9 +1059,9 @@ cdef class _Period(object): int64_t nanos, offset_nanos if (PyDelta_Check(other) or util.is_timedelta64_object(other) or - isinstance(other, offsets.Tick)): + isinstance(other, _Tick)): offset = to_offset(self.freq.rule_code) - if isinstance(offset, offsets.Tick): + if isinstance(offset, _Tick): nanos = delta_to_nanoseconds(other) offset_nanos = delta_to_nanoseconds(offset) if nanos % offset_nanos == 0: diff --git a/pandas/tseries/offsets.py b/pandas/tseries/offsets.py index f9c9ec09844d6..d78d199f1404b 100644 --- a/pandas/tseries/offsets.py +++ b/pandas/tseries/offsets.py @@ -7,7 +7,7 @@ from pandas import compat import numpy as np -from pandas.core.dtypes.generic import ABCSeries, ABCDatetimeIndex, ABCPeriod +from pandas.core.dtypes.generic import ABCPeriod from pandas.core.tools.datetimes import to_datetime import pandas.core.common as com @@ -288,25 +288,6 @@ def _repr_attrs(self): def name(self): return self.rule_code - def __add__(self, other): - if isinstance(other, (ABCDatetimeIndex, ABCSeries)): - return other + self - elif isinstance(other, ABCPeriod): - return other + self - try: - return self.apply(other) - except ApplyTypeError: - return NotImplemented - - def __sub__(self, other): - if isinstance(other, datetime): - raise TypeError('Cannot subtract datetime from offset.') - elif type(other) == type(self): - return self.__class__(self.n - other.n, normalize=self.normalize, - **self.kwds) - else: # pragma: no cover - return NotImplemented - def rollback(self, dt): """Roll provided date backward to next offset only if not on offset""" dt = as_timestamp(dt) @@ -2106,7 +2087,7 @@ def f(self, other): return f -class Tick(SingleConstructorOffset): +class Tick(liboffsets._Tick, SingleConstructorOffset): _inc = Timedelta(microseconds=1000) _prefix = 'undefined' _attributes = frozenset(['n', 'normalize'])