##// END OF EJS Templates
Change from on_demand kwarg to interact_choose function
Gordon Ball -
Show More
@@ -1,23 +1,23 b''
1 from .widget import Widget, DOMWidget, CallbackDispatcher
1 from .widget import Widget, DOMWidget, CallbackDispatcher
2
2
3 from .widget_bool import Checkbox, ToggleButton
3 from .widget_bool import Checkbox, ToggleButton
4 from .widget_button import Button
4 from .widget_button import Button
5 from .widget_box import Box, Popup, FlexBox, HBox, VBox
5 from .widget_box import Box, Popup, FlexBox, HBox, VBox
6 from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider
6 from .widget_float import FloatText, BoundedFloatText, FloatSlider, FloatProgress, FloatRangeSlider
7 from .widget_image import Image
7 from .widget_image import Image
8 from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
8 from .widget_int import IntText, BoundedIntText, IntSlider, IntProgress, IntRangeSlider
9 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
9 from .widget_selection import RadioButtons, ToggleButtons, Dropdown, Select
10 from .widget_selectioncontainer import Tab, Accordion
10 from .widget_selectioncontainer import Tab, Accordion
11 from .widget_string import HTML, Latex, Text, Textarea
11 from .widget_string import HTML, Latex, Text, Textarea
12 from .interaction import interact, interactive, fixed
12 from .interaction import interact, interactive, fixed, interact_choose
13
13
14 # Deprecated classes
14 # Deprecated classes
15 from .widget_bool import CheckboxWidget, ToggleButtonWidget
15 from .widget_bool import CheckboxWidget, ToggleButtonWidget
16 from .widget_button import ButtonWidget
16 from .widget_button import ButtonWidget
17 from .widget_box import ContainerWidget, PopupWidget
17 from .widget_box import ContainerWidget, PopupWidget
18 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
18 from .widget_float import FloatTextWidget, BoundedFloatTextWidget, FloatSliderWidget, FloatProgressWidget
19 from .widget_image import ImageWidget
19 from .widget_image import ImageWidget
20 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
20 from .widget_int import IntTextWidget, BoundedIntTextWidget, IntSliderWidget, IntProgressWidget
21 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
21 from .widget_selection import RadioButtonsWidget, ToggleButtonsWidget, DropdownWidget, SelectWidget
22 from .widget_selectioncontainer import TabWidget, AccordionWidget
22 from .widget_selectioncontainer import TabWidget, AccordionWidget
23 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
23 from .widget_string import HTMLWidget, LatexWidget, TextWidget, TextareaWidget
@@ -1,274 +1,284 b''
1 """Interact with functions using widgets."""
1 """Interact with functions using widgets."""
2
2
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 from __future__ import print_function
15 from __future__ import print_function
16
16
17 try: # Python >= 3.3
17 try: # Python >= 3.3
18 from inspect import signature, Parameter
18 from inspect import signature, Parameter
19 except ImportError:
19 except ImportError:
20 from IPython.utils.signatures import signature, Parameter
20 from IPython.utils.signatures import signature, Parameter
21 from inspect import getcallargs
21 from inspect import getcallargs
22
22
23 from IPython.core.getipython import get_ipython
23 from IPython.core.getipython import get_ipython
24 from IPython.html.widgets import (Widget, Text,
24 from IPython.html.widgets import (Widget, Text,
25 FloatSlider, IntSlider, Checkbox, Dropdown,
25 FloatSlider, IntSlider, Checkbox, Dropdown,
26 Box, Button, DOMWidget)
26 Box, Button, DOMWidget)
27 from IPython.display import display, clear_output
27 from IPython.display import display, clear_output
28 from IPython.utils.py3compat import string_types, unicode_type
28 from IPython.utils.py3compat import string_types, unicode_type
29 from IPython.utils.traitlets import HasTraits, Any, Unicode
29 from IPython.utils.traitlets import HasTraits, Any, Unicode
30
30
31 empty = Parameter.empty
31 empty = Parameter.empty
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Classes and Functions
34 # Classes and Functions
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37
37
38 def _matches(o, pattern):
38 def _matches(o, pattern):
39 """Match a pattern of types in a sequence."""
39 """Match a pattern of types in a sequence."""
40 if not len(o) == len(pattern):
40 if not len(o) == len(pattern):
41 return False
41 return False
42 comps = zip(o,pattern)
42 comps = zip(o,pattern)
43 return all(isinstance(obj,kind) for obj,kind in comps)
43 return all(isinstance(obj,kind) for obj,kind in comps)
44
44
45
45
46 def _get_min_max_value(min, max, value=None, step=None):
46 def _get_min_max_value(min, max, value=None, step=None):
47 """Return min, max, value given input values with possible None."""
47 """Return min, max, value given input values with possible None."""
48 if value is None:
48 if value is None:
49 if not max > min:
49 if not max > min:
50 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
50 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
51 value = min + abs(min-max)/2
51 value = min + abs(min-max)/2
52 value = type(min)(value)
52 value = type(min)(value)
53 elif min is None and max is None:
53 elif min is None and max is None:
54 if value == 0.0:
54 if value == 0.0:
55 min, max, value = 0.0, 1.0, 0.5
55 min, max, value = 0.0, 1.0, 0.5
56 elif value == 0:
56 elif value == 0:
57 min, max, value = 0, 1, 0
57 min, max, value = 0, 1, 0
58 elif isinstance(value, (int, float)):
58 elif isinstance(value, (int, float)):
59 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
59 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
60 else:
60 else:
61 raise TypeError('expected a number, got: %r' % value)
61 raise TypeError('expected a number, got: %r' % value)
62 else:
62 else:
63 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
63 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
64 if step is not None:
64 if step is not None:
65 # ensure value is on a step
65 # ensure value is on a step
66 r = (value - min) % step
66 r = (value - min) % step
67 value = value - r
67 value = value - r
68 return min, max, value
68 return min, max, value
69
69
70 def _widget_abbrev_single_value(o):
70 def _widget_abbrev_single_value(o):
71 """Make widgets from single values, which can be used as parameter defaults."""
71 """Make widgets from single values, which can be used as parameter defaults."""
72 if isinstance(o, string_types):
72 if isinstance(o, string_types):
73 return Text(value=unicode_type(o))
73 return Text(value=unicode_type(o))
74 elif isinstance(o, dict):
74 elif isinstance(o, dict):
75 return Dropdown(values=o)
75 return Dropdown(values=o)
76 elif isinstance(o, bool):
76 elif isinstance(o, bool):
77 return Checkbox(value=o)
77 return Checkbox(value=o)
78 elif isinstance(o, float):
78 elif isinstance(o, float):
79 min, max, value = _get_min_max_value(None, None, o)
79 min, max, value = _get_min_max_value(None, None, o)
80 return FloatSlider(value=o, min=min, max=max)
80 return FloatSlider(value=o, min=min, max=max)
81 elif isinstance(o, int):
81 elif isinstance(o, int):
82 min, max, value = _get_min_max_value(None, None, o)
82 min, max, value = _get_min_max_value(None, None, o)
83 return IntSlider(value=o, min=min, max=max)
83 return IntSlider(value=o, min=min, max=max)
84 else:
84 else:
85 return None
85 return None
86
86
87 def _widget_abbrev(o):
87 def _widget_abbrev(o):
88 """Make widgets from abbreviations: single values, lists or tuples."""
88 """Make widgets from abbreviations: single values, lists or tuples."""
89 float_or_int = (float, int)
89 float_or_int = (float, int)
90 if isinstance(o, (list, tuple)):
90 if isinstance(o, (list, tuple)):
91 if o and all(isinstance(x, string_types) for x in o):
91 if o and all(isinstance(x, string_types) for x in o):
92 return Dropdown(values=[unicode_type(k) for k in o])
92 return Dropdown(values=[unicode_type(k) for k in o])
93 elif _matches(o, (float_or_int, float_or_int)):
93 elif _matches(o, (float_or_int, float_or_int)):
94 min, max, value = _get_min_max_value(o[0], o[1])
94 min, max, value = _get_min_max_value(o[0], o[1])
95 if all(isinstance(_, int) for _ in o):
95 if all(isinstance(_, int) for _ in o):
96 cls = IntSlider
96 cls = IntSlider
97 else:
97 else:
98 cls = FloatSlider
98 cls = FloatSlider
99 return cls(value=value, min=min, max=max)
99 return cls(value=value, min=min, max=max)
100 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
100 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
101 step = o[2]
101 step = o[2]
102 if step <= 0:
102 if step <= 0:
103 raise ValueError("step must be >= 0, not %r" % step)
103 raise ValueError("step must be >= 0, not %r" % step)
104 min, max, value = _get_min_max_value(o[0], o[1], step=step)
104 min, max, value = _get_min_max_value(o[0], o[1], step=step)
105 if all(isinstance(_, int) for _ in o):
105 if all(isinstance(_, int) for _ in o):
106 cls = IntSlider
106 cls = IntSlider
107 else:
107 else:
108 cls = FloatSlider
108 cls = FloatSlider
109 return cls(value=value, min=min, max=max, step=step)
109 return cls(value=value, min=min, max=max, step=step)
110 else:
110 else:
111 return _widget_abbrev_single_value(o)
111 return _widget_abbrev_single_value(o)
112
112
113 def _widget_from_abbrev(abbrev, default=empty):
113 def _widget_from_abbrev(abbrev, default=empty):
114 """Build a Widget instance given an abbreviation or Widget."""
114 """Build a Widget instance given an abbreviation or Widget."""
115 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
115 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
116 return abbrev
116 return abbrev
117
117
118 widget = _widget_abbrev(abbrev)
118 widget = _widget_abbrev(abbrev)
119 if default is not empty and isinstance(abbrev, (list, tuple, dict)):
119 if default is not empty and isinstance(abbrev, (list, tuple, dict)):
120 # if it's not a single-value abbreviation,
120 # if it's not a single-value abbreviation,
121 # set the initial value from the default
121 # set the initial value from the default
122 try:
122 try:
123 widget.value = default
123 widget.value = default
124 except Exception:
124 except Exception:
125 # ignore failure to set default
125 # ignore failure to set default
126 pass
126 pass
127 if widget is None:
127 if widget is None:
128 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
128 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
129 return widget
129 return widget
130
130
131 def _yield_abbreviations_for_parameter(param, kwargs):
131 def _yield_abbreviations_for_parameter(param, kwargs):
132 """Get an abbreviation for a function parameter."""
132 """Get an abbreviation for a function parameter."""
133 name = param.name
133 name = param.name
134 kind = param.kind
134 kind = param.kind
135 ann = param.annotation
135 ann = param.annotation
136 default = param.default
136 default = param.default
137 not_found = (name, empty, empty)
137 not_found = (name, empty, empty)
138 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
138 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
139 if name in kwargs:
139 if name in kwargs:
140 value = kwargs.pop(name)
140 value = kwargs.pop(name)
141 elif ann is not empty:
141 elif ann is not empty:
142 value = ann
142 value = ann
143 elif default is not empty:
143 elif default is not empty:
144 value = default
144 value = default
145 else:
145 else:
146 yield not_found
146 yield not_found
147 yield (name, value, default)
147 yield (name, value, default)
148 elif kind == Parameter.VAR_KEYWORD:
148 elif kind == Parameter.VAR_KEYWORD:
149 # In this case name=kwargs and we yield the items in kwargs with their keys.
149 # In this case name=kwargs and we yield the items in kwargs with their keys.
150 for k, v in kwargs.copy().items():
150 for k, v in kwargs.copy().items():
151 kwargs.pop(k)
151 kwargs.pop(k)
152 yield k, v, empty
152 yield k, v, empty
153
153
154 def _find_abbreviations(f, kwargs):
154 def _find_abbreviations(f, kwargs):
155 """Find the abbreviations for a function and kwargs passed to interact."""
155 """Find the abbreviations for a function and kwargs passed to interact."""
156 new_kwargs = []
156 new_kwargs = []
157 for param in signature(f).parameters.values():
157 for param in signature(f).parameters.values():
158 for name, value, default in _yield_abbreviations_for_parameter(param, kwargs):
158 for name, value, default in _yield_abbreviations_for_parameter(param, kwargs):
159 if value is empty:
159 if value is empty:
160 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
160 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
161 new_kwargs.append((name, value, default))
161 new_kwargs.append((name, value, default))
162 return new_kwargs
162 return new_kwargs
163
163
164 def _widgets_from_abbreviations(seq):
164 def _widgets_from_abbreviations(seq):
165 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
165 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
166 result = []
166 result = []
167 for name, abbrev, default in seq:
167 for name, abbrev, default in seq:
168 widget = _widget_from_abbrev(abbrev, default)
168 widget = _widget_from_abbrev(abbrev, default)
169 if not widget.description:
169 if not widget.description:
170 widget.description = name
170 widget.description = name
171 result.append(widget)
171 result.append(widget)
172 return result
172 return result
173
173
174 def interactive(__interact_f, **kwargs):
174 def interactive(__interact_f, **kwargs):
175 """Build a group of widgets to interact with a function."""
175 """Build a group of widgets to interact with a function."""
176 f = __interact_f
176 f = __interact_f
177 co = kwargs.pop('clear_output', True)
177 co = kwargs.pop('clear_output', True)
178 on_demand = kwargs.pop('on_demand', False)
178 choose = kwargs.pop('__choose', False)
179 kwargs_widgets = []
179 kwargs_widgets = []
180 container = Box()
180 container = Box()
181 container.result = None
181 container.result = None
182 container.args = []
182 container.args = []
183 container.kwargs = dict()
183 container.kwargs = dict()
184 kwargs = kwargs.copy()
184 kwargs = kwargs.copy()
185
185
186 new_kwargs = _find_abbreviations(f, kwargs)
186 new_kwargs = _find_abbreviations(f, kwargs)
187 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
187 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
188 # that will lead to a valid call of the function. This protects against unspecified
188 # that will lead to a valid call of the function. This protects against unspecified
189 # and doubly-specified arguments.
189 # and doubly-specified arguments.
190 getcallargs(f, **{n:v for n,v,_ in new_kwargs})
190 getcallargs(f, **{n:v for n,v,_ in new_kwargs})
191 # Now build the widgets from the abbreviations.
191 # Now build the widgets from the abbreviations.
192 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
192 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
193
193
194 # This has to be done as an assignment, not using container.children.append,
194 # This has to be done as an assignment, not using container.children.append,
195 # so that traitlets notices the update. We skip any objects (such as fixed) that
195 # so that traitlets notices the update. We skip any objects (such as fixed) that
196 # are not DOMWidgets.
196 # are not DOMWidgets.
197 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
197 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
198
198
199 # If we are only to run the function on demand, add a button to request this
199 # If we are only to run the function on demand, add a button to request this
200 if on_demand:
200 if choose:
201 on_demand_button = Button(description="Run %s" % f.__name__)
201 choose_button = Button(description="Run %s" % f.__name__)
202 c.append(on_demand_button)
202 c.append(choose_button)
203 container.children = c
203 container.children = c
204
204
205 # Build the callback
205 # Build the callback
206 def call_f(name=None, old=None, new=None):
206 def call_f(name=None, old=None, new=None):
207 container.kwargs = {}
207 container.kwargs = {}
208 for widget in kwargs_widgets:
208 for widget in kwargs_widgets:
209 value = widget.value
209 value = widget.value
210 container.kwargs[widget.description] = value
210 container.kwargs[widget.description] = value
211 if co:
211 if co:
212 clear_output(wait=True)
212 clear_output(wait=True)
213 if on_demand:
213 if choose:
214 on_demand_button.disabled = True
214 choose_button.disabled = True
215 try:
215 try:
216 container.result = f(**container.kwargs)
216 container.result = f(**container.kwargs)
217 except Exception as e:
217 except Exception as e:
218 ip = get_ipython()
218 ip = get_ipython()
219 if ip is None:
219 if ip is None:
220 container.log.warn("Exception in interact callback: %s", e, exc_info=True)
220 container.log.warn("Exception in interact callback: %s", e, exc_info=True)
221 else:
221 else:
222 ip.showtraceback()
222 ip.showtraceback()
223 finally:
223 finally:
224 if on_demand:
224 if choose:
225 on_demand_button.disabled = False
225 choose_button.disabled = False
226
226
227 # Wire up the widgets
227 # Wire up the widgets
228 # If we are doing on demand running, the callback is only triggered by the button
228 # If we are doing choose running, the callback is only triggered by the button
229 # Otherwise, it is triggered for every trait change received
229 # Otherwise, it is triggered for every trait change received
230 # On-demand running also suppresses running the fucntion with the initial parameters
230 # On-demand running also suppresses running the fucntion with the initial parameters
231 if on_demand:
231 if choose:
232 on_demand_button.on_click(call_f)
232 choose_button.on_click(call_f)
233 else:
233 else:
234 for widget in kwargs_widgets:
234 for widget in kwargs_widgets:
235 widget.on_trait_change(call_f, 'value')
235 widget.on_trait_change(call_f, 'value')
236
236
237 container.on_displayed(lambda _: call_f(None, None, None))
237 container.on_displayed(lambda _: call_f(None, None, None))
238
238
239 return container
239 return container
240
240
241 def interact(__interact_f=None, **kwargs):
241 def interact(__interact_f=None, **kwargs):
242 """interact(f, **kwargs)
242 """interact(f, **kwargs)
243
243
244 Interact with a function using widgets."""
244 Interact with a function using widgets."""
245 # positional arg support in: https://gist.github.com/8851331
245 # positional arg support in: https://gist.github.com/8851331
246 if __interact_f is not None:
246 if __interact_f is not None:
247 # This branch handles the cases:
247 # This branch handles the cases:
248 # 1. interact(f, **kwargs)
248 # 1. interact(f, **kwargs)
249 # 2. @interact
249 # 2. @interact
250 # def f(*args, **kwargs):
250 # def f(*args, **kwargs):
251 # ...
251 # ...
252 f = __interact_f
252 f = __interact_f
253 w = interactive(f, **kwargs)
253 w = interactive(f, **kwargs)
254 f.widget = w
254 f.widget = w
255 display(w)
255 display(w)
256 return f
256 return f
257 else:
257 else:
258 # This branch handles the case:
258 # This branch handles the case:
259 # @interact(a=30, b=40)
259 # @interact(a=30, b=40)
260 # def f(*args, **kwargs):
260 # def f(*args, **kwargs):
261 # ...
261 # ...
262 def dec(f):
262 def dec(f):
263 w = interactive(f, **kwargs)
263 w = interactive(f, **kwargs)
264 f.widget = w
264 f.widget = w
265 display(w)
265 display(w)
266 return f
266 return f
267 return dec
267 return dec
268
268
269 def interact_choose(__interact_f=None, **kwargs):
270 """interact_choose(f, **kwargs)
271
272 As `interact()`, generates widgets for each argument, but rather than running
273 the function after each widget change, adds a "Run" button and waits for it
274 to be clicked. Useful if the function is long-running and has several
275 parameters to change.
276 """
277 return interact(__interact_f, __choose=True, **kwargs)
278
269 class fixed(HasTraits):
279 class fixed(HasTraits):
270 """A pseudo-widget whose value is fixed and never synced to the client."""
280 """A pseudo-widget whose value is fixed and never synced to the client."""
271 value = Any(help="Any Python object")
281 value = Any(help="Any Python object")
272 description = Unicode('', help="Any Python object")
282 description = Unicode('', help="Any Python object")
273 def __init__(self, value, **kwargs):
283 def __init__(self, value, **kwargs):
274 super(fixed, self).__init__(value=value, **kwargs)
284 super(fixed, self).__init__(value=value, **kwargs)
@@ -1,612 +1,612 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.Text,
95 cls=widgets.Text,
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.Checkbox,
105 cls=widgets.Checkbox,
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.Dropdown,
118 cls=widgets.Dropdown,
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.FloatSlider,
129 cls=widgets.FloatSlider,
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.IntSlider,
144 cls=widgets.IntSlider,
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.IntSlider,
162 cls=widgets.IntSlider,
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.IntSlider,
179 cls=widgets.IntSlider,
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.FloatSlider,
196 cls=widgets.FloatSlider,
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.FloatSlider,
215 cls=widgets.FloatSlider,
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.Dropdown,
230 cls=widgets.Dropdown,
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.IntSlider,
256 cls=widgets.IntSlider,
257 value=10,
257 value=10,
258 ),
258 ),
259 f=dict(
259 f=dict(
260 cls=widgets.FloatSlider,
260 cls=widgets.FloatSlider,
261 value=4.5,
261 value=4.5,
262 ),
262 ),
263 g=dict(
263 g=dict(
264 cls=widgets.IntSlider,
264 cls=widgets.IntSlider,
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.IntSlider,
277 cls=widgets.IntSlider,
278 value=10,
278 value=10,
279 ),
279 ),
280 f=dict(
280 f=dict(
281 cls=widgets.FloatSlider,
281 cls=widgets.FloatSlider,
282 value=4.5,
282 value=4.5,
283 ),
283 ),
284 g=dict(
284 g=dict(
285 cls=widgets.IntSlider,
285 cls=widgets.IntSlider,
286 value=5,
286 value=5,
287 ),
287 ),
288 h=dict(
288 h=dict(
289 cls=widgets.Dropdown,
289 cls=widgets.Dropdown,
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.Dropdown,
294 cls=widgets.Dropdown,
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}, 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.FloatSlider,
308 cls=widgets.FloatSlider,
309 value=5.,
309 value=5.,
310 ),
310 ),
311 h=dict(
311 h=dict(
312 cls=widgets.Dropdown,
312 cls=widgets.Dropdown,
313 values={'a': 1},
313 values={'a': 1},
314 value=1,
314 value=1,
315 ),
315 ),
316 j=dict(
316 j=dict(
317 cls=widgets.Dropdown,
317 cls=widgets.Dropdown,
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.FloatText())
324 @annotate(n=10, f=widgets.FloatText())
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.IntSlider,
331 cls=widgets.IntSlider,
332 value=10,
332 value=10,
333 ),
333 ),
334 f=dict(
334 f=dict(
335 cls=widgets.FloatText,
335 cls=widgets.FloatText,
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.Text,
347 cls=widgets.Text,
348 value='kwarg',
348 value='kwarg',
349 ),
349 ),
350 annotate=dict(
350 annotate=dict(
351 cls=widgets.Text,
351 cls=widgets.Text,
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.IntSlider,
365 cls=widgets.IntSlider,
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.Text,
378 cls=widgets.Text,
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.Text,
391 cls=widgets.Text,
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.IntSlider,
404 cls=widgets.IntSlider,
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.Text,
420 cls=widgets.Text,
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.Text,
444 cls=widgets.Text,
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.Text,
461 cls=widgets.Text,
462 value='text',
462 value='text',
463 description='b',
463 description='b',
464 )
464 )
465
465
466 def test_default_description():
466 def test_default_description():
467 c = interactive(f, b='text')
467 c = interactive(f, b='text')
468 w = c.children[0]
468 w = c.children[0]
469 check_widget(w,
469 check_widget(w,
470 cls=widgets.Text,
470 cls=widgets.Text,
471 value='text',
471 value='text',
472 description='b',
472 description='b',
473 )
473 )
474
474
475 def test_custom_description():
475 def test_custom_description():
476 c = interactive(f, b=widgets.Text(value='text', description='foo'))
476 c = interactive(f, b=widgets.Text(value='text', description='foo'))
477 w = c.children[0]
477 w = c.children[0]
478 check_widget(w,
478 check_widget(w,
479 cls=widgets.Text,
479 cls=widgets.Text,
480 value='text',
480 value='text',
481 description='foo',
481 description='foo',
482 )
482 )
483
483
484 def test_interact_ondemand_button():
484 def test_interact_choose_button():
485 c = interactive(f, on_demand=True)
485 c = interactive(f, __choose=True)
486 w = c.children[0]
486 w = c.children[0]
487 check_widget(w, cls=widgets.Button)
487 check_widget(w, cls=widgets.Button)
488
488
489 def test_interact_ondemand_nocall():
489 def test_interact_choose_nocall():
490 callcount = 0
490 callcount = 0
491 def calltest(testarg):
491 def calltest(testarg):
492 callcount += 1
492 callcount += 1
493 c = interactive(calltest, testarg=5, on_demand=True)
493 c = interactive(calltest, testarg=5, __choose=True)
494 c.children[0].value = 10
494 c.children[0].value = 10
495 nt.assert_equal(callcount, 0)
495 nt.assert_equal(callcount, 0)
496
496
497 def test_int_range_logic():
497 def test_int_range_logic():
498 irsw = widgets.IntRangeSlider
498 irsw = widgets.IntRangeSlider
499 w = irsw(value=(2, 4), min=0, max=6)
499 w = irsw(value=(2, 4), min=0, max=6)
500 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
500 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
501 w.value = (4, 2)
501 w.value = (4, 2)
502 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
502 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
503 w.value = (-1, 7)
503 w.value = (-1, 7)
504 check_widget(w, cls=irsw, value=(0, 6), min=0, max=6)
504 check_widget(w, cls=irsw, value=(0, 6), min=0, max=6)
505 w.min = 3
505 w.min = 3
506 check_widget(w, cls=irsw, value=(3, 6), min=3, max=6)
506 check_widget(w, cls=irsw, value=(3, 6), min=3, max=6)
507 w.max = 3
507 w.max = 3
508 check_widget(w, cls=irsw, value=(3, 3), min=3, max=3)
508 check_widget(w, cls=irsw, value=(3, 3), min=3, max=3)
509
509
510 w.min = 0
510 w.min = 0
511 w.max = 6
511 w.max = 6
512 w.lower = 2
512 w.lower = 2
513 w.upper = 4
513 w.upper = 4
514 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
514 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
515 w.value = (0, 1) #lower non-overlapping range
515 w.value = (0, 1) #lower non-overlapping range
516 check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
516 check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
517 w.value = (5, 6) #upper non-overlapping range
517 w.value = (5, 6) #upper non-overlapping range
518 check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
518 check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
519 w.value = (-1, 4) #semi out-of-range
519 w.value = (-1, 4) #semi out-of-range
520 check_widget(w, cls=irsw, value=(0, 4), min=0, max=6)
520 check_widget(w, cls=irsw, value=(0, 4), min=0, max=6)
521 w.lower = 2
521 w.lower = 2
522 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
522 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
523 w.value = (-2, -1) #wholly out of range
523 w.value = (-2, -1) #wholly out of range
524 check_widget(w, cls=irsw, value=(0, 0), min=0, max=6)
524 check_widget(w, cls=irsw, value=(0, 0), min=0, max=6)
525 w.value = (7, 8)
525 w.value = (7, 8)
526 check_widget(w, cls=irsw, value=(6, 6), min=0, max=6)
526 check_widget(w, cls=irsw, value=(6, 6), min=0, max=6)
527
527
528 with nt.assert_raises(ValueError):
528 with nt.assert_raises(ValueError):
529 w.min = 7
529 w.min = 7
530 with nt.assert_raises(ValueError):
530 with nt.assert_raises(ValueError):
531 w.max = -1
531 w.max = -1
532 with nt.assert_raises(ValueError):
532 with nt.assert_raises(ValueError):
533 w.lower = 5
533 w.lower = 5
534 with nt.assert_raises(ValueError):
534 with nt.assert_raises(ValueError):
535 w.upper = 1
535 w.upper = 1
536
536
537 w = irsw(min=2, max=3)
537 w = irsw(min=2, max=3)
538 check_widget(w, min=2, max=3)
538 check_widget(w, min=2, max=3)
539 w = irsw(min=100, max=200)
539 w = irsw(min=100, max=200)
540 check_widget(w, lower=125, upper=175, value=(125, 175))
540 check_widget(w, lower=125, upper=175, value=(125, 175))
541
541
542 with nt.assert_raises(ValueError):
542 with nt.assert_raises(ValueError):
543 irsw(value=(2, 4), lower=3)
543 irsw(value=(2, 4), lower=3)
544 with nt.assert_raises(ValueError):
544 with nt.assert_raises(ValueError):
545 irsw(value=(2, 4), upper=3)
545 irsw(value=(2, 4), upper=3)
546 with nt.assert_raises(ValueError):
546 with nt.assert_raises(ValueError):
547 irsw(value=(2, 4), lower=3, upper=3)
547 irsw(value=(2, 4), lower=3, upper=3)
548 with nt.assert_raises(ValueError):
548 with nt.assert_raises(ValueError):
549 irsw(min=2, max=1)
549 irsw(min=2, max=1)
550 with nt.assert_raises(ValueError):
550 with nt.assert_raises(ValueError):
551 irsw(lower=5)
551 irsw(lower=5)
552 with nt.assert_raises(ValueError):
552 with nt.assert_raises(ValueError):
553 irsw(upper=5)
553 irsw(upper=5)
554
554
555
555
556 def test_float_range_logic():
556 def test_float_range_logic():
557 frsw = widgets.FloatRangeSlider
557 frsw = widgets.FloatRangeSlider
558 w = frsw(value=(.2, .4), min=0., max=.6)
558 w = frsw(value=(.2, .4), min=0., max=.6)
559 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
559 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
560 w.value = (.4, .2)
560 w.value = (.4, .2)
561 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
561 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
562 w.value = (-.1, .7)
562 w.value = (-.1, .7)
563 check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6)
563 check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6)
564 w.min = .3
564 w.min = .3
565 check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6)
565 check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6)
566 w.max = .3
566 w.max = .3
567 check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3)
567 check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3)
568
568
569 w.min = 0.
569 w.min = 0.
570 w.max = .6
570 w.max = .6
571 w.lower = .2
571 w.lower = .2
572 w.upper = .4
572 w.upper = .4
573 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
573 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
574 w.value = (0., .1) #lower non-overlapping range
574 w.value = (0., .1) #lower non-overlapping range
575 check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
575 check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
576 w.value = (.5, .6) #upper non-overlapping range
576 w.value = (.5, .6) #upper non-overlapping range
577 check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
577 check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
578 w.value = (-.1, .4) #semi out-of-range
578 w.value = (-.1, .4) #semi out-of-range
579 check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6)
579 check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6)
580 w.lower = .2
580 w.lower = .2
581 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
581 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
582 w.value = (-.2, -.1) #wholly out of range
582 w.value = (-.2, -.1) #wholly out of range
583 check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6)
583 check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6)
584 w.value = (.7, .8)
584 w.value = (.7, .8)
585 check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6)
585 check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6)
586
586
587 with nt.assert_raises(ValueError):
587 with nt.assert_raises(ValueError):
588 w.min = .7
588 w.min = .7
589 with nt.assert_raises(ValueError):
589 with nt.assert_raises(ValueError):
590 w.max = -.1
590 w.max = -.1
591 with nt.assert_raises(ValueError):
591 with nt.assert_raises(ValueError):
592 w.lower = .5
592 w.lower = .5
593 with nt.assert_raises(ValueError):
593 with nt.assert_raises(ValueError):
594 w.upper = .1
594 w.upper = .1
595
595
596 w = frsw(min=2, max=3)
596 w = frsw(min=2, max=3)
597 check_widget(w, min=2, max=3)
597 check_widget(w, min=2, max=3)
598 w = frsw(min=1., max=2.)
598 w = frsw(min=1., max=2.)
599 check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75))
599 check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75))
600
600
601 with nt.assert_raises(ValueError):
601 with nt.assert_raises(ValueError):
602 frsw(value=(2, 4), lower=3)
602 frsw(value=(2, 4), lower=3)
603 with nt.assert_raises(ValueError):
603 with nt.assert_raises(ValueError):
604 frsw(value=(2, 4), upper=3)
604 frsw(value=(2, 4), upper=3)
605 with nt.assert_raises(ValueError):
605 with nt.assert_raises(ValueError):
606 frsw(value=(2, 4), lower=3, upper=3)
606 frsw(value=(2, 4), lower=3, upper=3)
607 with nt.assert_raises(ValueError):
607 with nt.assert_raises(ValueError):
608 frsw(min=.2, max=.1)
608 frsw(min=.2, max=.1)
609 with nt.assert_raises(ValueError):
609 with nt.assert_raises(ValueError):
610 frsw(lower=5)
610 frsw(lower=5)
611 with nt.assert_raises(ValueError):
611 with nt.assert_raises(ValueError):
612 frsw(upper=5)
612 frsw(upper=5)
General Comments 0
You need to be logged in to leave comments. Login now