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