Skip to content

Commit

Permalink
Implement delegate_names to allow decorating delegated attributes (#2…
Browse files Browse the repository at this point in the history
  • Loading branch information
jbrockmendel authored and jreback committed Sep 8, 2018
1 parent 17cd73f commit aeb9299
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 57 deletions.
32 changes: 32 additions & 0 deletions pandas/core/accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,38 @@ def f(self, *args, **kwargs):
setattr(cls, name, f)


def delegate_names(delegate, accessors, typ, overwrite=False):
"""
Add delegated names to a class using a class decorator. This provides
an alternative usage to directly calling `_add_delegate_accessors`
below a class definition.
Parameters
----------
delegate : the class to get methods/properties & doc-strings
acccessors : string list of accessors to add
typ : 'property' or 'method'
overwrite : boolean, default False
overwrite the method/property in the target class if it exists
Returns
-------
decorator
Examples
--------
@delegate_names(Categorical, ["categories", "ordered"], "property")
class CategoricalAccessor(PandasDelegate):
[...]
"""
def add_delegate_accessors(cls):
cls._add_delegate_accessors(delegate, accessors, typ,
overwrite=overwrite)
return cls

return add_delegate_accessors


# Ported with modifications from xarray
# https://github.com/pydata/xarray/blob/master/xarray/core/extensions.py
# 1. We don't need to catch and re-raise AttributeErrors as RuntimeErrors
Expand Down
20 changes: 10 additions & 10 deletions pandas/core/arrays/categorical.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
is_dict_like)

from pandas.core.algorithms import factorize, take_1d, unique1d, take
from pandas.core.accessor import PandasDelegate
from pandas.core.accessor import PandasDelegate, delegate_names
from pandas.core.base import (PandasObject,
NoNewAttributesMixin, _shared_docs)
import pandas.core.common as com
Expand Down Expand Up @@ -2365,6 +2365,15 @@ def isin(self, values):
# The Series.cat accessor


@delegate_names(delegate=Categorical,
accessors=["categories", "ordered"],
typ="property")
@delegate_names(delegate=Categorical,
accessors=["rename_categories", "reorder_categories",
"add_categories", "remove_categories",
"remove_unused_categories", "set_categories",
"as_ordered", "as_unordered"],
typ="method")
class CategoricalAccessor(PandasDelegate, PandasObject, NoNewAttributesMixin):
"""
Accessor object for categorical properties of the Series values.
Expand Down Expand Up @@ -2424,15 +2433,6 @@ def _delegate_method(self, name, *args, **kwargs):
return Series(res, index=self.index, name=self.name)


CategoricalAccessor._add_delegate_accessors(delegate=Categorical,
accessors=["categories",
"ordered"],
typ='property')
CategoricalAccessor._add_delegate_accessors(delegate=Categorical, accessors=[
"rename_categories", "reorder_categories", "add_categories",
"remove_categories", "remove_unused_categories", "set_categories",
"as_ordered", "as_unordered"], typ='method')

# utility routines


Expand Down
50 changes: 19 additions & 31 deletions pandas/core/indexes/accessors.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
is_timedelta64_dtype, is_categorical_dtype,
is_list_like)

from pandas.core.accessor import PandasDelegate
from pandas.core.accessor import PandasDelegate, delegate_names
from pandas.core.base import NoNewAttributesMixin, PandasObject
from pandas.core.indexes.datetimes import DatetimeIndex
from pandas.core.indexes.period import PeriodIndex
Expand Down Expand Up @@ -110,6 +110,12 @@ def _delegate_method(self, name, *args, **kwargs):
return result


@delegate_names(delegate=DatetimeIndex,
accessors=DatetimeIndex._datetimelike_ops,
typ="property")
@delegate_names(delegate=DatetimeIndex,
accessors=DatetimeIndex._datetimelike_methods,
typ="method")
class DatetimeProperties(Properties):
"""
Accessor object for datetimelike properties of the Series values.
Expand Down Expand Up @@ -175,16 +181,12 @@ def freq(self):
return self._get_values().inferred_freq


DatetimeProperties._add_delegate_accessors(
delegate=DatetimeIndex,
accessors=DatetimeIndex._datetimelike_ops,
typ='property')
DatetimeProperties._add_delegate_accessors(
delegate=DatetimeIndex,
accessors=DatetimeIndex._datetimelike_methods,
typ='method')


@delegate_names(delegate=TimedeltaIndex,
accessors=TimedeltaIndex._datetimelike_ops,
typ="property")
@delegate_names(delegate=TimedeltaIndex,
accessors=TimedeltaIndex._datetimelike_methods,
typ="method")
class TimedeltaProperties(Properties):
"""
Accessor object for datetimelike properties of the Series values.
Expand Down Expand Up @@ -268,16 +270,12 @@ def freq(self):
return self._get_values().inferred_freq


TimedeltaProperties._add_delegate_accessors(
delegate=TimedeltaIndex,
accessors=TimedeltaIndex._datetimelike_ops,
typ='property')
TimedeltaProperties._add_delegate_accessors(
delegate=TimedeltaIndex,
accessors=TimedeltaIndex._datetimelike_methods,
typ='method')


@delegate_names(delegate=PeriodIndex,
accessors=PeriodIndex._datetimelike_ops,
typ="property")
@delegate_names(delegate=PeriodIndex,
accessors=PeriodIndex._datetimelike_methods,
typ="method")
class PeriodProperties(Properties):
"""
Accessor object for datetimelike properties of the Series values.
Expand All @@ -293,16 +291,6 @@ class PeriodProperties(Properties):
"""


PeriodProperties._add_delegate_accessors(
delegate=PeriodIndex,
accessors=PeriodIndex._datetimelike_ops,
typ='property')
PeriodProperties._add_delegate_accessors(
delegate=PeriodIndex,
accessors=PeriodIndex._datetimelike_methods,
typ='method')


class CombinedDatetimelikeProperties(DatetimeProperties, TimedeltaProperties):

def __new__(cls, data):
Expand Down
27 changes: 11 additions & 16 deletions pandas/core/indexes/category.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,17 @@
_index_doc_kwargs.update(dict(target_klass='CategoricalIndex'))


@accessor.delegate_names(
delegate=Categorical,
accessors=["rename_categories",
"reorder_categories",
"add_categories",
"remove_categories",
"remove_unused_categories",
"set_categories",
"as_ordered", "as_unordered",
"min", "max"],
typ='method', overwrite=True)
class CategoricalIndex(Index, accessor.PandasDelegate):
"""
Expand Down Expand Up @@ -835,24 +846,8 @@ def _delegate_method(self, name, *args, **kwargs):
return res
return CategoricalIndex(res, name=self.name)

@classmethod
def _add_accessors(cls):
""" add in Categorical accessor methods """

CategoricalIndex._add_delegate_accessors(
delegate=Categorical, accessors=["rename_categories",
"reorder_categories",
"add_categories",
"remove_categories",
"remove_unused_categories",
"set_categories",
"as_ordered", "as_unordered",
"min", "max"],
typ='method', overwrite=True)


CategoricalIndex._add_numeric_methods_add_sub_disabled()
CategoricalIndex._add_numeric_methods_disabled()
CategoricalIndex._add_logical_methods_disabled()
CategoricalIndex._add_comparison_methods()
CategoricalIndex._add_accessors()

0 comments on commit aeb9299

Please sign in to comment.