Skip to content

Commit 43ad6a8

Browse files
TomAugspurgerPingviinituutti
authored andcommitted
REF: Refactor Datetimelike delegation (pandas-dev#24039)
1 parent 794f587 commit 43ad6a8

File tree

2 files changed

+62
-41
lines changed

2 files changed

+62
-41
lines changed

pandas/core/indexes/datetimelike.py

+47
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"""
33
Base and utility classes for tseries type pandas objects.
44
"""
5+
import operator
56
import warnings
67

78
import numpy as np
@@ -19,6 +20,7 @@
1920
from pandas.core.dtypes.generic import ABCIndex, ABCIndexClass, ABCSeries
2021

2122
from pandas.core import algorithms, ops
23+
from pandas.core.accessor import PandasDelegate
2224
from pandas.core.arrays.datetimelike import (
2325
DatetimeLikeArrayMixin, _ensure_datetimelike_to_i8)
2426
import pandas.core.indexes.base as ibase
@@ -643,3 +645,48 @@ def f(self):
643645
f.__name__ = fget.__name__
644646
f.__doc__ = fget.__doc__
645647
return property(f)
648+
649+
650+
class DatetimelikeDelegateMixin(PandasDelegate):
651+
"""
652+
Delegation mechanism, specific for Datetime, Timedelta, and Period types.
653+
654+
Functionality is delegated from the Index class to an Array class. A
655+
few things can be customized
656+
657+
* _delegate_class : type
658+
The class being delegated to.
659+
* _delegated_methods, delegated_properties : List
660+
The list of property / method names being delagated.
661+
* raw_methods : Set
662+
The set of methods whose results should should *not* be
663+
boxed in an index, after being returned from the array
664+
* raw_properties : Set
665+
The set of properties whose results should should *not* be
666+
boxed in an index, after being returned from the array
667+
"""
668+
# raw_methods : dispatch methods that shouldn't be boxed in an Index
669+
_raw_methods = set()
670+
# raw_properties : dispatch properties that shouldn't be boxed in an Index
671+
_raw_properties = set()
672+
name = None
673+
_data = None
674+
675+
@property
676+
def _delegate_class(self):
677+
raise AbstractMethodError
678+
679+
def _delegate_property_get(self, name, *args, **kwargs):
680+
result = getattr(self._data, name)
681+
if name not in self._raw_properties:
682+
result = Index(result, name=self.name)
683+
return result
684+
685+
def _delegate_property_set(self, name, value, *args, **kwargs):
686+
setattr(self._data, name, value)
687+
688+
def _delegate_method(self, name, *args, **kwargs):
689+
result = operator.methodcaller(name, *args, **kwargs)(self._data)
690+
if name not in self._raw_methods:
691+
result = Index(result, name=self.name)
692+
return result

pandas/core/indexes/period.py

+15-41
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# pylint: disable=E1101,E1103,W0232
22
from datetime import datetime, timedelta
3-
import operator
43
import warnings
54

65
import numpy as np
@@ -18,15 +17,16 @@
1817

1918
from pandas import compat
2019
from pandas.core import common as com
21-
from pandas.core.accessor import PandasDelegate, delegate_names
20+
from pandas.core.accessor import delegate_names
2221
from pandas.core.algorithms import unique1d
2322
import pandas.core.arrays.datetimelike as dtl
23+
from pandas.core.arrays.datetimelike import DatelikeOps
2424
from pandas.core.arrays.period import PeriodArray, period_array
2525
from pandas.core.base import _shared_docs
2626
import pandas.core.indexes.base as ibase
2727
from pandas.core.indexes.base import _index_shared_docs, ensure_index
2828
from pandas.core.indexes.datetimelike import (
29-
DatetimeIndexOpsMixin, wrap_arithmetic_op)
29+
DatetimeIndexOpsMixin, DatetimelikeDelegateMixin, wrap_arithmetic_op)
3030
from pandas.core.indexes.datetimes import DatetimeIndex, Index, Int64Index
3131
from pandas.core.missing import isna
3232
from pandas.core.ops import get_op_result_name
@@ -54,37 +54,26 @@ def _new_PeriodIndex(cls, **d):
5454
return cls(values, **d)
5555

5656

57-
class PeriodDelegateMixin(PandasDelegate):
57+
class PeriodDelegateMixin(DatetimelikeDelegateMixin):
5858
"""
5959
Delegate from PeriodIndex to PeriodArray.
6060
"""
61-
def _delegate_property_get(self, name, *args, **kwargs):
62-
result = getattr(self._data, name)
63-
box_ops = (
64-
set(PeriodArray._datetimelike_ops) - set(PeriodArray._bool_ops)
65-
)
66-
if name in box_ops:
67-
result = Index(result, name=self.name)
68-
return result
69-
70-
def _delegate_property_set(self, name, value, *args, **kwargs):
71-
setattr(self._data, name, value)
72-
73-
def _delegate_method(self, name, *args, **kwargs):
74-
result = operator.methodcaller(name, *args, **kwargs)(self._data)
75-
return Index(result, name=self.name)
61+
_delegate_class = PeriodArray
62+
_delegated_properties = PeriodArray._datetimelike_ops
63+
_delegated_methods = (
64+
set(PeriodArray._datetimelike_methods) | {'_addsub_int_array'}
65+
)
66+
_raw_properties = {'is_leap_year'}
7667

7768

7869
@delegate_names(PeriodArray,
79-
PeriodArray._datetimelike_ops + ['size', 'asi8', 'shape'],
70+
PeriodDelegateMixin._delegated_properties,
8071
typ='property')
8172
@delegate_names(PeriodArray,
82-
[x for x in PeriodArray._datetimelike_methods
83-
if x not in {"asfreq", "to_timestamp"}],
84-
typ="method",
85-
overwrite=True)
86-
class PeriodIndex(DatetimeIndexOpsMixin,
87-
Int64Index, PeriodDelegateMixin):
73+
PeriodDelegateMixin._delegated_methods,
74+
typ="method")
75+
class PeriodIndex(DatelikeOps, DatetimeIndexOpsMixin, Int64Index,
76+
PeriodDelegateMixin):
8877
"""
8978
Immutable ndarray holding ordinal values indicating regular periods in
9079
time such as particular years, quarters, months, etc.
@@ -349,21 +338,6 @@ def _maybe_box_as_values(self, values, **attribs):
349338
freq = attribs['freq']
350339
return PeriodArray(values, freq=freq)
351340

352-
# ------------------------------------------------------------------------
353-
# Dispatch and maybe box. Not done in delegate_names because we box
354-
# different from those (which use Index).
355-
356-
def asfreq(self, freq=None, how='E'):
357-
result = self._data.asfreq(freq=freq, how=how)
358-
return self._simple_new(result, name=self.name)
359-
360-
def to_timestamp(self, freq=None, how='start'):
361-
from pandas import DatetimeIndex
362-
result = self._data.to_timestamp(freq=freq, how=how)
363-
return DatetimeIndex._simple_new(result.asi8,
364-
name=self.name,
365-
freq=result.freq)
366-
367341
def _maybe_convert_timedelta(self, other):
368342
"""
369343
Convert timedelta-like input to an integer multiple of self.freq

0 commit comments

Comments
 (0)