##// END OF EJS Templates
Move forward-declaration tests to their own section of test_traitlets.
Scott Sanderson -
Show More
@@ -1,1369 +1,1422 b''
1 # encoding: utf-8
1 # encoding: utf-8
2 """Tests for IPython.utils.traitlets."""
2 """Tests for IPython.utils.traitlets."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6 #
6 #
7 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
7 # Adapted from enthought.traits, Copyright (c) Enthought, Inc.,
8 # also under the terms of the Modified BSD License.
8 # also under the terms of the Modified BSD License.
9
9
10 import pickle
10 import pickle
11 import re
11 import re
12 import sys
12 import sys
13 from unittest import TestCase
13 from unittest import TestCase
14
14
15 import nose.tools as nt
15 import nose.tools as nt
16 from nose import SkipTest
16 from nose import SkipTest
17
17
18 from IPython.utils.traitlets import (
18 from IPython.utils.traitlets import (
19 HasTraits, MetaHasTraits, TraitType, Any, CBytes, Dict,
19 HasTraits, MetaHasTraits, TraitType, Any, CBytes, Dict,
20 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
20 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
21 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
21 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
22 ObjectName, DottedObjectName, CRegExp, link, directional_link,
22 ObjectName, DottedObjectName, CRegExp, link, directional_link,
23 EventfulList, EventfulDict, ForwardDeclaredType, ForwardDeclaredInstance,
23 EventfulList, EventfulDict, ForwardDeclaredType, ForwardDeclaredInstance,
24 )
24 )
25 from IPython.utils import py3compat
25 from IPython.utils import py3compat
26 from IPython.testing.decorators import skipif
26 from IPython.testing.decorators import skipif
27
27
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29 # Helper classes for testing
29 # Helper classes for testing
30 #-----------------------------------------------------------------------------
30 #-----------------------------------------------------------------------------
31
31
32
32
33 class HasTraitsStub(HasTraits):
33 class HasTraitsStub(HasTraits):
34
34
35 def _notify_trait(self, name, old, new):
35 def _notify_trait(self, name, old, new):
36 self._notify_name = name
36 self._notify_name = name
37 self._notify_old = old
37 self._notify_old = old
38 self._notify_new = new
38 self._notify_new = new
39
39
40
40
41 #-----------------------------------------------------------------------------
41 #-----------------------------------------------------------------------------
42 # Test classes
42 # Test classes
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44
44
45
45
46 class TestTraitType(TestCase):
46 class TestTraitType(TestCase):
47
47
48 def test_get_undefined(self):
48 def test_get_undefined(self):
49 class A(HasTraits):
49 class A(HasTraits):
50 a = TraitType
50 a = TraitType
51 a = A()
51 a = A()
52 self.assertEqual(a.a, Undefined)
52 self.assertEqual(a.a, Undefined)
53
53
54 def test_set(self):
54 def test_set(self):
55 class A(HasTraitsStub):
55 class A(HasTraitsStub):
56 a = TraitType
56 a = TraitType
57
57
58 a = A()
58 a = A()
59 a.a = 10
59 a.a = 10
60 self.assertEqual(a.a, 10)
60 self.assertEqual(a.a, 10)
61 self.assertEqual(a._notify_name, 'a')
61 self.assertEqual(a._notify_name, 'a')
62 self.assertEqual(a._notify_old, Undefined)
62 self.assertEqual(a._notify_old, Undefined)
63 self.assertEqual(a._notify_new, 10)
63 self.assertEqual(a._notify_new, 10)
64
64
65 def test_validate(self):
65 def test_validate(self):
66 class MyTT(TraitType):
66 class MyTT(TraitType):
67 def validate(self, inst, value):
67 def validate(self, inst, value):
68 return -1
68 return -1
69 class A(HasTraitsStub):
69 class A(HasTraitsStub):
70 tt = MyTT
70 tt = MyTT
71
71
72 a = A()
72 a = A()
73 a.tt = 10
73 a.tt = 10
74 self.assertEqual(a.tt, -1)
74 self.assertEqual(a.tt, -1)
75
75
76 def test_default_validate(self):
76 def test_default_validate(self):
77 class MyIntTT(TraitType):
77 class MyIntTT(TraitType):
78 def validate(self, obj, value):
78 def validate(self, obj, value):
79 if isinstance(value, int):
79 if isinstance(value, int):
80 return value
80 return value
81 self.error(obj, value)
81 self.error(obj, value)
82 class A(HasTraits):
82 class A(HasTraits):
83 tt = MyIntTT(10)
83 tt = MyIntTT(10)
84 a = A()
84 a = A()
85 self.assertEqual(a.tt, 10)
85 self.assertEqual(a.tt, 10)
86
86
87 # Defaults are validated when the HasTraits is instantiated
87 # Defaults are validated when the HasTraits is instantiated
88 class B(HasTraits):
88 class B(HasTraits):
89 tt = MyIntTT('bad default')
89 tt = MyIntTT('bad default')
90 self.assertRaises(TraitError, B)
90 self.assertRaises(TraitError, B)
91
91
92 def test_is_valid_for(self):
92 def test_is_valid_for(self):
93 class MyTT(TraitType):
93 class MyTT(TraitType):
94 def is_valid_for(self, value):
94 def is_valid_for(self, value):
95 return True
95 return True
96 class A(HasTraits):
96 class A(HasTraits):
97 tt = MyTT
97 tt = MyTT
98
98
99 a = A()
99 a = A()
100 a.tt = 10
100 a.tt = 10
101 self.assertEqual(a.tt, 10)
101 self.assertEqual(a.tt, 10)
102
102
103 def test_value_for(self):
103 def test_value_for(self):
104 class MyTT(TraitType):
104 class MyTT(TraitType):
105 def value_for(self, value):
105 def value_for(self, value):
106 return 20
106 return 20
107 class A(HasTraits):
107 class A(HasTraits):
108 tt = MyTT
108 tt = MyTT
109
109
110 a = A()
110 a = A()
111 a.tt = 10
111 a.tt = 10
112 self.assertEqual(a.tt, 20)
112 self.assertEqual(a.tt, 20)
113
113
114 def test_info(self):
114 def test_info(self):
115 class A(HasTraits):
115 class A(HasTraits):
116 tt = TraitType
116 tt = TraitType
117 a = A()
117 a = A()
118 self.assertEqual(A.tt.info(), 'any value')
118 self.assertEqual(A.tt.info(), 'any value')
119
119
120 def test_error(self):
120 def test_error(self):
121 class A(HasTraits):
121 class A(HasTraits):
122 tt = TraitType
122 tt = TraitType
123 a = A()
123 a = A()
124 self.assertRaises(TraitError, A.tt.error, a, 10)
124 self.assertRaises(TraitError, A.tt.error, a, 10)
125
125
126 def test_dynamic_initializer(self):
126 def test_dynamic_initializer(self):
127 class A(HasTraits):
127 class A(HasTraits):
128 x = Int(10)
128 x = Int(10)
129 def _x_default(self):
129 def _x_default(self):
130 return 11
130 return 11
131 class B(A):
131 class B(A):
132 x = Int(20)
132 x = Int(20)
133 class C(A):
133 class C(A):
134 def _x_default(self):
134 def _x_default(self):
135 return 21
135 return 21
136
136
137 a = A()
137 a = A()
138 self.assertEqual(a._trait_values, {})
138 self.assertEqual(a._trait_values, {})
139 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
139 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
140 self.assertEqual(a.x, 11)
140 self.assertEqual(a.x, 11)
141 self.assertEqual(a._trait_values, {'x': 11})
141 self.assertEqual(a._trait_values, {'x': 11})
142 b = B()
142 b = B()
143 self.assertEqual(b._trait_values, {'x': 20})
143 self.assertEqual(b._trait_values, {'x': 20})
144 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
144 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
145 self.assertEqual(b.x, 20)
145 self.assertEqual(b.x, 20)
146 c = C()
146 c = C()
147 self.assertEqual(c._trait_values, {})
147 self.assertEqual(c._trait_values, {})
148 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
148 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
149 self.assertEqual(c.x, 21)
149 self.assertEqual(c.x, 21)
150 self.assertEqual(c._trait_values, {'x': 21})
150 self.assertEqual(c._trait_values, {'x': 21})
151 # Ensure that the base class remains unmolested when the _default
151 # Ensure that the base class remains unmolested when the _default
152 # initializer gets overridden in a subclass.
152 # initializer gets overridden in a subclass.
153 a = A()
153 a = A()
154 c = C()
154 c = C()
155 self.assertEqual(a._trait_values, {})
155 self.assertEqual(a._trait_values, {})
156 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
156 self.assertEqual(list(a._trait_dyn_inits.keys()), ['x'])
157 self.assertEqual(a.x, 11)
157 self.assertEqual(a.x, 11)
158 self.assertEqual(a._trait_values, {'x': 11})
158 self.assertEqual(a._trait_values, {'x': 11})
159
159
160
160
161
161
162 class TestHasTraitsMeta(TestCase):
162 class TestHasTraitsMeta(TestCase):
163
163
164 def test_metaclass(self):
164 def test_metaclass(self):
165 self.assertEqual(type(HasTraits), MetaHasTraits)
165 self.assertEqual(type(HasTraits), MetaHasTraits)
166
166
167 class A(HasTraits):
167 class A(HasTraits):
168 a = Int
168 a = Int
169
169
170 a = A()
170 a = A()
171 self.assertEqual(type(a.__class__), MetaHasTraits)
171 self.assertEqual(type(a.__class__), MetaHasTraits)
172 self.assertEqual(a.a,0)
172 self.assertEqual(a.a,0)
173 a.a = 10
173 a.a = 10
174 self.assertEqual(a.a,10)
174 self.assertEqual(a.a,10)
175
175
176 class B(HasTraits):
176 class B(HasTraits):
177 b = Int()
177 b = Int()
178
178
179 b = B()
179 b = B()
180 self.assertEqual(b.b,0)
180 self.assertEqual(b.b,0)
181 b.b = 10
181 b.b = 10
182 self.assertEqual(b.b,10)
182 self.assertEqual(b.b,10)
183
183
184 class C(HasTraits):
184 class C(HasTraits):
185 c = Int(30)
185 c = Int(30)
186
186
187 c = C()
187 c = C()
188 self.assertEqual(c.c,30)
188 self.assertEqual(c.c,30)
189 c.c = 10
189 c.c = 10
190 self.assertEqual(c.c,10)
190 self.assertEqual(c.c,10)
191
191
192 def test_this_class(self):
192 def test_this_class(self):
193 class A(HasTraits):
193 class A(HasTraits):
194 t = This()
194 t = This()
195 tt = This()
195 tt = This()
196 class B(A):
196 class B(A):
197 tt = This()
197 tt = This()
198 ttt = This()
198 ttt = This()
199 self.assertEqual(A.t.this_class, A)
199 self.assertEqual(A.t.this_class, A)
200 self.assertEqual(B.t.this_class, A)
200 self.assertEqual(B.t.this_class, A)
201 self.assertEqual(B.tt.this_class, B)
201 self.assertEqual(B.tt.this_class, B)
202 self.assertEqual(B.ttt.this_class, B)
202 self.assertEqual(B.ttt.this_class, B)
203
203
204 class TestHasTraitsNotify(TestCase):
204 class TestHasTraitsNotify(TestCase):
205
205
206 def setUp(self):
206 def setUp(self):
207 self._notify1 = []
207 self._notify1 = []
208 self._notify2 = []
208 self._notify2 = []
209
209
210 def notify1(self, name, old, new):
210 def notify1(self, name, old, new):
211 self._notify1.append((name, old, new))
211 self._notify1.append((name, old, new))
212
212
213 def notify2(self, name, old, new):
213 def notify2(self, name, old, new):
214 self._notify2.append((name, old, new))
214 self._notify2.append((name, old, new))
215
215
216 def test_notify_all(self):
216 def test_notify_all(self):
217
217
218 class A(HasTraits):
218 class A(HasTraits):
219 a = Int
219 a = Int
220 b = Float
220 b = Float
221
221
222 a = A()
222 a = A()
223 a.on_trait_change(self.notify1)
223 a.on_trait_change(self.notify1)
224 a.a = 0
224 a.a = 0
225 self.assertEqual(len(self._notify1),0)
225 self.assertEqual(len(self._notify1),0)
226 a.b = 0.0
226 a.b = 0.0
227 self.assertEqual(len(self._notify1),0)
227 self.assertEqual(len(self._notify1),0)
228 a.a = 10
228 a.a = 10
229 self.assertTrue(('a',0,10) in self._notify1)
229 self.assertTrue(('a',0,10) in self._notify1)
230 a.b = 10.0
230 a.b = 10.0
231 self.assertTrue(('b',0.0,10.0) in self._notify1)
231 self.assertTrue(('b',0.0,10.0) in self._notify1)
232 self.assertRaises(TraitError,setattr,a,'a','bad string')
232 self.assertRaises(TraitError,setattr,a,'a','bad string')
233 self.assertRaises(TraitError,setattr,a,'b','bad string')
233 self.assertRaises(TraitError,setattr,a,'b','bad string')
234 self._notify1 = []
234 self._notify1 = []
235 a.on_trait_change(self.notify1,remove=True)
235 a.on_trait_change(self.notify1,remove=True)
236 a.a = 20
236 a.a = 20
237 a.b = 20.0
237 a.b = 20.0
238 self.assertEqual(len(self._notify1),0)
238 self.assertEqual(len(self._notify1),0)
239
239
240 def test_notify_one(self):
240 def test_notify_one(self):
241
241
242 class A(HasTraits):
242 class A(HasTraits):
243 a = Int
243 a = Int
244 b = Float
244 b = Float
245
245
246 a = A()
246 a = A()
247 a.on_trait_change(self.notify1, 'a')
247 a.on_trait_change(self.notify1, 'a')
248 a.a = 0
248 a.a = 0
249 self.assertEqual(len(self._notify1),0)
249 self.assertEqual(len(self._notify1),0)
250 a.a = 10
250 a.a = 10
251 self.assertTrue(('a',0,10) in self._notify1)
251 self.assertTrue(('a',0,10) in self._notify1)
252 self.assertRaises(TraitError,setattr,a,'a','bad string')
252 self.assertRaises(TraitError,setattr,a,'a','bad string')
253
253
254 def test_subclass(self):
254 def test_subclass(self):
255
255
256 class A(HasTraits):
256 class A(HasTraits):
257 a = Int
257 a = Int
258
258
259 class B(A):
259 class B(A):
260 b = Float
260 b = Float
261
261
262 b = B()
262 b = B()
263 self.assertEqual(b.a,0)
263 self.assertEqual(b.a,0)
264 self.assertEqual(b.b,0.0)
264 self.assertEqual(b.b,0.0)
265 b.a = 100
265 b.a = 100
266 b.b = 100.0
266 b.b = 100.0
267 self.assertEqual(b.a,100)
267 self.assertEqual(b.a,100)
268 self.assertEqual(b.b,100.0)
268 self.assertEqual(b.b,100.0)
269
269
270 def test_notify_subclass(self):
270 def test_notify_subclass(self):
271
271
272 class A(HasTraits):
272 class A(HasTraits):
273 a = Int
273 a = Int
274
274
275 class B(A):
275 class B(A):
276 b = Float
276 b = Float
277
277
278 b = B()
278 b = B()
279 b.on_trait_change(self.notify1, 'a')
279 b.on_trait_change(self.notify1, 'a')
280 b.on_trait_change(self.notify2, 'b')
280 b.on_trait_change(self.notify2, 'b')
281 b.a = 0
281 b.a = 0
282 b.b = 0.0
282 b.b = 0.0
283 self.assertEqual(len(self._notify1),0)
283 self.assertEqual(len(self._notify1),0)
284 self.assertEqual(len(self._notify2),0)
284 self.assertEqual(len(self._notify2),0)
285 b.a = 10
285 b.a = 10
286 b.b = 10.0
286 b.b = 10.0
287 self.assertTrue(('a',0,10) in self._notify1)
287 self.assertTrue(('a',0,10) in self._notify1)
288 self.assertTrue(('b',0.0,10.0) in self._notify2)
288 self.assertTrue(('b',0.0,10.0) in self._notify2)
289
289
290 def test_static_notify(self):
290 def test_static_notify(self):
291
291
292 class A(HasTraits):
292 class A(HasTraits):
293 a = Int
293 a = Int
294 _notify1 = []
294 _notify1 = []
295 def _a_changed(self, name, old, new):
295 def _a_changed(self, name, old, new):
296 self._notify1.append((name, old, new))
296 self._notify1.append((name, old, new))
297
297
298 a = A()
298 a = A()
299 a.a = 0
299 a.a = 0
300 # This is broken!!!
300 # This is broken!!!
301 self.assertEqual(len(a._notify1),0)
301 self.assertEqual(len(a._notify1),0)
302 a.a = 10
302 a.a = 10
303 self.assertTrue(('a',0,10) in a._notify1)
303 self.assertTrue(('a',0,10) in a._notify1)
304
304
305 class B(A):
305 class B(A):
306 b = Float
306 b = Float
307 _notify2 = []
307 _notify2 = []
308 def _b_changed(self, name, old, new):
308 def _b_changed(self, name, old, new):
309 self._notify2.append((name, old, new))
309 self._notify2.append((name, old, new))
310
310
311 b = B()
311 b = B()
312 b.a = 10
312 b.a = 10
313 b.b = 10.0
313 b.b = 10.0
314 self.assertTrue(('a',0,10) in b._notify1)
314 self.assertTrue(('a',0,10) in b._notify1)
315 self.assertTrue(('b',0.0,10.0) in b._notify2)
315 self.assertTrue(('b',0.0,10.0) in b._notify2)
316
316
317 def test_notify_args(self):
317 def test_notify_args(self):
318
318
319 def callback0():
319 def callback0():
320 self.cb = ()
320 self.cb = ()
321 def callback1(name):
321 def callback1(name):
322 self.cb = (name,)
322 self.cb = (name,)
323 def callback2(name, new):
323 def callback2(name, new):
324 self.cb = (name, new)
324 self.cb = (name, new)
325 def callback3(name, old, new):
325 def callback3(name, old, new):
326 self.cb = (name, old, new)
326 self.cb = (name, old, new)
327
327
328 class A(HasTraits):
328 class A(HasTraits):
329 a = Int
329 a = Int
330
330
331 a = A()
331 a = A()
332 a.on_trait_change(callback0, 'a')
332 a.on_trait_change(callback0, 'a')
333 a.a = 10
333 a.a = 10
334 self.assertEqual(self.cb,())
334 self.assertEqual(self.cb,())
335 a.on_trait_change(callback0, 'a', remove=True)
335 a.on_trait_change(callback0, 'a', remove=True)
336
336
337 a.on_trait_change(callback1, 'a')
337 a.on_trait_change(callback1, 'a')
338 a.a = 100
338 a.a = 100
339 self.assertEqual(self.cb,('a',))
339 self.assertEqual(self.cb,('a',))
340 a.on_trait_change(callback1, 'a', remove=True)
340 a.on_trait_change(callback1, 'a', remove=True)
341
341
342 a.on_trait_change(callback2, 'a')
342 a.on_trait_change(callback2, 'a')
343 a.a = 1000
343 a.a = 1000
344 self.assertEqual(self.cb,('a',1000))
344 self.assertEqual(self.cb,('a',1000))
345 a.on_trait_change(callback2, 'a', remove=True)
345 a.on_trait_change(callback2, 'a', remove=True)
346
346
347 a.on_trait_change(callback3, 'a')
347 a.on_trait_change(callback3, 'a')
348 a.a = 10000
348 a.a = 10000
349 self.assertEqual(self.cb,('a',1000,10000))
349 self.assertEqual(self.cb,('a',1000,10000))
350 a.on_trait_change(callback3, 'a', remove=True)
350 a.on_trait_change(callback3, 'a', remove=True)
351
351
352 self.assertEqual(len(a._trait_notifiers['a']),0)
352 self.assertEqual(len(a._trait_notifiers['a']),0)
353
353
354 def test_notify_only_once(self):
354 def test_notify_only_once(self):
355
355
356 class A(HasTraits):
356 class A(HasTraits):
357 listen_to = ['a']
357 listen_to = ['a']
358
358
359 a = Int(0)
359 a = Int(0)
360 b = 0
360 b = 0
361
361
362 def __init__(self, **kwargs):
362 def __init__(self, **kwargs):
363 super(A, self).__init__(**kwargs)
363 super(A, self).__init__(**kwargs)
364 self.on_trait_change(self.listener1, ['a'])
364 self.on_trait_change(self.listener1, ['a'])
365
365
366 def listener1(self, name, old, new):
366 def listener1(self, name, old, new):
367 self.b += 1
367 self.b += 1
368
368
369 class B(A):
369 class B(A):
370
370
371 c = 0
371 c = 0
372 d = 0
372 d = 0
373
373
374 def __init__(self, **kwargs):
374 def __init__(self, **kwargs):
375 super(B, self).__init__(**kwargs)
375 super(B, self).__init__(**kwargs)
376 self.on_trait_change(self.listener2)
376 self.on_trait_change(self.listener2)
377
377
378 def listener2(self, name, old, new):
378 def listener2(self, name, old, new):
379 self.c += 1
379 self.c += 1
380
380
381 def _a_changed(self, name, old, new):
381 def _a_changed(self, name, old, new):
382 self.d += 1
382 self.d += 1
383
383
384 b = B()
384 b = B()
385 b.a += 1
385 b.a += 1
386 self.assertEqual(b.b, b.c)
386 self.assertEqual(b.b, b.c)
387 self.assertEqual(b.b, b.d)
387 self.assertEqual(b.b, b.d)
388 b.a += 1
388 b.a += 1
389 self.assertEqual(b.b, b.c)
389 self.assertEqual(b.b, b.c)
390 self.assertEqual(b.b, b.d)
390 self.assertEqual(b.b, b.d)
391
391
392
392
393 class TestHasTraits(TestCase):
393 class TestHasTraits(TestCase):
394
394
395 def test_trait_names(self):
395 def test_trait_names(self):
396 class A(HasTraits):
396 class A(HasTraits):
397 i = Int
397 i = Int
398 f = Float
398 f = Float
399 a = A()
399 a = A()
400 self.assertEqual(sorted(a.trait_names()),['f','i'])
400 self.assertEqual(sorted(a.trait_names()),['f','i'])
401 self.assertEqual(sorted(A.class_trait_names()),['f','i'])
401 self.assertEqual(sorted(A.class_trait_names()),['f','i'])
402
402
403 def test_trait_metadata(self):
403 def test_trait_metadata(self):
404 class A(HasTraits):
404 class A(HasTraits):
405 i = Int(config_key='MY_VALUE')
405 i = Int(config_key='MY_VALUE')
406 a = A()
406 a = A()
407 self.assertEqual(a.trait_metadata('i','config_key'), 'MY_VALUE')
407 self.assertEqual(a.trait_metadata('i','config_key'), 'MY_VALUE')
408
408
409 def test_trait_metadata_default(self):
409 def test_trait_metadata_default(self):
410 class A(HasTraits):
410 class A(HasTraits):
411 i = Int()
411 i = Int()
412 a = A()
412 a = A()
413 self.assertEqual(a.trait_metadata('i', 'config_key'), None)
413 self.assertEqual(a.trait_metadata('i', 'config_key'), None)
414 self.assertEqual(a.trait_metadata('i', 'config_key', 'default'), 'default')
414 self.assertEqual(a.trait_metadata('i', 'config_key', 'default'), 'default')
415
415
416 def test_traits(self):
416 def test_traits(self):
417 class A(HasTraits):
417 class A(HasTraits):
418 i = Int
418 i = Int
419 f = Float
419 f = Float
420 a = A()
420 a = A()
421 self.assertEqual(a.traits(), dict(i=A.i, f=A.f))
421 self.assertEqual(a.traits(), dict(i=A.i, f=A.f))
422 self.assertEqual(A.class_traits(), dict(i=A.i, f=A.f))
422 self.assertEqual(A.class_traits(), dict(i=A.i, f=A.f))
423
423
424 def test_traits_metadata(self):
424 def test_traits_metadata(self):
425 class A(HasTraits):
425 class A(HasTraits):
426 i = Int(config_key='VALUE1', other_thing='VALUE2')
426 i = Int(config_key='VALUE1', other_thing='VALUE2')
427 f = Float(config_key='VALUE3', other_thing='VALUE2')
427 f = Float(config_key='VALUE3', other_thing='VALUE2')
428 j = Int(0)
428 j = Int(0)
429 a = A()
429 a = A()
430 self.assertEqual(a.traits(), dict(i=A.i, f=A.f, j=A.j))
430 self.assertEqual(a.traits(), dict(i=A.i, f=A.f, j=A.j))
431 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
431 traits = a.traits(config_key='VALUE1', other_thing='VALUE2')
432 self.assertEqual(traits, dict(i=A.i))
432 self.assertEqual(traits, dict(i=A.i))
433
433
434 # This passes, but it shouldn't because I am replicating a bug in
434 # This passes, but it shouldn't because I am replicating a bug in
435 # traits.
435 # traits.
436 traits = a.traits(config_key=lambda v: True)
436 traits = a.traits(config_key=lambda v: True)
437 self.assertEqual(traits, dict(i=A.i, f=A.f, j=A.j))
437 self.assertEqual(traits, dict(i=A.i, f=A.f, j=A.j))
438
438
439 def test_init(self):
439 def test_init(self):
440 class A(HasTraits):
440 class A(HasTraits):
441 i = Int()
441 i = Int()
442 x = Float()
442 x = Float()
443 a = A(i=1, x=10.0)
443 a = A(i=1, x=10.0)
444 self.assertEqual(a.i, 1)
444 self.assertEqual(a.i, 1)
445 self.assertEqual(a.x, 10.0)
445 self.assertEqual(a.x, 10.0)
446
446
447 def test_positional_args(self):
447 def test_positional_args(self):
448 class A(HasTraits):
448 class A(HasTraits):
449 i = Int(0)
449 i = Int(0)
450 def __init__(self, i):
450 def __init__(self, i):
451 super(A, self).__init__()
451 super(A, self).__init__()
452 self.i = i
452 self.i = i
453
453
454 a = A(5)
454 a = A(5)
455 self.assertEqual(a.i, 5)
455 self.assertEqual(a.i, 5)
456 # should raise TypeError if no positional arg given
456 # should raise TypeError if no positional arg given
457 self.assertRaises(TypeError, A)
457 self.assertRaises(TypeError, A)
458
458
459 #-----------------------------------------------------------------------------
459 #-----------------------------------------------------------------------------
460 # Tests for specific trait types
460 # Tests for specific trait types
461 #-----------------------------------------------------------------------------
461 #-----------------------------------------------------------------------------
462
462
463
463
464 class TestType(TestCase):
464 class TestType(TestCase):
465
465
466 def test_default(self):
466 def test_default(self):
467
467
468 class B(object): pass
468 class B(object): pass
469 class A(HasTraits):
469 class A(HasTraits):
470 klass = Type
470 klass = Type
471
471
472 a = A()
472 a = A()
473 self.assertEqual(a.klass, None)
473 self.assertEqual(a.klass, None)
474
474
475 a.klass = B
475 a.klass = B
476 self.assertEqual(a.klass, B)
476 self.assertEqual(a.klass, B)
477 self.assertRaises(TraitError, setattr, a, 'klass', 10)
477 self.assertRaises(TraitError, setattr, a, 'klass', 10)
478
478
479 def test_value(self):
479 def test_value(self):
480
480
481 class B(object): pass
481 class B(object): pass
482 class C(object): pass
482 class C(object): pass
483 class A(HasTraits):
483 class A(HasTraits):
484 klass = Type(B)
484 klass = Type(B)
485
485
486 a = A()
486 a = A()
487 self.assertEqual(a.klass, B)
487 self.assertEqual(a.klass, B)
488 self.assertRaises(TraitError, setattr, a, 'klass', C)
488 self.assertRaises(TraitError, setattr, a, 'klass', C)
489 self.assertRaises(TraitError, setattr, a, 'klass', object)
489 self.assertRaises(TraitError, setattr, a, 'klass', object)
490 a.klass = B
490 a.klass = B
491
491
492 def test_allow_none(self):
492 def test_allow_none(self):
493
493
494 class B(object): pass
494 class B(object): pass
495 class C(B): pass
495 class C(B): pass
496 class A(HasTraits):
496 class A(HasTraits):
497 klass = Type(B, allow_none=False)
497 klass = Type(B, allow_none=False)
498
498
499 a = A()
499 a = A()
500 self.assertEqual(a.klass, B)
500 self.assertEqual(a.klass, B)
501 self.assertRaises(TraitError, setattr, a, 'klass', None)
501 self.assertRaises(TraitError, setattr, a, 'klass', None)
502 a.klass = C
502 a.klass = C
503 self.assertEqual(a.klass, C)
503 self.assertEqual(a.klass, C)
504
504
505 def test_validate_klass(self):
505 def test_validate_klass(self):
506
506
507 class A(HasTraits):
507 class A(HasTraits):
508 klass = Type('no strings allowed')
508 klass = Type('no strings allowed')
509
509
510 self.assertRaises(ImportError, A)
510 self.assertRaises(ImportError, A)
511
511
512 class A(HasTraits):
512 class A(HasTraits):
513 klass = Type('rub.adub.Duck')
513 klass = Type('rub.adub.Duck')
514
514
515 self.assertRaises(ImportError, A)
515 self.assertRaises(ImportError, A)
516
516
517 def test_validate_default(self):
517 def test_validate_default(self):
518
518
519 class B(object): pass
519 class B(object): pass
520 class A(HasTraits):
520 class A(HasTraits):
521 klass = Type('bad default', B)
521 klass = Type('bad default', B)
522
522
523 self.assertRaises(ImportError, A)
523 self.assertRaises(ImportError, A)
524
524
525 class C(HasTraits):
525 class C(HasTraits):
526 klass = Type(None, B, allow_none=False)
526 klass = Type(None, B, allow_none=False)
527
527
528 self.assertRaises(TraitError, C)
528 self.assertRaises(TraitError, C)
529
529
530 def test_str_klass(self):
530 def test_str_klass(self):
531
531
532 class A(HasTraits):
532 class A(HasTraits):
533 klass = Type('IPython.utils.ipstruct.Struct')
533 klass = Type('IPython.utils.ipstruct.Struct')
534
534
535 from IPython.utils.ipstruct import Struct
535 from IPython.utils.ipstruct import Struct
536 a = A()
536 a = A()
537 a.klass = Struct
537 a.klass = Struct
538 self.assertEqual(a.klass, Struct)
538 self.assertEqual(a.klass, Struct)
539
539
540 self.assertRaises(TraitError, setattr, a, 'klass', 10)
540 self.assertRaises(TraitError, setattr, a, 'klass', 10)
541
541
542 def test_set_str_klass(self):
542 def test_set_str_klass(self):
543
543
544 class A(HasTraits):
544 class A(HasTraits):
545 klass = Type()
545 klass = Type()
546
546
547 a = A(klass='IPython.utils.ipstruct.Struct')
547 a = A(klass='IPython.utils.ipstruct.Struct')
548 from IPython.utils.ipstruct import Struct
548 from IPython.utils.ipstruct import Struct
549 self.assertEqual(a.klass, Struct)
549 self.assertEqual(a.klass, Struct)
550
550
551 class TestInstance(TestCase):
551 class TestInstance(TestCase):
552
552
553 def test_basic(self):
553 def test_basic(self):
554 class Foo(object): pass
554 class Foo(object): pass
555 class Bar(Foo): pass
555 class Bar(Foo): pass
556 class Bah(object): pass
556 class Bah(object): pass
557
557
558 class A(HasTraits):
558 class A(HasTraits):
559 inst = Instance(Foo)
559 inst = Instance(Foo)
560
560
561 a = A()
561 a = A()
562 self.assertTrue(a.inst is None)
562 self.assertTrue(a.inst is None)
563 a.inst = Foo()
563 a.inst = Foo()
564 self.assertTrue(isinstance(a.inst, Foo))
564 self.assertTrue(isinstance(a.inst, Foo))
565 a.inst = Bar()
565 a.inst = Bar()
566 self.assertTrue(isinstance(a.inst, Foo))
566 self.assertTrue(isinstance(a.inst, Foo))
567 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
567 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
568 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
568 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
569 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
569 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
570
570
571 def test_default_klass(self):
571 def test_default_klass(self):
572 class Foo(object): pass
572 class Foo(object): pass
573 class Bar(Foo): pass
573 class Bar(Foo): pass
574 class Bah(object): pass
574 class Bah(object): pass
575
575
576 class FooInstance(Instance):
576 class FooInstance(Instance):
577 klass = Foo
577 klass = Foo
578
578
579 class A(HasTraits):
579 class A(HasTraits):
580 inst = FooInstance()
580 inst = FooInstance()
581
581
582 a = A()
582 a = A()
583 self.assertTrue(a.inst is None)
583 self.assertTrue(a.inst is None)
584 a.inst = Foo()
584 a.inst = Foo()
585 self.assertTrue(isinstance(a.inst, Foo))
585 self.assertTrue(isinstance(a.inst, Foo))
586 a.inst = Bar()
586 a.inst = Bar()
587 self.assertTrue(isinstance(a.inst, Foo))
587 self.assertTrue(isinstance(a.inst, Foo))
588 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
588 self.assertRaises(TraitError, setattr, a, 'inst', Foo)
589 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
589 self.assertRaises(TraitError, setattr, a, 'inst', Bar)
590 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
590 self.assertRaises(TraitError, setattr, a, 'inst', Bah())
591
591
592 def test_unique_default_value(self):
592 def test_unique_default_value(self):
593 class Foo(object): pass
593 class Foo(object): pass
594 class A(HasTraits):
594 class A(HasTraits):
595 inst = Instance(Foo,(),{})
595 inst = Instance(Foo,(),{})
596
596
597 a = A()
597 a = A()
598 b = A()
598 b = A()
599 self.assertTrue(a.inst is not b.inst)
599 self.assertTrue(a.inst is not b.inst)
600
600
601 def test_args_kw(self):
601 def test_args_kw(self):
602 class Foo(object):
602 class Foo(object):
603 def __init__(self, c): self.c = c
603 def __init__(self, c): self.c = c
604 class Bar(object): pass
604 class Bar(object): pass
605 class Bah(object):
605 class Bah(object):
606 def __init__(self, c, d):
606 def __init__(self, c, d):
607 self.c = c; self.d = d
607 self.c = c; self.d = d
608
608
609 class A(HasTraits):
609 class A(HasTraits):
610 inst = Instance(Foo, (10,))
610 inst = Instance(Foo, (10,))
611 a = A()
611 a = A()
612 self.assertEqual(a.inst.c, 10)
612 self.assertEqual(a.inst.c, 10)
613
613
614 class B(HasTraits):
614 class B(HasTraits):
615 inst = Instance(Bah, args=(10,), kw=dict(d=20))
615 inst = Instance(Bah, args=(10,), kw=dict(d=20))
616 b = B()
616 b = B()
617 self.assertEqual(b.inst.c, 10)
617 self.assertEqual(b.inst.c, 10)
618 self.assertEqual(b.inst.d, 20)
618 self.assertEqual(b.inst.d, 20)
619
619
620 class C(HasTraits):
620 class C(HasTraits):
621 inst = Instance(Foo)
621 inst = Instance(Foo)
622 c = C()
622 c = C()
623 self.assertTrue(c.inst is None)
623 self.assertTrue(c.inst is None)
624
624
625 def test_bad_default(self):
625 def test_bad_default(self):
626 class Foo(object): pass
626 class Foo(object): pass
627
627
628 class A(HasTraits):
628 class A(HasTraits):
629 inst = Instance(Foo, allow_none=False)
629 inst = Instance(Foo, allow_none=False)
630
630
631 self.assertRaises(TraitError, A)
631 self.assertRaises(TraitError, A)
632
632
633 def test_instance(self):
633 def test_instance(self):
634 class Foo(object): pass
634 class Foo(object): pass
635
635
636 def inner():
636 def inner():
637 class A(HasTraits):
637 class A(HasTraits):
638 inst = Instance(Foo())
638 inst = Instance(Foo())
639
639
640 self.assertRaises(TraitError, inner)
640 self.assertRaises(TraitError, inner)
641
641
642
642
643 class TestThis(TestCase):
643 class TestThis(TestCase):
644
644
645 def test_this_class(self):
645 def test_this_class(self):
646 class Foo(HasTraits):
646 class Foo(HasTraits):
647 this = This
647 this = This
648
648
649 f = Foo()
649 f = Foo()
650 self.assertEqual(f.this, None)
650 self.assertEqual(f.this, None)
651 g = Foo()
651 g = Foo()
652 f.this = g
652 f.this = g
653 self.assertEqual(f.this, g)
653 self.assertEqual(f.this, g)
654 self.assertRaises(TraitError, setattr, f, 'this', 10)
654 self.assertRaises(TraitError, setattr, f, 'this', 10)
655
655
656 def test_this_inst(self):
656 def test_this_inst(self):
657 class Foo(HasTraits):
657 class Foo(HasTraits):
658 this = This()
658 this = This()
659
659
660 f = Foo()
660 f = Foo()
661 f.this = Foo()
661 f.this = Foo()
662 self.assertTrue(isinstance(f.this, Foo))
662 self.assertTrue(isinstance(f.this, Foo))
663
663
664 def test_subclass(self):
664 def test_subclass(self):
665 class Foo(HasTraits):
665 class Foo(HasTraits):
666 t = This()
666 t = This()
667 class Bar(Foo):
667 class Bar(Foo):
668 pass
668 pass
669 f = Foo()
669 f = Foo()
670 b = Bar()
670 b = Bar()
671 f.t = b
671 f.t = b
672 b.t = f
672 b.t = f
673 self.assertEqual(f.t, b)
673 self.assertEqual(f.t, b)
674 self.assertEqual(b.t, f)
674 self.assertEqual(b.t, f)
675
675
676 def test_subclass_override(self):
676 def test_subclass_override(self):
677 class Foo(HasTraits):
677 class Foo(HasTraits):
678 t = This()
678 t = This()
679 class Bar(Foo):
679 class Bar(Foo):
680 t = This()
680 t = This()
681 f = Foo()
681 f = Foo()
682 b = Bar()
682 b = Bar()
683 f.t = b
683 f.t = b
684 self.assertEqual(f.t, b)
684 self.assertEqual(f.t, b)
685 self.assertRaises(TraitError, setattr, b, 't', f)
685 self.assertRaises(TraitError, setattr, b, 't', f)
686
686
687 def test_this_in_container(self):
687 def test_this_in_container(self):
688
688
689 class Tree(HasTraits):
689 class Tree(HasTraits):
690 value = Unicode()
690 value = Unicode()
691 leaves = List(This())
691 leaves = List(This())
692
692
693 tree = Tree(
693 tree = Tree(
694 value='foo',
694 value='foo',
695 leaves=[Tree('bar'), Tree('buzz')]
695 leaves=[Tree('bar'), Tree('buzz')]
696 )
696 )
697
697
698 with self.assertRaises(TraitError):
698 with self.assertRaises(TraitError):
699 tree.leaves = [1, 2]
699 tree.leaves = [1, 2]
700
700
701 class TraitTestBase(TestCase):
701 class TraitTestBase(TestCase):
702 """A best testing class for basic trait types."""
702 """A best testing class for basic trait types."""
703
703
704 def assign(self, value):
704 def assign(self, value):
705 self.obj.value = value
705 self.obj.value = value
706
706
707 def coerce(self, value):
707 def coerce(self, value):
708 return value
708 return value
709
709
710 def test_good_values(self):
710 def test_good_values(self):
711 if hasattr(self, '_good_values'):
711 if hasattr(self, '_good_values'):
712 for value in self._good_values:
712 for value in self._good_values:
713 self.assign(value)
713 self.assign(value)
714 self.assertEqual(self.obj.value, self.coerce(value))
714 self.assertEqual(self.obj.value, self.coerce(value))
715
715
716 def test_bad_values(self):
716 def test_bad_values(self):
717 if hasattr(self, '_bad_values'):
717 if hasattr(self, '_bad_values'):
718 for value in self._bad_values:
718 for value in self._bad_values:
719 try:
719 try:
720 self.assertRaises(TraitError, self.assign, value)
720 self.assertRaises(TraitError, self.assign, value)
721 except AssertionError:
721 except AssertionError:
722 assert False, value
722 assert False, value
723
723
724 def test_default_value(self):
724 def test_default_value(self):
725 if hasattr(self, '_default_value'):
725 if hasattr(self, '_default_value'):
726 self.assertEqual(self._default_value, self.obj.value)
726 self.assertEqual(self._default_value, self.obj.value)
727
727
728 def test_allow_none(self):
728 def test_allow_none(self):
729 if (hasattr(self, '_bad_values') and hasattr(self, '_good_values') and
729 if (hasattr(self, '_bad_values') and hasattr(self, '_good_values') and
730 None in self._bad_values):
730 None in self._bad_values):
731 trait=self.obj.traits()['value']
731 trait=self.obj.traits()['value']
732 try:
732 try:
733 trait.allow_none = True
733 trait.allow_none = True
734 self._bad_values.remove(None)
734 self._bad_values.remove(None)
735 #skip coerce. Allow None casts None to None.
735 #skip coerce. Allow None casts None to None.
736 self.assign(None)
736 self.assign(None)
737 self.assertEqual(self.obj.value,None)
737 self.assertEqual(self.obj.value,None)
738 self.test_good_values()
738 self.test_good_values()
739 self.test_bad_values()
739 self.test_bad_values()
740 finally:
740 finally:
741 #tear down
741 #tear down
742 trait.allow_none = False
742 trait.allow_none = False
743 self._bad_values.append(None)
743 self._bad_values.append(None)
744
744
745 def tearDown(self):
745 def tearDown(self):
746 # restore default value after tests, if set
746 # restore default value after tests, if set
747 if hasattr(self, '_default_value'):
747 if hasattr(self, '_default_value'):
748 self.obj.value = self._default_value
748 self.obj.value = self._default_value
749
749
750
750
751 class AnyTrait(HasTraits):
751 class AnyTrait(HasTraits):
752
752
753 value = Any
753 value = Any
754
754
755 class AnyTraitTest(TraitTestBase):
755 class AnyTraitTest(TraitTestBase):
756
756
757 obj = AnyTrait()
757 obj = AnyTrait()
758
758
759 _default_value = None
759 _default_value = None
760 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
760 _good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
761 _bad_values = []
761 _bad_values = []
762
762
763
763
764 class IntTrait(HasTraits):
764 class IntTrait(HasTraits):
765
765
766 value = Int(99)
766 value = Int(99)
767
767
768 class TestInt(TraitTestBase):
768 class TestInt(TraitTestBase):
769
769
770 obj = IntTrait()
770 obj = IntTrait()
771 _default_value = 99
771 _default_value = 99
772 _good_values = [10, -10]
772 _good_values = [10, -10]
773 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j,
773 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j,
774 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
774 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
775 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
775 u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
776 if not py3compat.PY3:
776 if not py3compat.PY3:
777 _bad_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
777 _bad_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
778
778
779
779
780 class LongTrait(HasTraits):
780 class LongTrait(HasTraits):
781
781
782 value = Long(99 if py3compat.PY3 else long(99))
782 value = Long(99 if py3compat.PY3 else long(99))
783
783
784 class TestLong(TraitTestBase):
784 class TestLong(TraitTestBase):
785
785
786 obj = LongTrait()
786 obj = LongTrait()
787
787
788 _default_value = 99 if py3compat.PY3 else long(99)
788 _default_value = 99 if py3compat.PY3 else long(99)
789 _good_values = [10, -10]
789 _good_values = [10, -10]
790 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,),
790 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,),
791 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
791 None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
792 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
792 '-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
793 u'-10.1']
793 u'-10.1']
794 if not py3compat.PY3:
794 if not py3compat.PY3:
795 # maxint undefined on py3, because int == long
795 # maxint undefined on py3, because int == long
796 _good_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
796 _good_values.extend([long(10), long(-10), 10*sys.maxint, -10*sys.maxint])
797 _bad_values.extend([[long(10)], (long(10),)])
797 _bad_values.extend([[long(10)], (long(10),)])
798
798
799 @skipif(py3compat.PY3, "not relevant on py3")
799 @skipif(py3compat.PY3, "not relevant on py3")
800 def test_cast_small(self):
800 def test_cast_small(self):
801 """Long casts ints to long"""
801 """Long casts ints to long"""
802 self.obj.value = 10
802 self.obj.value = 10
803 self.assertEqual(type(self.obj.value), long)
803 self.assertEqual(type(self.obj.value), long)
804
804
805
805
806 class IntegerTrait(HasTraits):
806 class IntegerTrait(HasTraits):
807 value = Integer(1)
807 value = Integer(1)
808
808
809 class TestInteger(TestLong):
809 class TestInteger(TestLong):
810 obj = IntegerTrait()
810 obj = IntegerTrait()
811 _default_value = 1
811 _default_value = 1
812
812
813 def coerce(self, n):
813 def coerce(self, n):
814 return int(n)
814 return int(n)
815
815
816 @skipif(py3compat.PY3, "not relevant on py3")
816 @skipif(py3compat.PY3, "not relevant on py3")
817 def test_cast_small(self):
817 def test_cast_small(self):
818 """Integer casts small longs to int"""
818 """Integer casts small longs to int"""
819 if py3compat.PY3:
819 if py3compat.PY3:
820 raise SkipTest("not relevant on py3")
820 raise SkipTest("not relevant on py3")
821
821
822 self.obj.value = long(100)
822 self.obj.value = long(100)
823 self.assertEqual(type(self.obj.value), int)
823 self.assertEqual(type(self.obj.value), int)
824
824
825
825
826 class FloatTrait(HasTraits):
826 class FloatTrait(HasTraits):
827
827
828 value = Float(99.0)
828 value = Float(99.0)
829
829
830 class TestFloat(TraitTestBase):
830 class TestFloat(TraitTestBase):
831
831
832 obj = FloatTrait()
832 obj = FloatTrait()
833
833
834 _default_value = 99.0
834 _default_value = 99.0
835 _good_values = [10, -10, 10.1, -10.1]
835 _good_values = [10, -10, 10.1, -10.1]
836 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None,
836 _bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None,
837 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
837 1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
838 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
838 u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
839 if not py3compat.PY3:
839 if not py3compat.PY3:
840 _bad_values.extend([long(10), long(-10)])
840 _bad_values.extend([long(10), long(-10)])
841
841
842
842
843 class ComplexTrait(HasTraits):
843 class ComplexTrait(HasTraits):
844
844
845 value = Complex(99.0-99.0j)
845 value = Complex(99.0-99.0j)
846
846
847 class TestComplex(TraitTestBase):
847 class TestComplex(TraitTestBase):
848
848
849 obj = ComplexTrait()
849 obj = ComplexTrait()
850
850
851 _default_value = 99.0-99.0j
851 _default_value = 99.0-99.0j
852 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
852 _good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
853 10.1j, 10.1+10.1j, 10.1-10.1j]
853 10.1j, 10.1+10.1j, 10.1-10.1j]
854 _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
854 _bad_values = [u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
855 if not py3compat.PY3:
855 if not py3compat.PY3:
856 _bad_values.extend([long(10), long(-10)])
856 _bad_values.extend([long(10), long(-10)])
857
857
858
858
859 class BytesTrait(HasTraits):
859 class BytesTrait(HasTraits):
860
860
861 value = Bytes(b'string')
861 value = Bytes(b'string')
862
862
863 class TestBytes(TraitTestBase):
863 class TestBytes(TraitTestBase):
864
864
865 obj = BytesTrait()
865 obj = BytesTrait()
866
866
867 _default_value = b'string'
867 _default_value = b'string'
868 _good_values = [b'10', b'-10', b'10L',
868 _good_values = [b'10', b'-10', b'10L',
869 b'-10L', b'10.1', b'-10.1', b'string']
869 b'-10L', b'10.1', b'-10.1', b'string']
870 _bad_values = [10, -10, 10.1, -10.1, 1j, [10],
870 _bad_values = [10, -10, 10.1, -10.1, 1j, [10],
871 ['ten'],{'ten': 10},(10,), None, u'string']
871 ['ten'],{'ten': 10},(10,), None, u'string']
872 if not py3compat.PY3:
872 if not py3compat.PY3:
873 _bad_values.extend([long(10), long(-10)])
873 _bad_values.extend([long(10), long(-10)])
874
874
875
875
876 class UnicodeTrait(HasTraits):
876 class UnicodeTrait(HasTraits):
877
877
878 value = Unicode(u'unicode')
878 value = Unicode(u'unicode')
879
879
880 class TestUnicode(TraitTestBase):
880 class TestUnicode(TraitTestBase):
881
881
882 obj = UnicodeTrait()
882 obj = UnicodeTrait()
883
883
884 _default_value = u'unicode'
884 _default_value = u'unicode'
885 _good_values = ['10', '-10', '10L', '-10L', '10.1',
885 _good_values = ['10', '-10', '10L', '-10L', '10.1',
886 '-10.1', '', u'', 'string', u'string', u"€"]
886 '-10.1', '', u'', 'string', u'string', u"€"]
887 _bad_values = [10, -10, 10.1, -10.1, 1j,
887 _bad_values = [10, -10, 10.1, -10.1, 1j,
888 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
888 [10], ['ten'], [u'ten'], {'ten': 10},(10,), None]
889 if not py3compat.PY3:
889 if not py3compat.PY3:
890 _bad_values.extend([long(10), long(-10)])
890 _bad_values.extend([long(10), long(-10)])
891
891
892
892
893 class ObjectNameTrait(HasTraits):
893 class ObjectNameTrait(HasTraits):
894 value = ObjectName("abc")
894 value = ObjectName("abc")
895
895
896 class TestObjectName(TraitTestBase):
896 class TestObjectName(TraitTestBase):
897 obj = ObjectNameTrait()
897 obj = ObjectNameTrait()
898
898
899 _default_value = "abc"
899 _default_value = "abc"
900 _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
900 _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"]
901 _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
901 _bad_values = [1, "", u"€", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]",
902 None, object(), object]
902 None, object(), object]
903 if sys.version_info[0] < 3:
903 if sys.version_info[0] < 3:
904 _bad_values.append(u"ΓΎ")
904 _bad_values.append(u"ΓΎ")
905 else:
905 else:
906 _good_values.append(u"ΓΎ") # ΓΎ=1 is valid in Python 3 (PEP 3131).
906 _good_values.append(u"ΓΎ") # ΓΎ=1 is valid in Python 3 (PEP 3131).
907
907
908
908
909 class DottedObjectNameTrait(HasTraits):
909 class DottedObjectNameTrait(HasTraits):
910 value = DottedObjectName("a.b")
910 value = DottedObjectName("a.b")
911
911
912 class TestDottedObjectName(TraitTestBase):
912 class TestDottedObjectName(TraitTestBase):
913 obj = DottedObjectNameTrait()
913 obj = DottedObjectNameTrait()
914
914
915 _default_value = "a.b"
915 _default_value = "a.b"
916 _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
916 _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"]
917 _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc.", None]
917 _bad_values = [1, u"abc.€", "_.@", ".", ".abc", "abc.", ".abc.", None]
918 if sys.version_info[0] < 3:
918 if sys.version_info[0] < 3:
919 _bad_values.append(u"t.ΓΎ")
919 _bad_values.append(u"t.ΓΎ")
920 else:
920 else:
921 _good_values.append(u"t.ΓΎ")
921 _good_values.append(u"t.ΓΎ")
922
922
923
923
924 class TCPAddressTrait(HasTraits):
924 class TCPAddressTrait(HasTraits):
925
925
926 value = TCPAddress()
926 value = TCPAddress()
927
927
928 class TestTCPAddress(TraitTestBase):
928 class TestTCPAddress(TraitTestBase):
929
929
930 obj = TCPAddressTrait()
930 obj = TCPAddressTrait()
931
931
932 _default_value = ('127.0.0.1',0)
932 _default_value = ('127.0.0.1',0)
933 _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)]
933 _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)]
934 _bad_values = [(0,0),('localhost',10.0),('localhost',-1), None]
934 _bad_values = [(0,0),('localhost',10.0),('localhost',-1), None]
935
935
936 class ListTrait(HasTraits):
936 class ListTrait(HasTraits):
937
937
938 value = List(Int)
938 value = List(Int)
939
939
940 class TestList(TraitTestBase):
940 class TestList(TraitTestBase):
941
941
942 obj = ListTrait()
942 obj = ListTrait()
943
943
944 _default_value = []
944 _default_value = []
945 _good_values = [[], [1], list(range(10)), (1,2)]
945 _good_values = [[], [1], list(range(10)), (1,2)]
946 _bad_values = [10, [1,'a'], 'a']
946 _bad_values = [10, [1,'a'], 'a']
947
947
948 def coerce(self, value):
948 def coerce(self, value):
949 if value is not None:
949 if value is not None:
950 value = list(value)
950 value = list(value)
951 return value
951 return value
952
952
953 class Foo(object):
953 class Foo(object):
954 pass
954 pass
955
955
956 class InstanceListTrait(HasTraits):
956 class InstanceListTrait(HasTraits):
957
957
958 value = List(Instance(__name__+'.Foo'))
958 value = List(Instance(__name__+'.Foo'))
959
959
960 class TestInstanceList(TraitTestBase):
960 class TestInstanceList(TraitTestBase):
961
961
962 obj = InstanceListTrait()
962 obj = InstanceListTrait()
963
963
964 def test_klass(self):
964 def test_klass(self):
965 """Test that the instance klass is properly assigned."""
965 """Test that the instance klass is properly assigned."""
966 self.assertIs(self.obj.traits()['value']._trait.klass, Foo)
966 self.assertIs(self.obj.traits()['value']._trait.klass, Foo)
967
967
968 _default_value = []
968 _default_value = []
969 _good_values = [[Foo(), Foo(), None], None]
969 _good_values = [[Foo(), Foo(), None], None]
970 _bad_values = [['1', 2,], '1', [Foo]]
970 _bad_values = [['1', 2,], '1', [Foo]]
971
971
972 class ForwardDeclaredInstanceListTrait(HasTraits):
973
974 value = List(ForwardDeclaredInstance('Foo'))
975
976 class TestForwardDeclaredInstanceList(TraitTestBase):
977
978 obj = ForwardDeclaredInstanceListTrait()
979
980 def test_klass(self):
981 """Test that the instance klass is properly assigned."""
982 self.assertIs(self.obj.traits()['value']._trait.klass, Foo)
983
984 _default_value = []
985 _good_values = [[Foo(), Foo(), None], None]
986 _bad_values = [['1', 2,], '1', [Foo]]
987
988
989 class LenListTrait(HasTraits):
972 class LenListTrait(HasTraits):
990
973
991 value = List(Int, [0], minlen=1, maxlen=2)
974 value = List(Int, [0], minlen=1, maxlen=2)
992
975
993 class TestLenList(TraitTestBase):
976 class TestLenList(TraitTestBase):
994
977
995 obj = LenListTrait()
978 obj = LenListTrait()
996
979
997 _default_value = [0]
980 _default_value = [0]
998 _good_values = [[1], [1,2], (1,2)]
981 _good_values = [[1], [1,2], (1,2)]
999 _bad_values = [10, [1,'a'], 'a', [], list(range(3))]
982 _bad_values = [10, [1,'a'], 'a', [], list(range(3))]
1000
983
1001 def coerce(self, value):
984 def coerce(self, value):
1002 if value is not None:
985 if value is not None:
1003 value = list(value)
986 value = list(value)
1004 return value
987 return value
1005
988
1006 class TupleTrait(HasTraits):
989 class TupleTrait(HasTraits):
1007
990
1008 value = Tuple(Int(allow_none=True))
991 value = Tuple(Int(allow_none=True))
1009
992
1010 class TestTupleTrait(TraitTestBase):
993 class TestTupleTrait(TraitTestBase):
1011
994
1012 obj = TupleTrait()
995 obj = TupleTrait()
1013
996
1014 _default_value = None
997 _default_value = None
1015 _good_values = [(1,), None, (0,), [1], (None,)]
998 _good_values = [(1,), None, (0,), [1], (None,)]
1016 _bad_values = [10, (1,2), ('a'), ()]
999 _bad_values = [10, (1,2), ('a'), ()]
1017
1000
1018 def coerce(self, value):
1001 def coerce(self, value):
1019 if value is not None:
1002 if value is not None:
1020 value = tuple(value)
1003 value = tuple(value)
1021 return value
1004 return value
1022
1005
1023 def test_invalid_args(self):
1006 def test_invalid_args(self):
1024 self.assertRaises(TypeError, Tuple, 5)
1007 self.assertRaises(TypeError, Tuple, 5)
1025 self.assertRaises(TypeError, Tuple, default_value='hello')
1008 self.assertRaises(TypeError, Tuple, default_value='hello')
1026 t = Tuple(Int, CBytes, default_value=(1,5))
1009 t = Tuple(Int, CBytes, default_value=(1,5))
1027
1010
1028 class LooseTupleTrait(HasTraits):
1011 class LooseTupleTrait(HasTraits):
1029
1012
1030 value = Tuple((1,2,3))
1013 value = Tuple((1,2,3))
1031
1014
1032 class TestLooseTupleTrait(TraitTestBase):
1015 class TestLooseTupleTrait(TraitTestBase):
1033
1016
1034 obj = LooseTupleTrait()
1017 obj = LooseTupleTrait()
1035
1018
1036 _default_value = (1,2,3)
1019 _default_value = (1,2,3)
1037 _good_values = [(1,), None, [1], (0,), tuple(range(5)), tuple('hello'), ('a',5), ()]
1020 _good_values = [(1,), None, [1], (0,), tuple(range(5)), tuple('hello'), ('a',5), ()]
1038 _bad_values = [10, 'hello', {}]
1021 _bad_values = [10, 'hello', {}]
1039
1022
1040 def coerce(self, value):
1023 def coerce(self, value):
1041 if value is not None:
1024 if value is not None:
1042 value = tuple(value)
1025 value = tuple(value)
1043 return value
1026 return value
1044
1027
1045 def test_invalid_args(self):
1028 def test_invalid_args(self):
1046 self.assertRaises(TypeError, Tuple, 5)
1029 self.assertRaises(TypeError, Tuple, 5)
1047 self.assertRaises(TypeError, Tuple, default_value='hello')
1030 self.assertRaises(TypeError, Tuple, default_value='hello')
1048 t = Tuple(Int, CBytes, default_value=(1,5))
1031 t = Tuple(Int, CBytes, default_value=(1,5))
1049
1032
1050
1033
1051 class MultiTupleTrait(HasTraits):
1034 class MultiTupleTrait(HasTraits):
1052
1035
1053 value = Tuple(Int, Bytes, default_value=[99,b'bottles'])
1036 value = Tuple(Int, Bytes, default_value=[99,b'bottles'])
1054
1037
1055 class TestMultiTuple(TraitTestBase):
1038 class TestMultiTuple(TraitTestBase):
1056
1039
1057 obj = MultiTupleTrait()
1040 obj = MultiTupleTrait()
1058
1041
1059 _default_value = (99,b'bottles')
1042 _default_value = (99,b'bottles')
1060 _good_values = [(1,b'a'), (2,b'b')]
1043 _good_values = [(1,b'a'), (2,b'b')]
1061 _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
1044 _bad_values = ((),10, b'a', (1,b'a',3), (b'a',1), (1, u'a'))
1062
1045
1063 class CRegExpTrait(HasTraits):
1046 class CRegExpTrait(HasTraits):
1064
1047
1065 value = CRegExp(r'')
1048 value = CRegExp(r'')
1066
1049
1067 class TestCRegExp(TraitTestBase):
1050 class TestCRegExp(TraitTestBase):
1068
1051
1069 def coerce(self, value):
1052 def coerce(self, value):
1070 return re.compile(value)
1053 return re.compile(value)
1071
1054
1072 obj = CRegExpTrait()
1055 obj = CRegExpTrait()
1073
1056
1074 _default_value = re.compile(r'')
1057 _default_value = re.compile(r'')
1075 _good_values = [r'\d+', re.compile(r'\d+')]
1058 _good_values = [r'\d+', re.compile(r'\d+')]
1076 _bad_values = ['(', None, ()]
1059 _bad_values = ['(', None, ()]
1077
1060
1078 class DictTrait(HasTraits):
1061 class DictTrait(HasTraits):
1079 value = Dict()
1062 value = Dict()
1080
1063
1081 def test_dict_assignment():
1064 def test_dict_assignment():
1082 d = dict()
1065 d = dict()
1083 c = DictTrait()
1066 c = DictTrait()
1084 c.value = d
1067 c.value = d
1085 d['a'] = 5
1068 d['a'] = 5
1086 nt.assert_equal(d, c.value)
1069 nt.assert_equal(d, c.value)
1087 nt.assert_true(c.value is d)
1070 nt.assert_true(c.value is d)
1088
1071
1089 class TestLink(TestCase):
1072 class TestLink(TestCase):
1090 def test_connect_same(self):
1073 def test_connect_same(self):
1091 """Verify two traitlets of the same type can be linked together using link."""
1074 """Verify two traitlets of the same type can be linked together using link."""
1092
1075
1093 # Create two simple classes with Int traitlets.
1076 # Create two simple classes with Int traitlets.
1094 class A(HasTraits):
1077 class A(HasTraits):
1095 value = Int()
1078 value = Int()
1096 a = A(value=9)
1079 a = A(value=9)
1097 b = A(value=8)
1080 b = A(value=8)
1098
1081
1099 # Conenct the two classes.
1082 # Conenct the two classes.
1100 c = link((a, 'value'), (b, 'value'))
1083 c = link((a, 'value'), (b, 'value'))
1101
1084
1102 # Make sure the values are the same at the point of linking.
1085 # Make sure the values are the same at the point of linking.
1103 self.assertEqual(a.value, b.value)
1086 self.assertEqual(a.value, b.value)
1104
1087
1105 # Change one of the values to make sure they stay in sync.
1088 # Change one of the values to make sure they stay in sync.
1106 a.value = 5
1089 a.value = 5
1107 self.assertEqual(a.value, b.value)
1090 self.assertEqual(a.value, b.value)
1108 b.value = 6
1091 b.value = 6
1109 self.assertEqual(a.value, b.value)
1092 self.assertEqual(a.value, b.value)
1110
1093
1111 def test_link_different(self):
1094 def test_link_different(self):
1112 """Verify two traitlets of different types can be linked together using link."""
1095 """Verify two traitlets of different types can be linked together using link."""
1113
1096
1114 # Create two simple classes with Int traitlets.
1097 # Create two simple classes with Int traitlets.
1115 class A(HasTraits):
1098 class A(HasTraits):
1116 value = Int()
1099 value = Int()
1117 class B(HasTraits):
1100 class B(HasTraits):
1118 count = Int()
1101 count = Int()
1119 a = A(value=9)
1102 a = A(value=9)
1120 b = B(count=8)
1103 b = B(count=8)
1121
1104
1122 # Conenct the two classes.
1105 # Conenct the two classes.
1123 c = link((a, 'value'), (b, 'count'))
1106 c = link((a, 'value'), (b, 'count'))
1124
1107
1125 # Make sure the values are the same at the point of linking.
1108 # Make sure the values are the same at the point of linking.
1126 self.assertEqual(a.value, b.count)
1109 self.assertEqual(a.value, b.count)
1127
1110
1128 # Change one of the values to make sure they stay in sync.
1111 # Change one of the values to make sure they stay in sync.
1129 a.value = 5
1112 a.value = 5
1130 self.assertEqual(a.value, b.count)
1113 self.assertEqual(a.value, b.count)
1131 b.count = 4
1114 b.count = 4
1132 self.assertEqual(a.value, b.count)
1115 self.assertEqual(a.value, b.count)
1133
1116
1134 def test_unlink(self):
1117 def test_unlink(self):
1135 """Verify two linked traitlets can be unlinked."""
1118 """Verify two linked traitlets can be unlinked."""
1136
1119
1137 # Create two simple classes with Int traitlets.
1120 # Create two simple classes with Int traitlets.
1138 class A(HasTraits):
1121 class A(HasTraits):
1139 value = Int()
1122 value = Int()
1140 a = A(value=9)
1123 a = A(value=9)
1141 b = A(value=8)
1124 b = A(value=8)
1142
1125
1143 # Connect the two classes.
1126 # Connect the two classes.
1144 c = link((a, 'value'), (b, 'value'))
1127 c = link((a, 'value'), (b, 'value'))
1145 a.value = 4
1128 a.value = 4
1146 c.unlink()
1129 c.unlink()
1147
1130
1148 # Change one of the values to make sure they don't stay in sync.
1131 # Change one of the values to make sure they don't stay in sync.
1149 a.value = 5
1132 a.value = 5
1150 self.assertNotEqual(a.value, b.value)
1133 self.assertNotEqual(a.value, b.value)
1151
1134
1152 def test_callbacks(self):
1135 def test_callbacks(self):
1153 """Verify two linked traitlets have their callbacks called once."""
1136 """Verify two linked traitlets have their callbacks called once."""
1154
1137
1155 # Create two simple classes with Int traitlets.
1138 # Create two simple classes with Int traitlets.
1156 class A(HasTraits):
1139 class A(HasTraits):
1157 value = Int()
1140 value = Int()
1158 class B(HasTraits):
1141 class B(HasTraits):
1159 count = Int()
1142 count = Int()
1160 a = A(value=9)
1143 a = A(value=9)
1161 b = B(count=8)
1144 b = B(count=8)
1162
1145
1163 # Register callbacks that count.
1146 # Register callbacks that count.
1164 callback_count = []
1147 callback_count = []
1165 def a_callback(name, old, new):
1148 def a_callback(name, old, new):
1166 callback_count.append('a')
1149 callback_count.append('a')
1167 a.on_trait_change(a_callback, 'value')
1150 a.on_trait_change(a_callback, 'value')
1168 def b_callback(name, old, new):
1151 def b_callback(name, old, new):
1169 callback_count.append('b')
1152 callback_count.append('b')
1170 b.on_trait_change(b_callback, 'count')
1153 b.on_trait_change(b_callback, 'count')
1171
1154
1172 # Connect the two classes.
1155 # Connect the two classes.
1173 c = link((a, 'value'), (b, 'count'))
1156 c = link((a, 'value'), (b, 'count'))
1174
1157
1175 # Make sure b's count was set to a's value once.
1158 # Make sure b's count was set to a's value once.
1176 self.assertEqual(''.join(callback_count), 'b')
1159 self.assertEqual(''.join(callback_count), 'b')
1177 del callback_count[:]
1160 del callback_count[:]
1178
1161
1179 # Make sure a's value was set to b's count once.
1162 # Make sure a's value was set to b's count once.
1180 b.count = 5
1163 b.count = 5
1181 self.assertEqual(''.join(callback_count), 'ba')
1164 self.assertEqual(''.join(callback_count), 'ba')
1182 del callback_count[:]
1165 del callback_count[:]
1183
1166
1184 # Make sure b's count was set to a's value once.
1167 # Make sure b's count was set to a's value once.
1185 a.value = 4
1168 a.value = 4
1186 self.assertEqual(''.join(callback_count), 'ab')
1169 self.assertEqual(''.join(callback_count), 'ab')
1187 del callback_count[:]
1170 del callback_count[:]
1188
1171
1189 class TestDirectionalLink(TestCase):
1172 class TestDirectionalLink(TestCase):
1190 def test_connect_same(self):
1173 def test_connect_same(self):
1191 """Verify two traitlets of the same type can be linked together using directional_link."""
1174 """Verify two traitlets of the same type can be linked together using directional_link."""
1192
1175
1193 # Create two simple classes with Int traitlets.
1176 # Create two simple classes with Int traitlets.
1194 class A(HasTraits):
1177 class A(HasTraits):
1195 value = Int()
1178 value = Int()
1196 a = A(value=9)
1179 a = A(value=9)
1197 b = A(value=8)
1180 b = A(value=8)
1198
1181
1199 # Conenct the two classes.
1182 # Conenct the two classes.
1200 c = directional_link((a, 'value'), (b, 'value'))
1183 c = directional_link((a, 'value'), (b, 'value'))
1201
1184
1202 # Make sure the values are the same at the point of linking.
1185 # Make sure the values are the same at the point of linking.
1203 self.assertEqual(a.value, b.value)
1186 self.assertEqual(a.value, b.value)
1204
1187
1205 # Change one the value of the source and check that it synchronizes the target.
1188 # Change one the value of the source and check that it synchronizes the target.
1206 a.value = 5
1189 a.value = 5
1207 self.assertEqual(b.value, 5)
1190 self.assertEqual(b.value, 5)
1208 # Change one the value of the target and check that it has no impact on the source
1191 # Change one the value of the target and check that it has no impact on the source
1209 b.value = 6
1192 b.value = 6
1210 self.assertEqual(a.value, 5)
1193 self.assertEqual(a.value, 5)
1211
1194
1212 def test_link_different(self):
1195 def test_link_different(self):
1213 """Verify two traitlets of different types can be linked together using link."""
1196 """Verify two traitlets of different types can be linked together using link."""
1214
1197
1215 # Create two simple classes with Int traitlets.
1198 # Create two simple classes with Int traitlets.
1216 class A(HasTraits):
1199 class A(HasTraits):
1217 value = Int()
1200 value = Int()
1218 class B(HasTraits):
1201 class B(HasTraits):
1219 count = Int()
1202 count = Int()
1220 a = A(value=9)
1203 a = A(value=9)
1221 b = B(count=8)
1204 b = B(count=8)
1222
1205
1223 # Conenct the two classes.
1206 # Conenct the two classes.
1224 c = directional_link((a, 'value'), (b, 'count'))
1207 c = directional_link((a, 'value'), (b, 'count'))
1225
1208
1226 # Make sure the values are the same at the point of linking.
1209 # Make sure the values are the same at the point of linking.
1227 self.assertEqual(a.value, b.count)
1210 self.assertEqual(a.value, b.count)
1228
1211
1229 # Change one the value of the source and check that it synchronizes the target.
1212 # Change one the value of the source and check that it synchronizes the target.
1230 a.value = 5
1213 a.value = 5
1231 self.assertEqual(b.count, 5)
1214 self.assertEqual(b.count, 5)
1232 # Change one the value of the target and check that it has no impact on the source
1215 # Change one the value of the target and check that it has no impact on the source
1233 b.value = 6
1216 b.value = 6
1234 self.assertEqual(a.value, 5)
1217 self.assertEqual(a.value, 5)
1235
1218
1236 def test_unlink(self):
1219 def test_unlink(self):
1237 """Verify two linked traitlets can be unlinked."""
1220 """Verify two linked traitlets can be unlinked."""
1238
1221
1239 # Create two simple classes with Int traitlets.
1222 # Create two simple classes with Int traitlets.
1240 class A(HasTraits):
1223 class A(HasTraits):
1241 value = Int()
1224 value = Int()
1242 a = A(value=9)
1225 a = A(value=9)
1243 b = A(value=8)
1226 b = A(value=8)
1244
1227
1245 # Connect the two classes.
1228 # Connect the two classes.
1246 c = directional_link((a, 'value'), (b, 'value'))
1229 c = directional_link((a, 'value'), (b, 'value'))
1247 a.value = 4
1230 a.value = 4
1248 c.unlink()
1231 c.unlink()
1249
1232
1250 # Change one of the values to make sure they don't stay in sync.
1233 # Change one of the values to make sure they don't stay in sync.
1251 a.value = 5
1234 a.value = 5
1252 self.assertNotEqual(a.value, b.value)
1235 self.assertNotEqual(a.value, b.value)
1253
1236
1254 class Pickleable(HasTraits):
1237 class Pickleable(HasTraits):
1255 i = Int()
1238 i = Int()
1256 j = Int()
1239 j = Int()
1257
1240
1258 def _i_default(self):
1241 def _i_default(self):
1259 return 1
1242 return 1
1260
1243
1261 def _i_changed(self, name, old, new):
1244 def _i_changed(self, name, old, new):
1262 self.j = new
1245 self.j = new
1263
1246
1264 def test_pickle_hastraits():
1247 def test_pickle_hastraits():
1265 c = Pickleable()
1248 c = Pickleable()
1266 for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
1249 for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
1267 p = pickle.dumps(c, protocol)
1250 p = pickle.dumps(c, protocol)
1268 c2 = pickle.loads(p)
1251 c2 = pickle.loads(p)
1269 nt.assert_equal(c2.i, c.i)
1252 nt.assert_equal(c2.i, c.i)
1270 nt.assert_equal(c2.j, c.j)
1253 nt.assert_equal(c2.j, c.j)
1271
1254
1272 c.i = 5
1255 c.i = 5
1273 for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
1256 for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
1274 p = pickle.dumps(c, protocol)
1257 p = pickle.dumps(c, protocol)
1275 c2 = pickle.loads(p)
1258 c2 = pickle.loads(p)
1276 nt.assert_equal(c2.i, c.i)
1259 nt.assert_equal(c2.i, c.i)
1277 nt.assert_equal(c2.j, c.j)
1260 nt.assert_equal(c2.j, c.j)
1278
1261
1279 class TestEventful(TestCase):
1262 class TestEventful(TestCase):
1280
1263
1281 def test_list(self):
1264 def test_list(self):
1282 """Does the EventfulList work?"""
1265 """Does the EventfulList work?"""
1283 event_cache = []
1266 event_cache = []
1284
1267
1285 class A(HasTraits):
1268 class A(HasTraits):
1286 x = EventfulList([c for c in 'abc'])
1269 x = EventfulList([c for c in 'abc'])
1287 a = A()
1270 a = A()
1288 a.x.on_events(lambda i, x: event_cache.append('insert'), \
1271 a.x.on_events(lambda i, x: event_cache.append('insert'), \
1289 lambda i, x: event_cache.append('set'), \
1272 lambda i, x: event_cache.append('set'), \
1290 lambda i: event_cache.append('del'), \
1273 lambda i: event_cache.append('del'), \
1291 lambda: event_cache.append('reverse'), \
1274 lambda: event_cache.append('reverse'), \
1292 lambda *p, **k: event_cache.append('sort'))
1275 lambda *p, **k: event_cache.append('sort'))
1293
1276
1294 a.x.remove('c')
1277 a.x.remove('c')
1295 # ab
1278 # ab
1296 a.x.insert(0, 'z')
1279 a.x.insert(0, 'z')
1297 # zab
1280 # zab
1298 del a.x[1]
1281 del a.x[1]
1299 # zb
1282 # zb
1300 a.x.reverse()
1283 a.x.reverse()
1301 # bz
1284 # bz
1302 a.x[1] = 'o'
1285 a.x[1] = 'o'
1303 # bo
1286 # bo
1304 a.x.append('a')
1287 a.x.append('a')
1305 # boa
1288 # boa
1306 a.x.sort()
1289 a.x.sort()
1307 # abo
1290 # abo
1308
1291
1309 # Were the correct events captured?
1292 # Were the correct events captured?
1310 self.assertEqual(event_cache, ['del', 'insert', 'del', 'reverse', 'set', 'set', 'sort'])
1293 self.assertEqual(event_cache, ['del', 'insert', 'del', 'reverse', 'set', 'set', 'sort'])
1311
1294
1312 # Is the output correct?
1295 # Is the output correct?
1313 self.assertEqual(a.x, [c for c in 'abo'])
1296 self.assertEqual(a.x, [c for c in 'abo'])
1314
1297
1315 def test_dict(self):
1298 def test_dict(self):
1316 """Does the EventfulDict work?"""
1299 """Does the EventfulDict work?"""
1317 event_cache = []
1300 event_cache = []
1318
1301
1319 class A(HasTraits):
1302 class A(HasTraits):
1320 x = EventfulDict({c: c for c in 'abc'})
1303 x = EventfulDict({c: c for c in 'abc'})
1321 a = A()
1304 a = A()
1322 a.x.on_events(lambda k, v: event_cache.append('add'), \
1305 a.x.on_events(lambda k, v: event_cache.append('add'), \
1323 lambda k, v: event_cache.append('set'), \
1306 lambda k, v: event_cache.append('set'), \
1324 lambda k: event_cache.append('del'))
1307 lambda k: event_cache.append('del'))
1325
1308
1326 del a.x['c']
1309 del a.x['c']
1327 # ab
1310 # ab
1328 a.x['z'] = 1
1311 a.x['z'] = 1
1329 # abz
1312 # abz
1330 a.x['z'] = 'z'
1313 a.x['z'] = 'z'
1331 # abz
1314 # abz
1332 a.x.pop('a')
1315 a.x.pop('a')
1333 # bz
1316 # bz
1334
1317
1335 # Were the correct events captured?
1318 # Were the correct events captured?
1336 self.assertEqual(event_cache, ['del', 'add', 'set', 'del'])
1319 self.assertEqual(event_cache, ['del', 'add', 'set', 'del'])
1337
1320
1338 # Is the output correct?
1321 # Is the output correct?
1339 self.assertEqual(a.x, {c: c for c in 'bz'})
1322 self.assertEqual(a.x, {c: c for c in 'bz'})
1340
1323
1324 ###
1325 # Traits for Forward Declaration Tests
1326 ###
1327 class ForwardDeclaredInstanceTrait(HasTraits):
1328
1329 value = ForwardDeclaredInstance(klass='ForwardDeclaredBar')
1330
1331 class ForwardDeclaredTypeTrait(HasTraits):
1332
1333 value = ForwardDeclaredType(klass='ForwardDeclaredBar')
1334
1335 class ForwardDeclaredInstanceListTrait(HasTraits):
1336
1337 value = List(ForwardDeclaredInstance('ForwardDeclaredBar'))
1341
1338
1339 class ForwardDeclaredTypeListTrait(HasTraits):
1340
1341 value = List(ForwardDeclaredType('ForwardDeclaredBar'))
1342 ###
1343 # End Traits for Forward Declaration Tests
1344 ###
1345
1346 ###
1347 # Classes for Forward Declaration Tests
1348 ###
1342 class ForwardDeclaredBar(object):
1349 class ForwardDeclaredBar(object):
1343 pass
1350 pass
1344
1351
1345 class ForwardDeclaredBarSub(ForwardDeclaredBar):
1352 class ForwardDeclaredBarSub(ForwardDeclaredBar):
1346 pass
1353 pass
1354 ###
1355 # End Classes for Forward Declaration Tests
1356 ###
1347
1357
1348 class ForwardDeclaredInstanceTrait(HasTraits):
1358 ###
1349
1359 # Forward Declaration Tests
1350 value = ForwardDeclaredInstance(klass='ForwardDeclaredBar')
1360 ###
1351
1352 class TestForwardDeclaredInstanceTrait(TraitTestBase):
1361 class TestForwardDeclaredInstanceTrait(TraitTestBase):
1353
1362
1354 obj = ForwardDeclaredInstanceTrait()
1363 obj = ForwardDeclaredInstanceTrait()
1355 _default_value = None
1364 _default_value = None
1356 _good_values = [None, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
1365 _good_values = [None, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
1357 _bad_values = ['foo', 3, ForwardDeclaredBar, ForwardDeclaredBarSub]
1366 _bad_values = ['foo', 3, ForwardDeclaredBar, ForwardDeclaredBarSub]
1358
1367
1359
1360 class ForwardDeclaredTypeTrait(HasTraits):
1361
1362 value = ForwardDeclaredType(klass='ForwardDeclaredBar')
1363
1364 class TestForwardDeclaredInstanceTrait(TraitTestBase):
1368 class TestForwardDeclaredInstanceTrait(TraitTestBase):
1365
1369
1366 obj = ForwardDeclaredTypeTrait()
1370 obj = ForwardDeclaredTypeTrait()
1367 _default_value = None
1371 _default_value = None
1368 _good_values = [None, ForwardDeclaredBar, ForwardDeclaredBarSub]
1372 _good_values = [None, ForwardDeclaredBar, ForwardDeclaredBarSub]
1369 _bad_values = ['foo', 3, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
1373 _bad_values = ['foo', 3, ForwardDeclaredBar(), ForwardDeclaredBarSub()]
1374
1375 class TestForwardDeclaredInstanceList(TraitTestBase):
1376
1377 obj = ForwardDeclaredInstanceListTrait()
1378
1379 def test_klass(self):
1380 """Test that the instance klass is properly assigned."""
1381 self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar)
1382
1383 _default_value = []
1384 _good_values = [
1385 [ForwardDeclaredBar(), ForwardDeclaredBarSub(), None],
1386 [None],
1387 [],
1388 None,
1389 ]
1390 _bad_values = [
1391 ForwardDeclaredBar(),
1392 [ForwardDeclaredBar(), 3],
1393 '1',
1394 # Note that this is the type, not an instance.
1395 [ForwardDeclaredBar]
1396 ]
1397
1398 class TestForwardDeclaredTypeList(TraitTestBase):
1399
1400 obj = ForwardDeclaredTypeListTrait()
1401
1402 def test_klass(self):
1403 """Test that the instance klass is properly assigned."""
1404 self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar)
1405
1406 _default_value = []
1407 _good_values = [
1408 [ForwardDeclaredBar, ForwardDeclaredBarSub, None],
1409 [],
1410 [None],
1411 None,
1412 ]
1413 _bad_values = [
1414 ForwardDeclaredBar,
1415 [ForwardDeclaredBar, 3],
1416 '1',
1417 # Note that this is an instance, not the type.
1418 [ForwardDeclaredBar()]
1419 ]
1420 ###
1421 # End Forward Declaration Tests
1422 ###
General Comments 0
You need to be logged in to leave comments. Login now