Skip to content

Commit d152421

Browse files
committed
Test to go along with example/recipe
Rename strings classes in tests Update imports in tests
1 parent 19f7ff6 commit d152421

File tree

4 files changed

+122
-23
lines changed

4 files changed

+122
-23
lines changed

pandas/tests/test_accessors.py

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
"""
4+
5+
An example/recipe/test for implementing custom accessors.
6+
7+
"""
8+
9+
import pandas as pd
10+
11+
from pandas.core.accessors import (wrap_delegate_names,
12+
PandasDelegate, AccessorProperty)
13+
14+
class State(object):
15+
def __repr__(self):
16+
return repr(self.name)
17+
18+
def __init__(self, name):
19+
self.name = name
20+
self._abbrev_dict = {'California': 'CA', 'Alabama': 'AL'}
21+
22+
@property
23+
def abbrev(self):
24+
return self._abbrev_dict[self.name]
25+
26+
@abbrev.setter
27+
def abbrev(self, value):
28+
self._abbrev_dict[self.name] = value
29+
30+
def fips(self):
31+
return {'California': 6, 'Alabama': 1}[self.name]
32+
33+
34+
35+
@wrap_delegate_names(delegate=State,
36+
accessors=["fips"],
37+
typ="method")
38+
@wrap_delegate_names(delegate=State,
39+
accessors=["abbrev"],
40+
typ="property")
41+
class StateDelegate(PandasDelegate):
42+
43+
def __init__(self, values):
44+
self.values = values
45+
#self._freeze()
46+
47+
@classmethod
48+
def _make_accessor(cls, data):
49+
"""
50+
When implementing custom accessors, `_make_accessor` is the place
51+
to do validation that the attributes be accessed will actually be
52+
present in the underlying data.
53+
"""
54+
if not isinstance(data, pd.Series):
55+
raise ValueError('Input must be a Series of States')
56+
elif not data.apply(lambda x: isinstance(x, State)).all():
57+
raise ValueError('All entries must be State objects')
58+
return StateDelegate(data)
59+
60+
def _delegate_method(self, name, *args, **kwargs):
61+
state_method = lambda x: getattr(x, name)(*args, **kwargs)
62+
return self.values.apply(state_method)
63+
64+
def _delegate_property_get(self, name):
65+
state_property = lambda x: getattr(x, name)
66+
return self.values.apply(state_property)
67+
68+
def _delegate_property_set(self, name, new_values):
69+
"""
70+
Setting properties via accessors is permitted but discouraged.
71+
"""
72+
for (obj, val) in zip(self.values, new_values):
73+
setattr(obj, name, val)
74+
75+
76+
77+
78+
79+
def test_geo_state_accessor():
80+
import pandas.util.testing as tm
81+
82+
pd.Series.state = AccessorProperty(StateDelegate)
83+
84+
ser = pd.Series([State('Alabama'), State('California')])
85+
86+
abbrev = pd.Series(['AL', 'CA'])
87+
tm.assert_series_equal(ser.state.abbrev, abbrev)
88+
89+
fips = pd.Series([1, 6])
90+
tm.assert_series_equal(ser.state.fips(), fips)
91+
92+
93+
94+
ser.state.abbrev = ['Foo', 'Bar']
95+
96+
new_abbrev = pd.Series(['Foo', 'Bar'])
97+
tm.assert_series_equal(ser.state.abbrev, new_abbrev)
98+
99+
100+

pandas/tests/test_base.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
Timedelta, IntervalIndex, Interval)
1818
from pandas.compat import StringIO
1919
from pandas.compat.numpy import np_array_datetime64_compat
20-
from pandas.core.accessors import PandasDelegate
20+
from pandas.core import accessors
21+
2122
from pandas.core.base import NoNewAttributesMixin
2223
from pandas.core.indexes.datetimelike import DatetimeIndexOpsMixin
2324
from pandas._libs.tslib import iNaT
@@ -105,28 +106,26 @@ def bar(self, *args, **kwargs):
105106
""" a test bar method """
106107
pass
107108

108-
class Delegate(PandasDelegate):
109+
class Delegate(accessors.PandasDelegate):
109110

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

113114
def setup_method(self, method):
114115
pass
115116

116-
def test_invalida_delgation(self):
117+
def test_invalid_delegation(self):
117118
# these show that in order for the delegation to work
118119
# the _delegate_* methods need to be overriden to not raise a TypeError
119120

120-
self.Delegate._add_delegate_accessors(
121-
delegate=self.Delegator,
122-
accessors=self.Delegator._properties,
123-
typ='property'
124-
)
125-
self.Delegate._add_delegate_accessors(
126-
delegate=self.Delegator,
127-
accessors=self.Delegator._methods,
128-
typ='method'
129-
)
121+
for name in self.Delegator._properties:
122+
func = accessors.Delegator.create_delegator_property(name, self.Delegator)
123+
setattr(self.Delegate, name, func)
124+
125+
for name in self.Delegator._methods:
126+
func = accessors.Delegator.create_delegator_method(name, self.Delegator)
127+
setattr(self.Delegate, name, func)
128+
130129

131130
delegate = self.Delegate(self.Delegator())
132131

pandas/tests/test_categorical.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4276,11 +4276,11 @@ def test_cat_accessor_no_new_attributes(self):
42764276

42774277
def test_str_accessor_api_for_categorical(self):
42784278
# https://github.com/pandas-dev/pandas/issues/10661
4279-
from pandas.core.strings import StringMethods
4279+
from pandas.core.strings import StringDelegate
42804280
s = Series(list('aabb'))
42814281
s = s + " " + s
42824282
c = s.astype('category')
4283-
assert isinstance(c.str, StringMethods)
4283+
assert isinstance(c.str, StringDelegate)
42844284

42854285
# str functions, which need special arguments
42864286
special_func_defs = [
@@ -4352,7 +4352,7 @@ def test_str_accessor_api_for_categorical(self):
43524352

43534353
def test_dt_accessor_api_for_categorical(self):
43544354
# https://github.com/pandas-dev/pandas/issues/10661
4355-
from pandas.core.indexes.accessors import Properties
4355+
from pandas.core.indexes.accessors import BaseDatetimeAccessor
43564356

43574357
s_dr = Series(date_range('1/1/2015', periods=5, tz="MET"))
43584358
c_dr = s_dr.astype("category")
@@ -4372,7 +4372,7 @@ def test_dt_accessor_api_for_categorical(self):
43724372
("Period", get_ops(PeriodIndex), s_pr, c_pr),
43734373
("Timedelta", get_ops(TimedeltaIndex), s_tdr, c_tdr)]
43744374

4375-
assert isinstance(c_dr.dt, Properties)
4375+
assert isinstance(c_dr.dt, BaseDatetimeAccessor)
43764376

43774377
special_func_defs = [
43784378
('strftime', ("%Y-%m-%d",), {}),

pandas/tests/test_strings.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ class TestStringMethods(object):
2424
def test_api(self):
2525

2626
# GH 6106, GH 9322
27-
assert Series.str is strings.StringMethods
28-
assert isinstance(Series(['']).str, strings.StringMethods)
27+
assert Series.str is strings.StringAccessor
28+
assert isinstance(Series(['']).str, strings.StringAccessor)
2929

3030
# GH 9184
3131
invalid = Series([1])
@@ -2708,14 +2708,14 @@ def test_index_str_accessor_visibility(self):
27082708
(['aa', datetime(2011, 1, 1)], 'mixed')]
27092709
for values, tp in cases:
27102710
idx = Index(values)
2711-
assert isinstance(Series(values).str, StringMethods)
2712-
assert isinstance(idx.str, StringMethods)
2711+
assert isinstance(Series(values).str, strings.StringAccessor)
2712+
assert isinstance(idx.str, strings.StringAccessor)
27132713
assert idx.inferred_type == tp
27142714

27152715
for values, tp in cases:
27162716
idx = Index(values)
2717-
assert isinstance(Series(values).str, StringMethods)
2718-
assert isinstance(idx.str, StringMethods)
2717+
assert isinstance(Series(values).str, strings.StringAccessor)
2718+
assert isinstance(idx.str, strings.StringAccessor)
27192719
assert idx.inferred_type == tp
27202720

27212721
cases = [([1, np.nan], 'floating'),

0 commit comments

Comments
 (0)