@@ -18,6 +18,8 @@ cimport numpy as cnp
18
18
from numpy cimport int64_t
19
19
cnp.import_array()
20
20
21
+ # TODO: formalize having _libs.properties "above" tslibs in the dependency structure
22
+ from pandas._libs.properties import cache_readonly
21
23
22
24
from pandas._libs.tslibs cimport util
23
25
from pandas._libs.tslibs.util cimport is_integer_object, is_datetime64_object
@@ -447,7 +449,7 @@ cdef class BaseOffset:
447
449
def __hash__ (self ):
448
450
return hash (self ._params)
449
451
450
- @property
452
+ @cache_readonly
451
453
def _params (self ):
452
454
"""
453
455
Returns a tuple containing all of the attributes needed to evaluate
@@ -583,7 +585,7 @@ cdef class BaseOffset:
583
585
def rule_code(self ) -> str:
584
586
return self._prefix
585
587
586
- @property
588
+ @cache_readonly
587
589
def freqstr(self ) -> str:
588
590
try:
589
591
code = self .rule_code
@@ -778,7 +780,19 @@ cdef class BaseOffset:
778
780
return self.n == 1
779
781
780
782
781
- cdef class Tick(BaseOffset ):
783
+ cdef class SingleConstructorOffset(BaseOffset ):
784
+ @classmethod
785
+ def _from_name (cls , suffix = None ):
786
+ # default _from_name calls cls with no args
787
+ if suffix:
788
+ raise ValueError (f" Bad freq suffix {suffix}" )
789
+ return cls ()
790
+
791
+
792
+ # ---------------------------------------------------------------------
793
+ # Tick Offsets
794
+
795
+ cdef class Tick(SingleConstructorOffset):
782
796
# ensure that reversed-ops with numpy scalars return NotImplemented
783
797
__array_priority__ = 1000
784
798
_adjust_dst = False
@@ -796,13 +810,6 @@ cdef class Tick(BaseOffset):
796
810
" Tick offset with `normalize=True` are not allowed."
797
811
)
798
812
799
- @classmethod
800
- def _from_name (cls , suffix = None ):
801
- # default _from_name calls cls with no args
802
- if suffix:
803
- raise ValueError (f" Bad freq suffix {suffix}" )
804
- return cls ()
805
-
806
813
def _repr_attrs (self ) -> str:
807
814
# Since cdef classes have no __dict__ , we need to override
808
815
return ""
@@ -981,7 +988,7 @@ def delta_to_tick(delta: timedelta) -> Tick:
981
988
# --------------------------------------------------------------------
982
989
983
990
984
- class BusinessMixin(BaseOffset ):
991
+ class BusinessMixin(SingleConstructorOffset ):
985
992
"""
986
993
Mixin to business types to provide related functions.
987
994
"""
@@ -1060,13 +1067,6 @@ class BusinessHourMixin(BusinessMixin):
1060
1067
object .__setattr__ (self , " start" , start)
1061
1068
object .__setattr__ (self , " end" , end)
1062
1069
1063
- @classmethod
1064
- def _from_name (cls , suffix = None ):
1065
- # default _from_name calls cls with no args
1066
- if suffix:
1067
- raise ValueError (f" Bad freq suffix {suffix}" )
1068
- return cls ()
1069
-
1070
1070
def _repr_attrs (self ) -> str:
1071
1071
out = super ()._repr_attrs()
1072
1072
hours = " ," .join(
@@ -1128,7 +1128,7 @@ class CustomMixin:
1128
1128
object .__setattr__ (self , " calendar" , calendar)
1129
1129
1130
1130
1131
- class WeekOfMonthMixin (BaseOffset ):
1131
+ class WeekOfMonthMixin (SingleConstructorOffset ):
1132
1132
"""
1133
1133
Mixin for methods common to WeekOfMonth and LastWeekOfMonth.
1134
1134
"""
@@ -1169,7 +1169,7 @@ class WeekOfMonthMixin(BaseOffset):
1169
1169
1170
1170
# ----------------------------------------------------------------------
1171
1171
1172
- cdef class YearOffset(BaseOffset ):
1172
+ cdef class YearOffset(SingleConstructorOffset ):
1173
1173
"""
1174
1174
DateOffset that just needs a month.
1175
1175
"""
@@ -1230,7 +1230,7 @@ cdef class YearOffset(BaseOffset):
1230
1230
return type (dtindex)._simple_new(shifted, dtype = dtindex.dtype)
1231
1231
1232
1232
1233
- cdef class QuarterOffset(BaseOffset ):
1233
+ cdef class QuarterOffset(SingleConstructorOffset ):
1234
1234
_attributes = frozenset ([" n" , " normalize" , " startingMonth" ])
1235
1235
# TODO: Consider combining QuarterOffset and YearOffset __init__ at some
1236
1236
# point. Also apply_index, is_on_offset, rule_code if
0 commit comments