Skip to content

Commit e74d452

Browse files
jbrockmendelNo-Stream
authored andcommitted
cut/paste AccessorProperty and PandasDelegate to core.accessor (pandas-dev#17651)
1 parent 4a48ad9 commit e74d452

File tree

9 files changed

+117
-110
lines changed

9 files changed

+117
-110
lines changed

pandas/core/accessor.py

+95
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
that can be mixed into or pinned onto other pandas classes.
66
77
"""
8+
from pandas.core.common import AbstractMethodError
89

910

1011
class DirNamesMixin(object):
@@ -33,3 +34,97 @@ def __dir__(self):
3334
rv = set(dir(type(self)))
3435
rv = (rv - self._dir_deletions()) | self._dir_additions()
3536
return sorted(rv)
37+
38+
39+
class AccessorProperty(object):
40+
"""Descriptor for implementing accessor properties like Series.str
41+
"""
42+
43+
def __init__(self, accessor_cls, construct_accessor=None):
44+
self.accessor_cls = accessor_cls
45+
self.construct_accessor = (construct_accessor or
46+
accessor_cls._make_accessor)
47+
self.__doc__ = accessor_cls.__doc__
48+
49+
def __get__(self, instance, owner=None):
50+
if instance is None:
51+
# this ensures that Series.str.<method> is well defined
52+
return self.accessor_cls
53+
return self.construct_accessor(instance)
54+
55+
def __set__(self, instance, value):
56+
raise AttributeError("can't set attribute")
57+
58+
def __delete__(self, instance):
59+
raise AttributeError("can't delete attribute")
60+
61+
62+
class PandasDelegate(object):
63+
""" an abstract base class for delegating methods/properties """
64+
65+
@classmethod
66+
def _make_accessor(cls, data):
67+
raise AbstractMethodError("_make_accessor should be implemented"
68+
"by subclass and return an instance"
69+
"of `cls`.")
70+
71+
def _delegate_property_get(self, name, *args, **kwargs):
72+
raise TypeError("You cannot access the "
73+
"property {name}".format(name=name))
74+
75+
def _delegate_property_set(self, name, value, *args, **kwargs):
76+
raise TypeError("The property {name} cannot be set".format(name=name))
77+
78+
def _delegate_method(self, name, *args, **kwargs):
79+
raise TypeError("You cannot call method {name}".format(name=name))
80+
81+
@classmethod
82+
def _add_delegate_accessors(cls, delegate, accessors, typ,
83+
overwrite=False):
84+
"""
85+
add accessors to cls from the delegate class
86+
87+
Parameters
88+
----------
89+
cls : the class to add the methods/properties to
90+
delegate : the class to get methods/properties & doc-strings
91+
acccessors : string list of accessors to add
92+
typ : 'property' or 'method'
93+
overwrite : boolean, default False
94+
overwrite the method/property in the target class if it exists
95+
"""
96+
97+
def _create_delegator_property(name):
98+
99+
def _getter(self):
100+
return self._delegate_property_get(name)
101+
102+
def _setter(self, new_values):
103+
return self._delegate_property_set(name, new_values)
104+
105+
_getter.__name__ = name
106+
_setter.__name__ = name
107+
108+
return property(fget=_getter, fset=_setter,
109+
doc=getattr(delegate, name).__doc__)
110+
111+
def _create_delegator_method(name):
112+
113+
def f(self, *args, **kwargs):
114+
return self._delegate_method(name, *args, **kwargs)
115+
116+
f.__name__ = name
117+
f.__doc__ = getattr(delegate, name).__doc__
118+
119+
return f
120+
121+
for name in accessors:
122+
123+
if typ == 'property':
124+
f = _create_delegator_property(name)
125+
else:
126+
f = _create_delegator_method(name)
127+
128+
# don't overwrite existing methods/properties
129+
if overwrite or not hasattr(cls, name):
130+
setattr(cls, name, f)

pandas/core/base.py

-94
Original file line numberDiff line numberDiff line change
@@ -153,100 +153,6 @@ def __setattr__(self, key, value):
153153
object.__setattr__(self, key, value)
154154

155155

156-
class PandasDelegate(PandasObject):
157-
""" an abstract base class for delegating methods/properties """
158-
159-
@classmethod
160-
def _make_accessor(cls, data):
161-
raise AbstractMethodError("_make_accessor should be implemented"
162-
"by subclass and return an instance"
163-
"of `cls`.")
164-
165-
def _delegate_property_get(self, name, *args, **kwargs):
166-
raise TypeError("You cannot access the "
167-
"property {name}".format(name=name))
168-
169-
def _delegate_property_set(self, name, value, *args, **kwargs):
170-
raise TypeError("The property {name} cannot be set".format(name=name))
171-
172-
def _delegate_method(self, name, *args, **kwargs):
173-
raise TypeError("You cannot call method {name}".format(name=name))
174-
175-
@classmethod
176-
def _add_delegate_accessors(cls, delegate, accessors, typ,
177-
overwrite=False):
178-
"""
179-
add accessors to cls from the delegate class
180-
181-
Parameters
182-
----------
183-
cls : the class to add the methods/properties to
184-
delegate : the class to get methods/properties & doc-strings
185-
acccessors : string list of accessors to add
186-
typ : 'property' or 'method'
187-
overwrite : boolean, default False
188-
overwrite the method/property in the target class if it exists
189-
"""
190-
191-
def _create_delegator_property(name):
192-
193-
def _getter(self):
194-
return self._delegate_property_get(name)
195-
196-
def _setter(self, new_values):
197-
return self._delegate_property_set(name, new_values)
198-
199-
_getter.__name__ = name
200-
_setter.__name__ = name
201-
202-
return property(fget=_getter, fset=_setter,
203-
doc=getattr(delegate, name).__doc__)
204-
205-
def _create_delegator_method(name):
206-
207-
def f(self, *args, **kwargs):
208-
return self._delegate_method(name, *args, **kwargs)
209-
210-
f.__name__ = name
211-
f.__doc__ = getattr(delegate, name).__doc__
212-
213-
return f
214-
215-
for name in accessors:
216-
217-
if typ == 'property':
218-
f = _create_delegator_property(name)
219-
else:
220-
f = _create_delegator_method(name)
221-
222-
# don't overwrite existing methods/properties
223-
if overwrite or not hasattr(cls, name):
224-
setattr(cls, name, f)
225-
226-
227-
class AccessorProperty(object):
228-
"""Descriptor for implementing accessor properties like Series.str
229-
"""
230-
231-
def __init__(self, accessor_cls, construct_accessor=None):
232-
self.accessor_cls = accessor_cls
233-
self.construct_accessor = (construct_accessor or
234-
accessor_cls._make_accessor)
235-
self.__doc__ = accessor_cls.__doc__
236-
237-
def __get__(self, instance, owner=None):
238-
if instance is None:
239-
# this ensures that Series.str.<method> is well defined
240-
return self.accessor_cls
241-
return self.construct_accessor(instance)
242-
243-
def __set__(self, instance, value):
244-
raise AttributeError("can't set attribute")
245-
246-
def __delete__(self, instance):
247-
raise AttributeError("can't delete attribute")
248-
249-
250156
class GroupByError(Exception):
251157
pass
252158

pandas/core/categorical.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
from pandas.core.common import is_null_slice, _maybe_box_datetimelike
3131

3232
from pandas.core.algorithms import factorize, take_1d, unique1d
33-
from pandas.core.base import (PandasObject, PandasDelegate,
33+
from pandas.core.accessor import PandasDelegate
34+
from pandas.core.base import (PandasObject,
3435
NoNewAttributesMixin, _shared_docs)
3536
import pandas.core.common as com
3637
from pandas.core.missing import interpolate_2d
@@ -2065,7 +2066,7 @@ def repeat(self, repeats, *args, **kwargs):
20652066
# The Series.cat accessor
20662067

20672068

2068-
class CategoricalAccessor(PandasDelegate, NoNewAttributesMixin):
2069+
class CategoricalAccessor(PandasDelegate, PandasObject, NoNewAttributesMixin):
20692070
"""
20702071
Accessor object for categorical properties of the Series values.
20712072

pandas/core/frame.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@
9090
from pandas.core.indexes.datetimes import DatetimeIndex
9191
from pandas.core.indexes.timedeltas import TimedeltaIndex
9292

93-
import pandas.core.base as base
93+
from pandas.core import accessor
9494
import pandas.core.common as com
9595
import pandas.core.nanops as nanops
9696
import pandas.core.ops as ops
@@ -5897,7 +5897,8 @@ def isin(self, values):
58975897

58985898
# ----------------------------------------------------------------------
58995899
# Add plotting methods to DataFrame
5900-
plot = base.AccessorProperty(gfx.FramePlotMethods, gfx.FramePlotMethods)
5900+
plot = accessor.AccessorProperty(gfx.FramePlotMethods,
5901+
gfx.FramePlotMethods)
59015902
hist = gfx.hist_frame
59025903
boxplot = gfx.boxplot_frame
59035904

pandas/core/indexes/accessors.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
is_timedelta64_dtype, is_categorical_dtype,
1212
is_list_like)
1313

14-
from pandas.core.base import PandasDelegate, NoNewAttributesMixin
14+
from pandas.core.accessor import PandasDelegate
15+
from pandas.core.base import NoNewAttributesMixin, PandasObject
1516
from pandas.core.indexes.datetimes import DatetimeIndex
1617
from pandas._libs.period import IncompatibleFrequency # noqa
1718
from pandas.core.indexes.period import PeriodIndex
@@ -81,7 +82,7 @@ def maybe_to_datetimelike(data, copy=False):
8182
"datetimelike index".format(type(data)))
8283

8384

84-
class Properties(PandasDelegate, NoNewAttributesMixin):
85+
class Properties(PandasDelegate, PandasObject, NoNewAttributesMixin):
8586

8687
def __init__(self, values, index, name, orig=None):
8788
self.values = values

pandas/core/indexes/base.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
import pandas.core.sorting as sorting
5858
from pandas.io.formats.printing import pprint_thing
5959
from pandas.core.ops import _comp_method_OBJECT_ARRAY
60-
from pandas.core import strings
60+
from pandas.core import strings, accessor
6161
from pandas.core.config import get_option
6262

6363

@@ -159,7 +159,7 @@ class Index(IndexOpsMixin, PandasObject):
159159
_accessors = frozenset(['str'])
160160

161161
# String Methods
162-
str = base.AccessorProperty(strings.StringMethods)
162+
str = accessor.AccessorProperty(strings.StringMethods)
163163

164164
def __new__(cls, data=None, dtype=None, copy=False, name=None,
165165
fastpath=False, tupleize_cols=True, **kwargs):

pandas/core/indexes/category.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from pandas.util._decorators import Appender, cache_readonly
2020
from pandas.core.config import get_option
2121
from pandas.core.indexes.base import Index, _index_shared_docs
22+
from pandas.core import accessor
2223
import pandas.core.base as base
2324
import pandas.core.missing as missing
2425
import pandas.core.indexes.base as ibase
@@ -27,7 +28,7 @@
2728
_index_doc_kwargs.update(dict(target_klass='CategoricalIndex'))
2829

2930

30-
class CategoricalIndex(Index, base.PandasDelegate):
31+
class CategoricalIndex(Index, accessor.PandasDelegate):
3132
"""
3233
3334
Immutable Index implementing an ordered, sliceable set. CategoricalIndex

pandas/core/series.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
from pandas.compat import zip, u, OrderedDict, StringIO
6363
from pandas.compat.numpy import function as nv
6464

65+
from pandas.core import accessor
6566
import pandas.core.ops as ops
6667
import pandas.core.algorithms as algorithms
6768

@@ -2901,19 +2902,19 @@ def to_period(self, freq=None, copy=True):
29012902

29022903
# -------------------------------------------------------------------------
29032904
# Datetimelike delegation methods
2904-
dt = base.AccessorProperty(CombinedDatetimelikeProperties)
2905+
dt = accessor.AccessorProperty(CombinedDatetimelikeProperties)
29052906

29062907
# -------------------------------------------------------------------------
29072908
# Categorical methods
2908-
cat = base.AccessorProperty(CategoricalAccessor)
2909+
cat = accessor.AccessorProperty(CategoricalAccessor)
29092910

29102911
# String Methods
2911-
str = base.AccessorProperty(strings.StringMethods)
2912+
str = accessor.AccessorProperty(strings.StringMethods)
29122913

29132914
# ----------------------------------------------------------------------
29142915
# Add plotting methods to Series
2915-
plot = base.AccessorProperty(gfx.SeriesPlotMethods,
2916-
gfx.SeriesPlotMethods)
2916+
plot = accessor.AccessorProperty(gfx.SeriesPlotMethods,
2917+
gfx.SeriesPlotMethods)
29172918
hist = gfx.hist_series
29182919

29192920

pandas/tests/test_base.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
CategoricalIndex, Timestamp)
1919
from pandas.compat import StringIO, PYPY, long
2020
from pandas.compat.numpy import np_array_datetime64_compat
21-
from pandas.core.base import PandasDelegate, NoNewAttributesMixin
21+
from pandas.core.accessor import PandasDelegate
22+
from pandas.core.base import PandasObject, NoNewAttributesMixin
2223
from pandas.core.indexes.datetimelike import DatetimeIndexOpsMixin
2324
from pandas._libs.tslib import iNaT
2425

@@ -105,7 +106,7 @@ def bar(self, *args, **kwargs):
105106
""" a test bar method """
106107
pass
107108

108-
class Delegate(PandasDelegate):
109+
class Delegate(PandasDelegate, PandasObject):
109110

110111
def __init__(self, obj):
111112
self.obj = obj

0 commit comments

Comments
 (0)