8000 reintroduce traitlets test · rmorshea/matplotlib@a4a2bb4 · GitHub
[go: up one dir, main page]

Skip to content

Commit a4a2bb4

Browse files
committed
reintroduce traitlets test
1 parent 6c4d647 commit a4a2bb4

File tree

3 files changed

+273
-7
lines changed

3 files changed

+273
-7
lines changed
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
from __future__ import absolute_import
2+
3+
from nose.tools import *
4+
from unittest import TestCase
5+
try:
6+
from traitlets import TraitError, HasTraits
7+
except ImportError:
8+
from IPython.utils.traitlets import TraitError, HasTraits
9+
10+
from matplotlib.traitlets import (Color, exdict, OnGetMixin, PrivateMethodMixin,
11+
Int, Configurable)
12+
13+
def test_exdict():
14+
e = exdict()
15+
assert_equal(e.ex, {})
16+
e['attr'] = 1
17+
assert_equal(e.ex, {})
18+
e['attr'] = 2
19+
assert_equal(e.ex, {'attr':1})
20+
21+
def test_getter():
22+
23+
class gInt(OnGetMixin, Int): pass
24+
25+
class A(PrivateMethodMixin, Configurable):
26+
27+
attr = gInt(0)
28+
def _attr_getter(self, value, trait):
29+
return value + 1
30+
31+
assert_equal(A().attr, 1)
32+
33+
class PrivateMethodTestCase(TestCase):
34+
"""Tests private attribute access, assignment, and callback forcing"""
35+
36+
def test_private_assignment(self):
37+
38+
class A(PrivateMethodMixin, Configurable):
39+
40+
attr = Int(0)
41+
# callbacks shouldn't be envoked
42+
def _attr_validate(self, value, trait):
43+
self.assertTrue(False)
44+
def _attr_changed(self):
45+
self.assertTrue(False)
46+
47+
a = A()
48+
a.private('attr', 1)
49+
self.assertEqual(a.attr, 1)
50+
51+
def test_private_access(self):
52+
53+
class gInt(OnGetMixin, Int): pass
54+
55+
class A(PrivateMethodMixin, Configurable):
56+
57+
attr = gInt(0)
58+
def _attr_getter(self, value, trait):
59+
return value + 1
60+
61+
self.assertEqual(A().private('attr'), 0)
62+
63+
def test_callback_forcing(self):
64+
65+
class A(PrivateMethodMixin, Configurable):
66+
67+
attr = Int(1)
68+
def _attr_validate(self, value, trait):
69+
return value+1
70+
def _attr_changed(self, name, old, new):
71+
# `private` avoids infinite recursion
72+
self.private(name, old+new)
73+
74+
a = A()
75+
a.private('attr', 2)
76+
self.assertEqual(a.attr, 2)
77+
a.force_callbacks('attr')
78+
self.assertEqual(a.attr, 4)
79+
80+
81+
class ColorTestCase(TestCase):
82+
"""Tests for the Color traits"""
83+
84+
def setUp(self):
85+
self.transparent_values = [None, False, '', 'none']
86+
self.black_values = ['#000000', '#000',(0,0,0,255), 0, 0.0, (.0,.0,.0), (.0,.0,.0,1.0)]
87+
self.colored_values = ['#BE3537', (190,53,55), (0.7451, 0.20784, 0.21569)]
88+
self.invalid_values = ['wfaef', '#0SX#$S', (0.45,0.3), 3.4, 344, (()), {}, True]
89+
90+
def _evaluate_invalids(self, a):
91+
for values in self.invalid_values:
92+
try:
93+
a.color = values
94+
assert_true(False)
95+
except TraitError:
96+
assert_raises(TraitError)
97+
98+
def test_noargs(self):
99+
class A(HasTraits):
100+
color = Color()
101+
a = A()
102+
for values in self.black_values:
103+
a.color = values
104+
assert_equal(a.color, (0.0,0.0,0.0,1.0))
105+
106+
for values in self.colored_values:
107+
a.color = values
108+
assert_equal(a.color, (0.7451, 0.20784, 0.21569, 1.0))
109+
self._evaluate_invalids(a)
110+
111+
112+
def test_hexcolor(self):
113+
class A(HasTraits):
114+
color = Color(as_hex=True)
115+
116+
a = A()
117+
118+
for values in self.black_values:
119+
a.color = values
120+
assert_equal(a.color, '#000000')
121+
122+
for values in self.colored_values:
123+
a.color = values
124+
assert_equal(a.color, '#be3537')
125+
126+
self._evaluate_invalids(a)
127+
128+
def test_rgb(self):
129+
class A(HasTraits):
130+
color = Color(force_rgb=True)
131+
132+
a = A()
133+
134+
for values in self.black_values:
135+
a.color = values
136+
assert_equal(a.color, (0.0,0.0,0.0))
137+
138+
for values in self.colored_values:
139+
a.color = values
140+
assert_equal(a.color, (0.7451, 0.20784, 0.21569))
141+
142+
self._evaluate_invalids(a)
143+
144+
def test_named(self):
145+
ncolors = {'hexblue': '#0000FF',
146+
'floatbllue': (0.0,0.0,1.0),
147+
'intblue' : (0,0,255)}
148+
149+
class A(HasTraits):
150+
color = Color()
151+
color.named_colors = ncolors
152+
153+
a = A()
154+
155+
for colorname in ncolors:
156+
a.color = colorname
157+
assert_equal(a.color, (0.0,0.0,1.0,1.0))
158+
159+
def test_alpha(self):
160+
class A(HasTraits):
161+
color = Color(default_alpha=0.4)
162+
163+
a = A()
164+
165+
assert_equal(a.color, (0.0, 0.0, 0.0, 1.0))
166+
167+
for values in self.transparent_values:
168+
a.color = values
169+
assert_equal(a.color, (0.0,0.0,0.0,0.0))
170+
171+
for values in self.black_values:
172+
a.color = values
173+
if isinstance(values, (tuple,list)) and len(values) == 4:
174+
assert_equal(a.color, (0.0,0.0,0.0,1.0))
175+
else:
176+
# User not provide alpha value so return default_alpha
177+
assert_equal(a.color, (0.0,0.0,0.0,0.4))
178+
179+
for values in self.colored_values:
180+
a.color = values
181+
assert_equal(a.color, (0.7451, 0.20784, 0.21569, 0.4))
182+
183+
if __name__ == '__main__':
184+
import nose
185+
nose.runmodule(argv=['-s', '--with-doctest'], exit=False)

lib/matplotlib/traitlets.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -77,24 +77,24 @@ def force_callbacks(self, name, cross_validate=True, notify_trait=True):
7777
except KeyError:
7878
trait = getattr(self.__class__, name)
7979
old = trait.default_value
80-
if notify_trait:
81-
self._notify_trait(name, old, new)
8280
if cross_validate:
8381
trait = self._retrieve_trait(name)
8482
# note value is updated via cross validation
8583
new = trait._cross_validate(self, new)
8684
self.private(name, new)
85+
if notify_trait:
86+
self._notify_trait(name, old, new)
8787

8888
def private(self, name, value=Undefined):
8989
trait = self._retrieve_trait(name)
9090

9191
if value is not Undefined:
92-
trait._cross_validation_lock = True
92+
self._cross_validation_lock = True
9393
_notify_trait = self._notify_trait
9494
self._notify_trait = lambda *a: None
9595
setattr(self, name, value)
9696
self._notify_trait = _notify_trait
97-
trait._cross_validation_lock = False
97+
self._cross_validation_lock = False
9898
if isinstance(_notify_trait, types.MethodType):
9999
self.__dict__.pop('_notify_trait', None)
100100

@@ -106,10 +106,10 @@ def _retrieve_trait(self, name):
106106
try:
107107
trait = getattr(self.__class__, name)
108108
if not isinstance(trait, BaseDescriptor):
109-
msg = "'%s' is a standard attribute, not a trait, of a %s instance"
109+
msg = "'%s' is a standard attribute, not a traitlet, of a %s instance"
110110
raise TraitError(msg % (name, self.__class__.__name__))
111111
except AttributeError:
112-
msg = "'%s' is not a trait of a %s instance"
112+
msg = "'%s' is not a traitlet of a %s instance"
113113
raise TraitError(msg % (name, self.__class__.__name__))
114114
return trait
115115

@@ -306,12 +306,15 @@ class Color(TraitType):
306306
'as_hex' : False,
307307
'default_alpha' : 1.0,
308308
}
309-
allow_none = True
310309
info_text = 'float, int, tuple of float or int, or a hex string color'
311310
default_value = (0.0,0.0,0.0, metadata['default_alpha'])
312311
named_colors = {}
313312
_re_color_hex = re.compile(r'#[a-fA-F0-9]{3}(?:[a-fA-F0-9]{3})?$')
314313

314+
def __init__(self, *args, **kwargs):
315+
super(Color, self).__init__(*args, **kwargs)
316+
self._metadata = self.metadata.copy()
317+
315318
def _int_to_float(self, value):
316319
as_float = (np.array(value)/255).tolist()
317320
return as_float

tools/refactor.ipynb

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,84 @@
4545
"#mrt.perform_replacements()"
4646
]
4747
},
48+
{
49+
"cell_type": "code",
50+
"execution_count": 3,
51+
"metadata": {
52+
"collapsed": true
53+
},
54+
"outputs": [],
55+
"source": [
56+
"from matplotlib.traitlets import exdict"
57+
]
58+
},
59+
{
60+
"cell_type": "code",
61+
"execution_count": 10,
62+
"metadata": {
63+
"collapsed": true
64+
},
65+
"outputs": [],
66+
"source": [
67+
"ed = exdict()"
68+
]
69+
},
70+
{
71+
"cell_type": "code",
72+
"execution_count": 12,
73+
"metadata": {
74+
"collapsed": false
75+
},
76+
"outputs": [
77+
{
78+
"data": {
79+
"text/plain": [
80+
"True"
81+
]
82+
},
83+
"execution_count": 12,
84+
"metadata": {},
85+
"output_type": "execute_result"
86+
}
87+
],
88+
"source": [
89+
"ed =={}"
90+
]
91+
},
92+
{
93+
"cell_type": "code",
94+
"execution_count": 8,
95+
"metadata": {
96+
"collapsed": false
97+
},
98+
"outputs": [],
99+
"source": [
100+
"ed['a'] = 1"
101+
]
102+
},
103+
{
104+
"cell_type": "code",
105+
"execution_count": 9,
106+
"metadata": {
107+
"collapsed": false
108+
},
109+
"outputs": [
110+
{
111+
"ename": "KeyError",
112+
"evalue": "'a'",
113+
"output_type": "error",
114+
"traceback": [
115+
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
116+
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
117+
"\u001b[0;32m<ipython-input-9-ef601d9802db>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0med\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mex\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'a'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
118+
"\u001b[0;31mKeyError\u001b[0m: 'a'"
119+
]
120+
}
121+
],
122+
"source": [
123+
"ed.ex['a']"
124+
]
125+
},
48126
{
49127
"cell_type": "code",
50128
"execution_count": null,

0 commit comments

Comments
 (0)
0