##// END OF EJS Templates
undo failed changes...
MinRK -
Show More
@@ -1,465 +1,465 b''
1 """Test interact and interactive."""
1 """Test interact and interactive."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2014 The IPython Development Team
4 # Copyright (C) 2014 The IPython Development Team
5 #
5 #
6 # Distributed under the terms of the BSD License. The full license is in
6 # Distributed under the terms of the BSD License. The full license is in
7 # the file COPYING, distributed as part of this software.
7 # the file COPYING, distributed as part of this software.
8 #-----------------------------------------------------------------------------
8 #-----------------------------------------------------------------------------
9
9
10 #-----------------------------------------------------------------------------
10 #-----------------------------------------------------------------------------
11 # Imports
11 # Imports
12 #-----------------------------------------------------------------------------
12 #-----------------------------------------------------------------------------
13
13
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 from collections import OrderedDict
16 from collections import OrderedDict
17
17
18 import nose.tools as nt
18 import nose.tools as nt
19 import IPython.testing.tools as tt
19 import IPython.testing.tools as tt
20
20
21 # from IPython.core.getipython import get_ipython
21 # from IPython.core.getipython import get_ipython
22 from IPython.html import widgets
22 from IPython.html import widgets
23 from IPython.html.widgets import interact, interactive, Widget, interaction
23 from IPython.html.widgets import interact, interactive, Widget, interaction
24 from IPython.utils.py3compat import annotate
24 from IPython.utils.py3compat import annotate
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Utility stuff
27 # Utility stuff
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 class DummyComm(object):
30 class DummyComm(object):
31 comm_id = 'a-b-c-d'
31 comm_id = 'a-b-c-d'
32 def send(self, *args, **kwargs):
32 def send(self, *args, **kwargs):
33 pass
33 pass
34
34
35 def close(self, *args, **kwargs):
35 def close(self, *args, **kwargs):
36 pass
36 pass
37
37
38 _widget_attrs = {}
38 _widget_attrs = {}
39 displayed = []
39 displayed = []
40
40
41 def setup():
41 def setup():
42 _widget_attrs['comm'] = Widget.comm
42 _widget_attrs['comm'] = Widget.comm
43 Widget.comm = DummyComm()
43 Widget.comm = DummyComm()
44 _widget_attrs['_ipython_display_'] = Widget._ipython_display_
44 _widget_attrs['_ipython_display_'] = Widget._ipython_display_
45 def raise_not_implemented(*args, **kwargs):
45 def raise_not_implemented(*args, **kwargs):
46 raise NotImplementedError()
46 raise NotImplementedError()
47 Widget._ipython_display_ = raise_not_implemented
47 Widget._ipython_display_ = raise_not_implemented
48
48
49 def teardown():
49 def teardown():
50 for attr, value in _widget_attrs.items():
50 for attr, value in _widget_attrs.items():
51 setattr(Widget, attr, value)
51 setattr(Widget, attr, value)
52
52
53 def f(**kwargs):
53 def f(**kwargs):
54 pass
54 pass
55
55
56 def clear_display():
56 def clear_display():
57 global displayed
57 global displayed
58 displayed = []
58 displayed = []
59
59
60 def record_display(*args):
60 def record_display(*args):
61 displayed.extend(args)
61 displayed.extend(args)
62
62
63 #-----------------------------------------------------------------------------
63 #-----------------------------------------------------------------------------
64 # Actual tests
64 # Actual tests
65 #-----------------------------------------------------------------------------
65 #-----------------------------------------------------------------------------
66
66
67 def check_widget(w, **d):
67 def check_widget(w, **d):
68 """Check a single widget against a dict"""
68 """Check a single widget against a dict"""
69 for attr, expected in d.items():
69 for attr, expected in d.items():
70 if attr == 'cls':
70 if attr == 'cls':
71 nt.assert_is(w.__class__, expected)
71 nt.assert_is(w.__class__, expected)
72 else:
72 else:
73 value = getattr(w, attr)
73 value = getattr(w, attr)
74 nt.assert_equal(value, expected,
74 nt.assert_equal(value, expected,
75 "%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected)
75 "%s.%s = %r != %r" % (w.__class__.__name__, attr, value, expected)
76 )
76 )
77
77
78 def check_widgets(container, **to_check):
78 def check_widgets(container, **to_check):
79 """Check that widgets are created as expected"""
79 """Check that widgets are created as expected"""
80 # build a widget dictionary, so it matches
80 # build a widget dictionary, so it matches
81 widgets = {}
81 widgets = {}
82 for w in container.children:
82 for w in container.children:
83 widgets[w.description] = w
83 widgets[w.description] = w
84
84
85 for key, d in to_check.items():
85 for key, d in to_check.items():
86 nt.assert_in(key, widgets)
86 nt.assert_in(key, widgets)
87 check_widget(widgets[key], **d)
87 check_widget(widgets[key], **d)
88
88
89
89
90 def test_single_value_string():
90 def test_single_value_string():
91 a = u'hello'
91 a = u'hello'
92 c = interactive(f, a=a)
92 c = interactive(f, a=a)
93 w = c.children[0]
93 w = c.children[0]
94 check_widget(w,
94 check_widget(w,
95 cls=widgets.TextWidget,
95 cls=widgets.TextWidget,
96 description='a',
96 description='a',
97 value=a,
97 value=a,
98 )
98 )
99
99
100 def test_single_value_bool():
100 def test_single_value_bool():
101 for a in (True, False):
101 for a in (True, False):
102 c = interactive(f, a=a)
102 c = interactive(f, a=a)
103 w = c.children[0]
103 w = c.children[0]
104 check_widget(w,
104 check_widget(w,
105 cls=widgets.CheckboxWidget,
105 cls=widgets.CheckboxWidget,
106 description='a',
106 description='a',
107 value=a,
107 value=a,
108 )
108 )
109
109
110 def test_single_value_dict():
110 def test_single_value_dict():
111 for d in [
111 for d in [
112 dict(a=5),
112 dict(a=5),
113 dict(a=5, b='b', c=dict),
113 dict(a=5, b='b', c=dict),
114 ]:
114 ]:
115 c = interactive(f, d=d)
115 c = interactive(f, d=d)
116 w = c.children[0]
116 w = c.children[0]
117 check_widget(w,
117 check_widget(w,
118 cls=widgets.DropdownWidget,
118 cls=widgets.DropdownWidget,
119 description='d',
119 description='d',
120 values=d,
120 values=d,
121 value=next(iter(d.values())),
121 value=next(iter(d.values())),
122 )
122 )
123
123
124 def test_single_value_float():
124 def test_single_value_float():
125 for a in (2.25, 1.0, -3.5):
125 for a in (2.25, 1.0, -3.5):
126 c = interactive(f, a=a)
126 c = interactive(f, a=a)
127 w = c.children[0]
127 w = c.children[0]
128 check_widget(w,
128 check_widget(w,
129 cls=widgets.FloatSliderWidget,
129 cls=widgets.FloatSliderWidget,
130 description='a',
130 description='a',
131 value=a,
131 value=a,
132 min= -a if a > 0 else 3*a,
132 min= -a if a > 0 else 3*a,
133 max= 3*a if a > 0 else -a,
133 max= 3*a if a > 0 else -a,
134 step=0.1,
134 step=0.1,
135 readout=True,
135 readout=True,
136 )
136 )
137
137
138 def test_single_value_int():
138 def test_single_value_int():
139 for a in (1, 5, -3):
139 for a in (1, 5, -3):
140 c = interactive(f, a=a)
140 c = interactive(f, a=a)
141 nt.assert_equal(len(c.children), 1)
141 nt.assert_equal(len(c.children), 1)
142 w = c.children[0]
142 w = c.children[0]
143 check_widget(w,
143 check_widget(w,
144 cls=widgets.IntSliderWidget,
144 cls=widgets.IntSliderWidget,
145 description='a',
145 description='a',
146 value=a,
146 value=a,
147 min= -a if a > 0 else 3*a,
147 min= -a if a > 0 else 3*a,
148 max= 3*a if a > 0 else -a,
148 max= 3*a if a > 0 else -a,
149 step=1,
149 step=1,
150 readout=True,
150 readout=True,
151 )
151 )
152
152
153 def test_list_tuple_2_int():
153 def test_list_tuple_2_int():
154 with nt.assert_raises(ValueError):
154 with nt.assert_raises(ValueError):
155 c = interactive(f, tup=(1,1))
155 c = interactive(f, tup=(1,1))
156 with nt.assert_raises(ValueError):
156 with nt.assert_raises(ValueError):
157 c = interactive(f, tup=(1,-1))
157 c = interactive(f, tup=(1,-1))
158 for min, max in [ (0,1), (1,10), (1,2), (-5,5), (-20,-19) ]:
158 for min, max in [ (0,1), (1,10), (1,2), (-5,5), (-20,-19) ]:
159 c = interactive(f, tup=(min, max), lis=[min, max])
159 c = interactive(f, tup=(min, max), lis=[min, max])
160 nt.assert_equal(len(c.children), 2)
160 nt.assert_equal(len(c.children), 2)
161 d = dict(
161 d = dict(
162 cls=widgets.IntSliderWidget,
162 cls=widgets.IntSliderWidget,
163 min=min,
163 min=min,
164 max=max,
164 max=max,
165 step=1,
165 step=1,
166 readout=True,
166 readout=True,
167 )
167 )
168 check_widgets(c, tup=d, lis=d)
168 check_widgets(c, tup=d, lis=d)
169
169
170 def test_list_tuple_3_int():
170 def test_list_tuple_3_int():
171 with nt.assert_raises(ValueError):
171 with nt.assert_raises(ValueError):
172 c = interactive(f, tup=(1,2,0))
172 c = interactive(f, tup=(1,2,0))
173 with nt.assert_raises(ValueError):
173 with nt.assert_raises(ValueError):
174 c = interactive(f, tup=(1,2,-1))
174 c = interactive(f, tup=(1,2,-1))
175 for min, max, step in [ (0,2,1), (1,10,2), (1,100,2), (-5,5,4), (-100,-20,4) ]:
175 for min, max, step in [ (0,2,1), (1,10,2), (1,100,2), (-5,5,4), (-100,-20,4) ]:
176 c = interactive(f, tup=(min, max, step), lis=[min, max, step])
176 c = interactive(f, tup=(min, max, step), lis=[min, max, step])
177 nt.assert_equal(len(c.children), 2)
177 nt.assert_equal(len(c.children), 2)
178 d = dict(
178 d = dict(
179 cls=widgets.IntSliderWidget,
179 cls=widgets.IntSliderWidget,
180 min=min,
180 min=min,
181 max=max,
181 max=max,
182 step=step,
182 step=step,
183 readout=True,
183 readout=True,
184 )
184 )
185 check_widgets(c, tup=d, lis=d)
185 check_widgets(c, tup=d, lis=d)
186
186
187 def test_list_tuple_2_float():
187 def test_list_tuple_2_float():
188 with nt.assert_raises(ValueError):
188 with nt.assert_raises(ValueError):
189 c = interactive(f, tup=(1.0,1.0))
189 c = interactive(f, tup=(1.0,1.0))
190 with nt.assert_raises(ValueError):
190 with nt.assert_raises(ValueError):
191 c = interactive(f, tup=(0.5,-0.5))
191 c = interactive(f, tup=(0.5,-0.5))
192 for min, max in [ (0.5, 1.5), (1.1,10.2), (1,2.2), (-5.,5), (-20,-19.) ]:
192 for min, max in [ (0.5, 1.5), (1.1,10.2), (1,2.2), (-5.,5), (-20,-19.) ]:
193 c = interactive(f, tup=(min, max), lis=[min, max])
193 c = interactive(f, tup=(min, max), lis=[min, max])
194 nt.assert_equal(len(c.children), 2)
194 nt.assert_equal(len(c.children), 2)
195 d = dict(
195 d = dict(
196 cls=widgets.FloatSliderWidget,
196 cls=widgets.FloatSliderWidget,
197 min=min,
197 min=min,
198 max=max,
198 max=max,
199 step=.1,
199 step=.1,
200 readout=True,
200 readout=True,
201 )
201 )
202 check_widgets(c, tup=d, lis=d)
202 check_widgets(c, tup=d, lis=d)
203
203
204 def test_list_tuple_3_float():
204 def test_list_tuple_3_float():
205 with nt.assert_raises(ValueError):
205 with nt.assert_raises(ValueError):
206 c = interactive(f, tup=(1,2,0.0))
206 c = interactive(f, tup=(1,2,0.0))
207 with nt.assert_raises(ValueError):
207 with nt.assert_raises(ValueError):
208 c = interactive(f, tup=(-1,-2,1.))
208 c = interactive(f, tup=(-1,-2,1.))
209 with nt.assert_raises(ValueError):
209 with nt.assert_raises(ValueError):
210 c = interactive(f, tup=(1,2.,-1.))
210 c = interactive(f, tup=(1,2.,-1.))
211 for min, max, step in [ (0.,2,1), (1,10.,2), (1,100,2.), (-5.,5.,4), (-100,-20.,4.) ]:
211 for min, max, step in [ (0.,2,1), (1,10.,2), (1,100,2.), (-5.,5.,4), (-100,-20.,4.) ]:
212 c = interactive(f, tup=(min, max, step), lis=[min, max, step])
212 c = interactive(f, tup=(min, max, step), lis=[min, max, step])
213 nt.assert_equal(len(c.children), 2)
213 nt.assert_equal(len(c.children), 2)
214 d = dict(
214 d = dict(
215 cls=widgets.FloatSliderWidget,
215 cls=widgets.FloatSliderWidget,
216 min=min,
216 min=min,
217 max=max,
217 max=max,
218 step=step,
218 step=step,
219 readout=True,
219 readout=True,
220 )
220 )
221 check_widgets(c, tup=d, lis=d)
221 check_widgets(c, tup=d, lis=d)
222
222
223 def test_list_tuple_str():
223 def test_list_tuple_str():
224 values = ['hello', 'there', 'guy']
224 values = ['hello', 'there', 'guy']
225 first = values[0]
225 first = values[0]
226 dvalues = OrderedDict((v,v) for v in values)
226 dvalues = OrderedDict((v,v) for v in values)
227 c = interactive(f, tup=tuple(values), lis=list(values))
227 c = interactive(f, tup=tuple(values), lis=list(values))
228 nt.assert_equal(len(c.children), 2)
228 nt.assert_equal(len(c.children), 2)
229 d = dict(
229 d = dict(
230 cls=widgets.DropdownWidget,
230 cls=widgets.DropdownWidget,
231 value=first,
231 value=first,
232 values=dvalues
232 values=dvalues
233 )
233 )
234 check_widgets(c, tup=d, lis=d)
234 check_widgets(c, tup=d, lis=d)
235
235
236 def test_list_tuple_invalid():
236 def test_list_tuple_invalid():
237 for bad in [
237 for bad in [
238 (),
238 (),
239 (5, 'hi'),
239 (5, 'hi'),
240 ('hi', 5),
240 ('hi', 5),
241 ({},),
241 ({},),
242 (None,),
242 (None,),
243 ]:
243 ]:
244 with nt.assert_raises(ValueError):
244 with nt.assert_raises(ValueError):
245 print(bad) # because there is no custom message in assert_raises
245 print(bad) # because there is no custom message in assert_raises
246 c = interactive(f, tup=bad)
246 c = interactive(f, tup=bad)
247
247
248 def test_defaults():
248 def test_defaults():
249 @annotate(n=10)
249 @annotate(n=10)
250 def f(n, f=4.5, g=1):
250 def f(n, f=4.5, g=1):
251 pass
251 pass
252
252
253 c = interactive(f)
253 c = interactive(f)
254 check_widgets(c,
254 check_widgets(c,
255 n=dict(
255 n=dict(
256 cls=widgets.IntSliderWidget,
256 cls=widgets.IntSliderWidget,
257 value=10,
257 value=10,
258 ),
258 ),
259 f=dict(
259 f=dict(
260 cls=widgets.FloatSliderWidget,
260 cls=widgets.FloatSliderWidget,
261 value=4.5,
261 value=4.5,
262 ),
262 ),
263 g=dict(
263 g=dict(
264 cls=widgets.IntSliderWidget,
264 cls=widgets.IntSliderWidget,
265 value=1,
265 value=1,
266 ),
266 ),
267 )
267 )
268
268
269 def test_default_values():
269 def test_default_values():
270 @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there'])
270 @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there'])
271 def f(n, f=4.5, g=1, h=2, j='there'):
271 def f(n, f=4.5, g=1, h=2, j='there'):
272 pass
272 pass
273
273
274 c = interactive(f)
274 c = interactive(f)
275 check_widgets(c,
275 check_widgets(c,
276 n=dict(
276 n=dict(
277 cls=widgets.IntSliderWidget,
277 cls=widgets.IntSliderWidget,
278 value=10,
278 value=10,
279 ),
279 ),
280 f=dict(
280 f=dict(
281 cls=widgets.FloatSliderWidget,
281 cls=widgets.FloatSliderWidget,
282 value=4.5,
282 value=4.5,
283 ),
283 ),
284 g=dict(
284 g=dict(
285 cls=widgets.IntSliderWidget,
285 cls=widgets.IntSliderWidget,
286 value=5,
286 value=5,
287 ),
287 ),
288 h=dict(
288 h=dict(
289 cls=widgets.DropdownWidget,
289 cls=widgets.DropdownWidget,
290 values={'a': 1, 'b': 2},
290 values={'a': 1, 'b': 2},
291 value=2
291 value=2
292 ),
292 ),
293 j=dict(
293 j=dict(
294 cls=widgets.DropdownWidget,
294 cls=widgets.DropdownWidget,
295 values={'hi':'hi', 'there':'there'},
295 values={'hi':'hi', 'there':'there'},
296 value='there'
296 value='there'
297 ),
297 ),
298 )
298 )
299
299
300 def test_default_out_of_bounds():
300 def test_default_out_of_bounds():
301 @annotate(f=(0, 10.), h={'a': 1, 'b': 2}, j=['hi', 'there'])
301 @annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there'])
302 def f(f='hi', h=5, j='other'):
302 def f(f='hi', h=5, j='other'):
303 pass
303 pass
304
304
305 c = interactive(f)
305 c = interactive(f)
306 check_widgets(c,
306 check_widgets(c,
307 f=dict(
307 f=dict(
308 cls=widgets.FloatSliderWidget,
308 cls=widgets.FloatSliderWidget,
309 value=5.,
309 value=5.,
310 ),
310 ),
311 h=dict(
311 h=dict(
312 cls=widgets.DropdownWidget,
312 cls=widgets.DropdownWidget,
313 values={'a': 1, 'b': 2},
313 values={'a': 1},
314 value=1
314 value=1,
315 ),
315 ),
316 j=dict(
316 j=dict(
317 cls=widgets.DropdownWidget,
317 cls=widgets.DropdownWidget,
318 values={'hi':'hi', 'there':'there'},
318 values={'hi':'hi', 'there':'there'},
319 value='hi'
319 value='hi',
320 ),
320 ),
321 )
321 )
322
322
323 def test_annotations():
323 def test_annotations():
324 @annotate(n=10, f=widgets.FloatTextWidget())
324 @annotate(n=10, f=widgets.FloatTextWidget())
325 def f(n, f):
325 def f(n, f):
326 pass
326 pass
327
327
328 c = interactive(f)
328 c = interactive(f)
329 check_widgets(c,
329 check_widgets(c,
330 n=dict(
330 n=dict(
331 cls=widgets.IntSliderWidget,
331 cls=widgets.IntSliderWidget,
332 value=10,
332 value=10,
333 ),
333 ),
334 f=dict(
334 f=dict(
335 cls=widgets.FloatTextWidget,
335 cls=widgets.FloatTextWidget,
336 ),
336 ),
337 )
337 )
338
338
339 def test_priority():
339 def test_priority():
340 @annotate(annotate='annotate', kwarg='annotate')
340 @annotate(annotate='annotate', kwarg='annotate')
341 def f(kwarg='default', annotate='default', default='default'):
341 def f(kwarg='default', annotate='default', default='default'):
342 pass
342 pass
343
343
344 c = interactive(f, kwarg='kwarg')
344 c = interactive(f, kwarg='kwarg')
345 check_widgets(c,
345 check_widgets(c,
346 kwarg=dict(
346 kwarg=dict(
347 cls=widgets.TextWidget,
347 cls=widgets.TextWidget,
348 value='kwarg',
348 value='kwarg',
349 ),
349 ),
350 annotate=dict(
350 annotate=dict(
351 cls=widgets.TextWidget,
351 cls=widgets.TextWidget,
352 value='annotate',
352 value='annotate',
353 ),
353 ),
354 )
354 )
355
355
356 @nt.with_setup(clear_display)
356 @nt.with_setup(clear_display)
357 def test_decorator_kwarg():
357 def test_decorator_kwarg():
358 with tt.monkeypatch(interaction, 'display', record_display):
358 with tt.monkeypatch(interaction, 'display', record_display):
359 @interact(a=5)
359 @interact(a=5)
360 def foo(a):
360 def foo(a):
361 pass
361 pass
362 nt.assert_equal(len(displayed), 1)
362 nt.assert_equal(len(displayed), 1)
363 w = displayed[0].children[0]
363 w = displayed[0].children[0]
364 check_widget(w,
364 check_widget(w,
365 cls=widgets.IntSliderWidget,
365 cls=widgets.IntSliderWidget,
366 value=5,
366 value=5,
367 )
367 )
368
368
369 @nt.with_setup(clear_display)
369 @nt.with_setup(clear_display)
370 def test_decorator_no_call():
370 def test_decorator_no_call():
371 with tt.monkeypatch(interaction, 'display', record_display):
371 with tt.monkeypatch(interaction, 'display', record_display):
372 @interact
372 @interact
373 def foo(a='default'):
373 def foo(a='default'):
374 pass
374 pass
375 nt.assert_equal(len(displayed), 1)
375 nt.assert_equal(len(displayed), 1)
376 w = displayed[0].children[0]
376 w = displayed[0].children[0]
377 check_widget(w,
377 check_widget(w,
378 cls=widgets.TextWidget,
378 cls=widgets.TextWidget,
379 value='default',
379 value='default',
380 )
380 )
381
381
382 @nt.with_setup(clear_display)
382 @nt.with_setup(clear_display)
383 def test_call_interact():
383 def test_call_interact():
384 def foo(a='default'):
384 def foo(a='default'):
385 pass
385 pass
386 with tt.monkeypatch(interaction, 'display', record_display):
386 with tt.monkeypatch(interaction, 'display', record_display):
387 ifoo = interact(foo)
387 ifoo = interact(foo)
388 nt.assert_equal(len(displayed), 1)
388 nt.assert_equal(len(displayed), 1)
389 w = displayed[0].children[0]
389 w = displayed[0].children[0]
390 check_widget(w,
390 check_widget(w,
391 cls=widgets.TextWidget,
391 cls=widgets.TextWidget,
392 value='default',
392 value='default',
393 )
393 )
394
394
395 @nt.with_setup(clear_display)
395 @nt.with_setup(clear_display)
396 def test_call_interact_kwargs():
396 def test_call_interact_kwargs():
397 def foo(a='default'):
397 def foo(a='default'):
398 pass
398 pass
399 with tt.monkeypatch(interaction, 'display', record_display):
399 with tt.monkeypatch(interaction, 'display', record_display):
400 ifoo = interact(foo, a=10)
400 ifoo = interact(foo, a=10)
401 nt.assert_equal(len(displayed), 1)
401 nt.assert_equal(len(displayed), 1)
402 w = displayed[0].children[0]
402 w = displayed[0].children[0]
403 check_widget(w,
403 check_widget(w,
404 cls=widgets.IntSliderWidget,
404 cls=widgets.IntSliderWidget,
405 value=10,
405 value=10,
406 )
406 )
407
407
408 @nt.with_setup(clear_display)
408 @nt.with_setup(clear_display)
409 def test_call_decorated_on_trait_change():
409 def test_call_decorated_on_trait_change():
410 """test calling @interact decorated functions"""
410 """test calling @interact decorated functions"""
411 d = {}
411 d = {}
412 with tt.monkeypatch(interaction, 'display', record_display):
412 with tt.monkeypatch(interaction, 'display', record_display):
413 @interact
413 @interact
414 def foo(a='default'):
414 def foo(a='default'):
415 d['a'] = a
415 d['a'] = a
416 return a
416 return a
417 nt.assert_equal(len(displayed), 1)
417 nt.assert_equal(len(displayed), 1)
418 w = displayed[0].children[0]
418 w = displayed[0].children[0]
419 check_widget(w,
419 check_widget(w,
420 cls=widgets.TextWidget,
420 cls=widgets.TextWidget,
421 value='default',
421 value='default',
422 )
422 )
423 # test calling the function directly
423 # test calling the function directly
424 a = foo('hello')
424 a = foo('hello')
425 nt.assert_equal(a, 'hello')
425 nt.assert_equal(a, 'hello')
426 nt.assert_equal(d['a'], 'hello')
426 nt.assert_equal(d['a'], 'hello')
427
427
428 # test that setting trait values calls the function
428 # test that setting trait values calls the function
429 w.value = 'called'
429 w.value = 'called'
430 nt.assert_equal(d['a'], 'called')
430 nt.assert_equal(d['a'], 'called')
431
431
432 @nt.with_setup(clear_display)
432 @nt.with_setup(clear_display)
433 def test_call_decorated_kwargs_on_trait_change():
433 def test_call_decorated_kwargs_on_trait_change():
434 """test calling @interact(foo=bar) decorated functions"""
434 """test calling @interact(foo=bar) decorated functions"""
435 d = {}
435 d = {}
436 with tt.monkeypatch(interaction, 'display', record_display):
436 with tt.monkeypatch(interaction, 'display', record_display):
437 @interact(a='kwarg')
437 @interact(a='kwarg')
438 def foo(a='default'):
438 def foo(a='default'):
439 d['a'] = a
439 d['a'] = a
440 return a
440 return a
441 nt.assert_equal(len(displayed), 1)
441 nt.assert_equal(len(displayed), 1)
442 w = displayed[0].children[0]
442 w = displayed[0].children[0]
443 check_widget(w,
443 check_widget(w,
444 cls=widgets.TextWidget,
444 cls=widgets.TextWidget,
445 value='kwarg',
445 value='kwarg',
446 )
446 )
447 # test calling the function directly
447 # test calling the function directly
448 a = foo('hello')
448 a = foo('hello')
449 nt.assert_equal(a, 'hello')
449 nt.assert_equal(a, 'hello')
450 nt.assert_equal(d['a'], 'hello')
450 nt.assert_equal(d['a'], 'hello')
451
451
452 # test that setting trait values calls the function
452 # test that setting trait values calls the function
453 w.value = 'called'
453 w.value = 'called'
454 nt.assert_equal(d['a'], 'called')
454 nt.assert_equal(d['a'], 'called')
455
455
456 def test_fixed():
456 def test_fixed():
457 c = interactive(f, a=widgets.fixed(5), b='text')
457 c = interactive(f, a=widgets.fixed(5), b='text')
458 nt.assert_equal(len(c.children), 1)
458 nt.assert_equal(len(c.children), 1)
459 w = c.children[0]
459 w = c.children[0]
460 check_widget(w,
460 check_widget(w,
461 cls=widgets.TextWidget,
461 cls=widgets.TextWidget,
462 value='text',
462 value='text',
463 description='b',
463 description='b',
464 )
464 )
465
465
@@ -1,119 +1,121 b''
1 """SelectionWidget classes.
1 """SelectionWidget classes.
2
2
3 Represents an enumeration using a widget.
3 Represents an enumeration using a widget.
4 """
4 """
5 #-----------------------------------------------------------------------------
5 #-----------------------------------------------------------------------------
6 # Copyright (c) 2013, the IPython Development Team.
6 # Copyright (c) 2013, the IPython Development Team.
7 #
7 #
8 # Distributed under the terms of the Modified BSD License.
8 # Distributed under the terms of the Modified BSD License.
9 #
9 #
10 # The full license is in the file COPYING.txt, distributed with this software.
10 # The full license is in the file COPYING.txt, distributed with this software.
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12
12
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 # Imports
14 # Imports
15 #-----------------------------------------------------------------------------
15 #-----------------------------------------------------------------------------
16
16
17 from collections import OrderedDict
17 from collections import OrderedDict
18 from threading import Lock
18 from threading import Lock
19
19
20 from .widget import DOMWidget
20 from .widget import DOMWidget
21 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
21 from IPython.utils.traitlets import Unicode, List, Bool, Any, Dict, TraitError
22 from IPython.utils.py3compat import unicode_type
22 from IPython.utils.py3compat import unicode_type
23
23
24 #-----------------------------------------------------------------------------
24 #-----------------------------------------------------------------------------
25 # SelectionWidget
25 # SelectionWidget
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 class _SelectionWidget(DOMWidget):
27 class _SelectionWidget(DOMWidget):
28 """Base class for Selection widgets
28 """Base class for Selection widgets
29
29
30 ``values`` can be specified as a list or dict. If given as a list,
30 ``values`` can be specified as a list or dict. If given as a list,
31 it will be transformed to a dict of the form ``{str(value):value}``.
31 it will be transformed to a dict of the form ``{str(value):value}``.
32 """
32 """
33
33
34 value = Any(help="Selected value")
34 value = Any(help="Selected value")
35 values = Dict(help="""Dictionary of {name: value} the user can select.
35 values = Dict(help="""Dictionary of {name: value} the user can select.
36
36
37 The keys of this dictionary are the strings that will be displayed in the UI,
37 The keys of this dictionary are the strings that will be displayed in the UI,
38 representing the actual Python choices.
38 representing the actual Python choices.
39
39
40 The keys of this dictionary are also available as value_names.
40 The keys of this dictionary are also available as value_names.
41 """)
41 """)
42 value_name = Unicode(help="The name of the selected value", sync=True)
42 value_name = Unicode(help="The name of the selected value", sync=True)
43 value_names = List(Unicode, help="""Read-only list of names for each value.
43 value_names = List(Unicode, help="""Read-only list of names for each value.
44
44
45 If values is specified as a list, this is the string representation of each element.
45 If values is specified as a list, this is the string representation of each element.
46 Otherwise, it is the keys of the values dictionary.
46 Otherwise, it is the keys of the values dictionary.
47
47
48 These strings are used to display the choices in the front-end.""", sync=True)
48 These strings are used to display the choices in the front-end.""", sync=True)
49 disabled = Bool(False, help="Enable or disable user changes", sync=True)
49 disabled = Bool(False, help="Enable or disable user changes", sync=True)
50 description = Unicode(help="Description of the value this widget represents", sync=True)
50 description = Unicode(help="Description of the value this widget represents", sync=True)
51
51
52
52
53 def __init__(self, *args, **kwargs):
53 def __init__(self, *args, **kwargs):
54 self.value_lock = Lock()
54 self.value_lock = Lock()
55 self._in_values_changed = False
55 self._in_values_changed = False
56 if 'values' in kwargs:
56 if 'values' in kwargs:
57 values = kwargs['values']
57 values = kwargs['values']
58 # convert list values to an dict of {str(v):v}
58 # convert list values to an dict of {str(v):v}
59 if isinstance(values, list):
59 if isinstance(values, list):
60 # preserve list order with an OrderedDict
60 # preserve list order with an OrderedDict
61 kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values)
61 kwargs['values'] = OrderedDict((unicode_type(v), v) for v in values)
62 DOMWidget.__init__(self, *args, **kwargs)
62 DOMWidget.__init__(self, *args, **kwargs)
63
63
64 def _values_changed(self, name, old, new):
64 def _values_changed(self, name, old, new):
65 """Handles when the values dict has been changed.
65 """Handles when the values dict has been changed.
66
66
67 Setting values implies setting value names from the keys of the dict.
67 Setting values implies setting value names from the keys of the dict.
68 """
68 """
69 self._in_values_changed = True
69 self._in_values_changed = True
70 try:
70 try:
71 self.value_names = list(new.keys())
71 self.value_names = list(new.keys())
72 finally:
72 finally:
73 self._in_values_changed = False
73 self._in_values_changed = False
74
74
75 # ensure that the chosen value is one of the choices
75 # ensure that the chosen value is one of the choices
76 if self.value not in new.values():
76 if self.value not in new.values():
77 self.value = next(iter(new.values()))
77 self.value = next(iter(new.values()))
78
78
79 def _value_names_changed(self, name, old, new):
79 def _value_names_changed(self, name, old, new):
80 if not self._in_values_changed:
80 if not self._in_values_changed:
81 raise TraitError("value_names is a read-only proxy to values.keys(). Use the values dict instead.")
81 raise TraitError("value_names is a read-only proxy to values.keys(). Use the values dict instead.")
82
82
83 def _value_changed(self, name, old, new):
83 def _value_changed(self, name, old, new):
84 """Called when value has been changed"""
84 """Called when value has been changed"""
85 if self.value_lock.acquire(False):
85 if self.value_lock.acquire(False):
86 try:
86 try:
87 # Reverse dictionary lookup for the value name
87 # Reverse dictionary lookup for the value name
88 for k,v in self.values.items():
88 for k,v in self.values.items():
89 if new == v:
89 if new == v:
90 # set the selected value name
90 # set the selected value name
91 self.value_name = k
91 self.value_name = k
92 return
92 return
93 # undo the change, and raise KeyError
94 self.value = old
93 raise KeyError(new)
95 raise KeyError(new)
94 finally:
96 finally:
95 self.value_lock.release()
97 self.value_lock.release()
96
98
97 def _value_name_changed(self, name, old, new):
99 def _value_name_changed(self, name, old, new):
98 """Called when the value name has been changed (typically by the frontend)."""
100 """Called when the value name has been changed (typically by the frontend)."""
99 if self.value_lock.acquire(False):
101 if self.value_lock.acquire(False):
100 try:
102 try:
101 self.value = self.values[new]
103 self.value = self.values[new]
102 finally:
104 finally:
103 self.value_lock.release()
105 self.value_lock.release()
104
106
105
107
106 class ToggleButtonsWidget(_SelectionWidget):
108 class ToggleButtonsWidget(_SelectionWidget):
107 _view_name = Unicode('ToggleButtonsView', sync=True)
109 _view_name = Unicode('ToggleButtonsView', sync=True)
108
110
109
111
110 class DropdownWidget(_SelectionWidget):
112 class DropdownWidget(_SelectionWidget):
111 _view_name = Unicode('DropdownView', sync=True)
113 _view_name = Unicode('DropdownView', sync=True)
112
114
113
115
114 class RadioButtonsWidget(_SelectionWidget):
116 class RadioButtonsWidget(_SelectionWidget):
115 _view_name = Unicode('RadioButtonsView', sync=True)
117 _view_name = Unicode('RadioButtonsView', sync=True)
116
118
117
119
118 class SelectWidget(_SelectionWidget):
120 class SelectWidget(_SelectionWidget):
119 _view_name = Unicode('SelectView', sync=True)
121 _view_name = Unicode('SelectView', sync=True)
General Comments 0
You need to be logged in to leave comments. Login now