##// END OF EJS Templates
Add a number of extra tests for the range widgets
Gordon Ball -
Show More
@@ -1,504 +1,591 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 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 313 values={'a': 1},
314 314 value=1,
315 315 ),
316 316 j=dict(
317 317 cls=widgets.DropdownWidget,
318 318 values={'hi':'hi', 'there':'there'},
319 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
466 466 def test_default_description():
467 467 c = interactive(f, b='text')
468 468 w = c.children[0]
469 469 check_widget(w,
470 470 cls=widgets.TextWidget,
471 471 value='text',
472 472 description='b',
473 473 )
474 474
475 475 def test_custom_description():
476 476 c = interactive(f, b=widgets.TextWidget(value='text', description='foo'))
477 477 w = c.children[0]
478 478 check_widget(w,
479 479 cls=widgets.TextWidget,
480 480 value='text',
481 481 description='foo',
482 482 )
483 483
484 484 def test_int_range_logic():
485 485 irsw = widgets.IntRangeSliderWidget
486 486 w = irsw(value=(2, 4), min=0, max=6)
487 487 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
488 488 w.value = (4, 2)
489 489 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
490 w.value = (-1, 7)
491 check_widget(w, cls=irsw, value=(0, 6), min=0, max=6)
490 492 w.min = 3
491 check_widget(w, cls=irsw, value=(3, 4), min=3, max=6)
493 check_widget(w, cls=irsw, value=(3, 6), min=3, max=6)
492 494 w.max = 3
493 495 check_widget(w, cls=irsw, value=(3, 3), min=3, max=3)
496
497 w.min = 0
498 w.max = 6
499 w.lower = 2
500 w.upper = 4
501 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
502 w.value = (0, 1) #lower non-overlapping range
503 check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
504 w.value = (5, 6) #upper non-overlapping range
505 check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
506 w.value = (-1, 4) #semi out-of-range
507 check_widget(w, cls=irsw, value=(0, 4), min=0, max=6)
508 w.lower = 2
509 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
510 w.value = (-2, -1) #wholly out of range
511 check_widget(w, cls=irsw, value=(0, 0), min=0, max=6)
512 w.value = (7, 8)
513 check_widget(w, cls=irsw, value=(6, 6), min=0, max=6)
514
515 with nt.assert_raises(ValueError):
516 w.min = 7
517 with nt.assert_raises(ValueError):
518 w.max = -1
519 with nt.assert_raises(ValueError):
520 w.lower = 5
521 with nt.assert_raises(ValueError):
522 w.upper = 1
523
524 w = irsw(lower=5, min=0, max=6)
525 check_widget(w, lower=5)
526 w = irsw(upper=1, min=0, max=6)
527 check_widget(w, upper=1)
528
529 with nt.assert_raises(ValueError):
530 irsw(value=(2, 4), lower=3)
531 with nt.assert_raises(ValueError):
532 irsw(value=(2, 4), upper=3)
533 with nt.assert_raises(ValueError):
534 irsw(value=(2, 4), lower=3, upper=3)
535 with nt.assert_raises(ValueError):
536 irsw(min=2, max=1)
537
494 538
495 539 def test_float_range_logic():
496 540 frsw = widgets.FloatRangeSliderWidget
497 541 w = frsw(value=(.2, .4), min=0., max=.6)
498 542 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
499 543 w.value = (.4, .2)
500 544 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
545 w.value = (-.1, .7)
546 check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6)
501 547 w.min = .3
502 check_widget(w, cls=frsw, value=(.3, .4), min=.3, max=.6)
548 check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6)
503 549 w.max = .3
504 550 check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3)
551
552 w.min = 0.
553 w.max = .6
554 w.lower = .2
555 w.upper = .4
556 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
557 w.value = (0., .1) #lower non-overlapping range
558 check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
559 w.value = (.5, .6) #upper non-overlapping range
560 check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
561 w.value = (-.1, .4) #semi out-of-range
562 check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6)
563 w.lower = .2
564 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
565 w.value = (-.2, -.1) #wholly out of range
566 check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6)
567 w.value = (.7, .8)
568 check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6)
569
570 with nt.assert_raises(ValueError):
571 w.min = .7
572 with nt.assert_raises(ValueError):
573 w.max = -.1
574 with nt.assert_raises(ValueError):
575 w.lower = .5
576 with nt.assert_raises(ValueError):
577 w.upper = .1
578
579 w = frsw(lower=.5, min=0., max=.6)
580 check_widget(w, lower=.5)
581 w = frsw(upper=.1, min=0., max=.6)
582 check_widget(w, upper=.1)
583
584 with nt.assert_raises(ValueError):
585 frsw(value=(2, 4), lower=3)
586 with nt.assert_raises(ValueError):
587 frsw(value=(2, 4), upper=3)
588 with nt.assert_raises(ValueError):
589 frsw(value=(2, 4), lower=3, upper=3)
590 with nt.assert_raises(ValueError):
591 frsw(min=.2, max=.1) No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now