##// END OF EJS Templates
Merge pull request #7508 from minrk/widget-description-kwarg...
Thomas Kluyver -
r20032:7187eb0d merge
parent child Browse files
Show More
@@ -1,274 +1,275 b''
1 """Interact with functions using widgets."""
1 """Interact with functions using widgets."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 try: # Python >= 3.3
8 try: # Python >= 3.3
9 from inspect import signature, Parameter
9 from inspect import signature, Parameter
10 except ImportError:
10 except ImportError:
11 from IPython.utils.signatures import signature, Parameter
11 from IPython.utils.signatures import signature, Parameter
12 from inspect import getcallargs
12 from inspect import getcallargs
13
13
14 from IPython.core.getipython import get_ipython
14 from IPython.core.getipython import get_ipython
15 from IPython.html.widgets import (Widget, Text,
15 from IPython.html.widgets import (Widget, Text,
16 FloatSlider, IntSlider, Checkbox, Dropdown,
16 FloatSlider, IntSlider, Checkbox, Dropdown,
17 Box, Button, DOMWidget)
17 Box, Button, DOMWidget)
18 from IPython.display import display, clear_output
18 from IPython.display import display, clear_output
19 from IPython.utils.py3compat import string_types, unicode_type
19 from IPython.utils.py3compat import string_types, unicode_type
20 from IPython.utils.traitlets import HasTraits, Any, Unicode
20 from IPython.utils.traitlets import HasTraits, Any, Unicode
21
21
22 empty = Parameter.empty
22 empty = Parameter.empty
23
23
24
24
25 def _matches(o, pattern):
25 def _matches(o, pattern):
26 """Match a pattern of types in a sequence."""
26 """Match a pattern of types in a sequence."""
27 if not len(o) == len(pattern):
27 if not len(o) == len(pattern):
28 return False
28 return False
29 comps = zip(o,pattern)
29 comps = zip(o,pattern)
30 return all(isinstance(obj,kind) for obj,kind in comps)
30 return all(isinstance(obj,kind) for obj,kind in comps)
31
31
32
32
33 def _get_min_max_value(min, max, value=None, step=None):
33 def _get_min_max_value(min, max, value=None, step=None):
34 """Return min, max, value given input values with possible None."""
34 """Return min, max, value given input values with possible None."""
35 if value is None:
35 if value is None:
36 if not max > min:
36 if not max > min:
37 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
37 raise ValueError('max must be greater than min: (min={0}, max={1})'.format(min, max))
38 value = min + abs(min-max)/2
38 value = min + abs(min-max)/2
39 value = type(min)(value)
39 value = type(min)(value)
40 elif min is None and max is None:
40 elif min is None and max is None:
41 if value == 0.0:
41 if value == 0.0:
42 min, max, value = 0.0, 1.0, 0.5
42 min, max, value = 0.0, 1.0, 0.5
43 elif value == 0:
43 elif value == 0:
44 min, max, value = 0, 1, 0
44 min, max, value = 0, 1, 0
45 elif isinstance(value, (int, float)):
45 elif isinstance(value, (int, float)):
46 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
46 min, max = (-value, 3*value) if value > 0 else (3*value, -value)
47 else:
47 else:
48 raise TypeError('expected a number, got: %r' % value)
48 raise TypeError('expected a number, got: %r' % value)
49 else:
49 else:
50 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
50 raise ValueError('unable to infer range, value from: ({0}, {1}, {2})'.format(min, max, value))
51 if step is not None:
51 if step is not None:
52 # ensure value is on a step
52 # ensure value is on a step
53 r = (value - min) % step
53 r = (value - min) % step
54 value = value - r
54 value = value - r
55 return min, max, value
55 return min, max, value
56
56
57 def _widget_abbrev_single_value(o):
57 def _widget_abbrev_single_value(o):
58 """Make widgets from single values, which can be used as parameter defaults."""
58 """Make widgets from single values, which can be used as parameter defaults."""
59 if isinstance(o, string_types):
59 if isinstance(o, string_types):
60 return Text(value=unicode_type(o))
60 return Text(value=unicode_type(o))
61 elif isinstance(o, dict):
61 elif isinstance(o, dict):
62 return Dropdown(values=o)
62 return Dropdown(values=o)
63 elif isinstance(o, bool):
63 elif isinstance(o, bool):
64 return Checkbox(value=o)
64 return Checkbox(value=o)
65 elif isinstance(o, float):
65 elif isinstance(o, float):
66 min, max, value = _get_min_max_value(None, None, o)
66 min, max, value = _get_min_max_value(None, None, o)
67 return FloatSlider(value=o, min=min, max=max)
67 return FloatSlider(value=o, min=min, max=max)
68 elif isinstance(o, int):
68 elif isinstance(o, int):
69 min, max, value = _get_min_max_value(None, None, o)
69 min, max, value = _get_min_max_value(None, None, o)
70 return IntSlider(value=o, min=min, max=max)
70 return IntSlider(value=o, min=min, max=max)
71 else:
71 else:
72 return None
72 return None
73
73
74 def _widget_abbrev(o):
74 def _widget_abbrev(o):
75 """Make widgets from abbreviations: single values, lists or tuples."""
75 """Make widgets from abbreviations: single values, lists or tuples."""
76 float_or_int = (float, int)
76 float_or_int = (float, int)
77 if isinstance(o, (list, tuple)):
77 if isinstance(o, (list, tuple)):
78 if o and all(isinstance(x, string_types) for x in o):
78 if o and all(isinstance(x, string_types) for x in o):
79 return Dropdown(values=[unicode_type(k) for k in o])
79 return Dropdown(values=[unicode_type(k) for k in o])
80 elif _matches(o, (float_or_int, float_or_int)):
80 elif _matches(o, (float_or_int, float_or_int)):
81 min, max, value = _get_min_max_value(o[0], o[1])
81 min, max, value = _get_min_max_value(o[0], o[1])
82 if all(isinstance(_, int) for _ in o):
82 if all(isinstance(_, int) for _ in o):
83 cls = IntSlider
83 cls = IntSlider
84 else:
84 else:
85 cls = FloatSlider
85 cls = FloatSlider
86 return cls(value=value, min=min, max=max)
86 return cls(value=value, min=min, max=max)
87 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
87 elif _matches(o, (float_or_int, float_or_int, float_or_int)):
88 step = o[2]
88 step = o[2]
89 if step <= 0:
89 if step <= 0:
90 raise ValueError("step must be >= 0, not %r" % step)
90 raise ValueError("step must be >= 0, not %r" % step)
91 min, max, value = _get_min_max_value(o[0], o[1], step=step)
91 min, max, value = _get_min_max_value(o[0], o[1], step=step)
92 if all(isinstance(_, int) for _ in o):
92 if all(isinstance(_, int) for _ in o):
93 cls = IntSlider
93 cls = IntSlider
94 else:
94 else:
95 cls = FloatSlider
95 cls = FloatSlider
96 return cls(value=value, min=min, max=max, step=step)
96 return cls(value=value, min=min, max=max, step=step)
97 else:
97 else:
98 return _widget_abbrev_single_value(o)
98 return _widget_abbrev_single_value(o)
99
99
100 def _widget_from_abbrev(abbrev, default=empty):
100 def _widget_from_abbrev(abbrev, default=empty):
101 """Build a Widget instance given an abbreviation or Widget."""
101 """Build a Widget instance given an abbreviation or Widget."""
102 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
102 if isinstance(abbrev, Widget) or isinstance(abbrev, fixed):
103 return abbrev
103 return abbrev
104
104
105 widget = _widget_abbrev(abbrev)
105 widget = _widget_abbrev(abbrev)
106 if default is not empty and isinstance(abbrev, (list, tuple, dict)):
106 if default is not empty and isinstance(abbrev, (list, tuple, dict)):
107 # if it's not a single-value abbreviation,
107 # if it's not a single-value abbreviation,
108 # set the initial value from the default
108 # set the initial value from the default
109 try:
109 try:
110 widget.value = default
110 widget.value = default
111 except Exception:
111 except Exception:
112 # ignore failure to set default
112 # ignore failure to set default
113 pass
113 pass
114 if widget is None:
114 if widget is None:
115 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
115 raise ValueError("%r cannot be transformed to a Widget" % (abbrev,))
116 return widget
116 return widget
117
117
118 def _yield_abbreviations_for_parameter(param, kwargs):
118 def _yield_abbreviations_for_parameter(param, kwargs):
119 """Get an abbreviation for a function parameter."""
119 """Get an abbreviation for a function parameter."""
120 name = param.name
120 name = param.name
121 kind = param.kind
121 kind = param.kind
122 ann = param.annotation
122 ann = param.annotation
123 default = param.default
123 default = param.default
124 not_found = (name, empty, empty)
124 not_found = (name, empty, empty)
125 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
125 if kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY):
126 if name in kwargs:
126 if name in kwargs:
127 value = kwargs.pop(name)
127 value = kwargs.pop(name)
128 elif ann is not empty:
128 elif ann is not empty:
129 value = ann
129 value = ann
130 elif default is not empty:
130 elif default is not empty:
131 value = default
131 value = default
132 else:
132 else:
133 yield not_found
133 yield not_found
134 yield (name, value, default)
134 yield (name, value, default)
135 elif kind == Parameter.VAR_KEYWORD:
135 elif kind == Parameter.VAR_KEYWORD:
136 # In this case name=kwargs and we yield the items in kwargs with their keys.
136 # In this case name=kwargs and we yield the items in kwargs with their keys.
137 for k, v in kwargs.copy().items():
137 for k, v in kwargs.copy().items():
138 kwargs.pop(k)
138 kwargs.pop(k)
139 yield k, v, empty
139 yield k, v, empty
140
140
141 def _find_abbreviations(f, kwargs):
141 def _find_abbreviations(f, kwargs):
142 """Find the abbreviations for a function and kwargs passed to interact."""
142 """Find the abbreviations for a function and kwargs passed to interact."""
143 new_kwargs = []
143 new_kwargs = []
144 for param in signature(f).parameters.values():
144 for param in signature(f).parameters.values():
145 for name, value, default in _yield_abbreviations_for_parameter(param, kwargs):
145 for name, value, default in _yield_abbreviations_for_parameter(param, kwargs):
146 if value is empty:
146 if value is empty:
147 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
147 raise ValueError('cannot find widget or abbreviation for argument: {!r}'.format(name))
148 new_kwargs.append((name, value, default))
148 new_kwargs.append((name, value, default))
149 return new_kwargs
149 return new_kwargs
150
150
151 def _widgets_from_abbreviations(seq):
151 def _widgets_from_abbreviations(seq):
152 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
152 """Given a sequence of (name, abbrev) tuples, return a sequence of Widgets."""
153 result = []
153 result = []
154 for name, abbrev, default in seq:
154 for name, abbrev, default in seq:
155 widget = _widget_from_abbrev(abbrev, default)
155 widget = _widget_from_abbrev(abbrev, default)
156 if not widget.description:
156 if not widget.description:
157 widget.description = name
157 widget.description = name
158 widget._kwarg = name
158 result.append(widget)
159 result.append(widget)
159 return result
160 return result
160
161
161 def interactive(__interact_f, **kwargs):
162 def interactive(__interact_f, **kwargs):
162 """Build a group of widgets to interact with a function."""
163 """Build a group of widgets to interact with a function."""
163 f = __interact_f
164 f = __interact_f
164 co = kwargs.pop('clear_output', True)
165 co = kwargs.pop('clear_output', True)
165 manual = kwargs.pop('__manual', False)
166 manual = kwargs.pop('__manual', False)
166 kwargs_widgets = []
167 kwargs_widgets = []
167 container = Box()
168 container = Box()
168 container.result = None
169 container.result = None
169 container.args = []
170 container.args = []
170 container.kwargs = dict()
171 container.kwargs = dict()
171 kwargs = kwargs.copy()
172 kwargs = kwargs.copy()
172
173
173 new_kwargs = _find_abbreviations(f, kwargs)
174 new_kwargs = _find_abbreviations(f, kwargs)
174 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
175 # Before we proceed, let's make sure that the user has passed a set of args+kwargs
175 # that will lead to a valid call of the function. This protects against unspecified
176 # that will lead to a valid call of the function. This protects against unspecified
176 # and doubly-specified arguments.
177 # and doubly-specified arguments.
177 getcallargs(f, **{n:v for n,v,_ in new_kwargs})
178 getcallargs(f, **{n:v for n,v,_ in new_kwargs})
178 # Now build the widgets from the abbreviations.
179 # Now build the widgets from the abbreviations.
179 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
180 kwargs_widgets.extend(_widgets_from_abbreviations(new_kwargs))
180
181
181 # This has to be done as an assignment, not using container.children.append,
182 # This has to be done as an assignment, not using container.children.append,
182 # so that traitlets notices the update. We skip any objects (such as fixed) that
183 # so that traitlets notices the update. We skip any objects (such as fixed) that
183 # are not DOMWidgets.
184 # are not DOMWidgets.
184 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
185 c = [w for w in kwargs_widgets if isinstance(w, DOMWidget)]
185
186
186 # If we are only to run the function on demand, add a button to request this
187 # If we are only to run the function on demand, add a button to request this
187 if manual:
188 if manual:
188 manual_button = Button(description="Run %s" % f.__name__)
189 manual_button = Button(description="Run %s" % f.__name__)
189 c.append(manual_button)
190 c.append(manual_button)
190 container.children = c
191 container.children = c
191
192
192 # Build the callback
193 # Build the callback
193 def call_f(name=None, old=None, new=None):
194 def call_f(name=None, old=None, new=None):
194 container.kwargs = {}
195 container.kwargs = {}
195 for widget in kwargs_widgets:
196 for widget in kwargs_widgets:
196 value = widget.value
197 value = widget.value
197 container.kwargs[widget.description] = value
198 container.kwargs[widget._kwarg] = value
198 if co:
199 if co:
199 clear_output(wait=True)
200 clear_output(wait=True)
200 if manual:
201 if manual:
201 manual_button.disabled = True
202 manual_button.disabled = True
202 try:
203 try:
203 container.result = f(**container.kwargs)
204 container.result = f(**container.kwargs)
204 except Exception as e:
205 except Exception as e:
205 ip = get_ipython()
206 ip = get_ipython()
206 if ip is None:
207 if ip is None:
207 container.log.warn("Exception in interact callback: %s", e, exc_info=True)
208 container.log.warn("Exception in interact callback: %s", e, exc_info=True)
208 else:
209 else:
209 ip.showtraceback()
210 ip.showtraceback()
210 finally:
211 finally:
211 if manual:
212 if manual:
212 manual_button.disabled = False
213 manual_button.disabled = False
213
214
214 # Wire up the widgets
215 # Wire up the widgets
215 # If we are doing manual running, the callback is only triggered by the button
216 # If we are doing manual running, the callback is only triggered by the button
216 # Otherwise, it is triggered for every trait change received
217 # Otherwise, it is triggered for every trait change received
217 # On-demand running also suppresses running the fucntion with the initial parameters
218 # On-demand running also suppresses running the fucntion with the initial parameters
218 if manual:
219 if manual:
219 manual_button.on_click(call_f)
220 manual_button.on_click(call_f)
220 else:
221 else:
221 for widget in kwargs_widgets:
222 for widget in kwargs_widgets:
222 widget.on_trait_change(call_f, 'value')
223 widget.on_trait_change(call_f, 'value')
223
224
224 container.on_displayed(lambda _: call_f(None, None, None))
225 container.on_displayed(lambda _: call_f(None, None, None))
225
226
226 return container
227 return container
227
228
228 def interact(__interact_f=None, **kwargs):
229 def interact(__interact_f=None, **kwargs):
229 """interact(f, **kwargs)
230 """interact(f, **kwargs)
230
231
231 Interact with a function using widgets."""
232 Interact with a function using widgets."""
232 # positional arg support in: https://gist.github.com/8851331
233 # positional arg support in: https://gist.github.com/8851331
233 if __interact_f is not None:
234 if __interact_f is not None:
234 # This branch handles the cases:
235 # This branch handles the cases:
235 # 1. interact(f, **kwargs)
236 # 1. interact(f, **kwargs)
236 # 2. @interact
237 # 2. @interact
237 # def f(*args, **kwargs):
238 # def f(*args, **kwargs):
238 # ...
239 # ...
239 f = __interact_f
240 f = __interact_f
240 w = interactive(f, **kwargs)
241 w = interactive(f, **kwargs)
241 try:
242 try:
242 f.widget = w
243 f.widget = w
243 except AttributeError:
244 except AttributeError:
244 # some things (instancemethods) can't have attributes attached,
245 # some things (instancemethods) can't have attributes attached,
245 # so wrap in a lambda
246 # so wrap in a lambda
246 f = lambda *args, **kwargs: __interact_f(*args, **kwargs)
247 f = lambda *args, **kwargs: __interact_f(*args, **kwargs)
247 f.widget = w
248 f.widget = w
248 display(w)
249 display(w)
249 return f
250 return f
250 else:
251 else:
251 # This branch handles the case:
252 # This branch handles the case:
252 # @interact(a=30, b=40)
253 # @interact(a=30, b=40)
253 # def f(*args, **kwargs):
254 # def f(*args, **kwargs):
254 # ...
255 # ...
255 def dec(f):
256 def dec(f):
256 return interact(f, **kwargs)
257 return interact(f, **kwargs)
257 return dec
258 return dec
258
259
259 def interact_manual(__interact_f=None, **kwargs):
260 def interact_manual(__interact_f=None, **kwargs):
260 """interact_manual(f, **kwargs)
261 """interact_manual(f, **kwargs)
261
262
262 As `interact()`, generates widgets for each argument, but rather than running
263 As `interact()`, generates widgets for each argument, but rather than running
263 the function after each widget change, adds a "Run" button and waits for it
264 the function after each widget change, adds a "Run" button and waits for it
264 to be clicked. Useful if the function is long-running and has several
265 to be clicked. Useful if the function is long-running and has several
265 parameters to change.
266 parameters to change.
266 """
267 """
267 return interact(__interact_f, __manual=True, **kwargs)
268 return interact(__interact_f, __manual=True, **kwargs)
268
269
269 class fixed(HasTraits):
270 class fixed(HasTraits):
270 """A pseudo-widget whose value is fixed and never synced to the client."""
271 """A pseudo-widget whose value is fixed and never synced to the client."""
271 value = Any(help="Any Python object")
272 value = Any(help="Any Python object")
272 description = Unicode('', help="Any Python object")
273 description = Unicode('', help="Any Python object")
273 def __init__(self, value, **kwargs):
274 def __init__(self, value, **kwargs):
274 super(fixed, self).__init__(value=value, **kwargs)
275 super(fixed, self).__init__(value=value, **kwargs)
@@ -1,628 +1,635 b''
1 """Test interact and interactive."""
1 """Test interact and interactive."""
2
2
3 # Copyright (c) IPython Development Team.
3 # Copyright (c) IPython Development Team.
4 # Distributed under the terms of the Modified BSD License.
4 # Distributed under the terms of the Modified BSD License.
5
5
6 from __future__ import print_function
6 from __future__ import print_function
7
7
8 from collections import OrderedDict
8 from collections import OrderedDict
9
9
10 import nose.tools as nt
10 import nose.tools as nt
11 import IPython.testing.tools as tt
11 import IPython.testing.tools as tt
12
12
13 from IPython.kernel.comm import Comm
13 from IPython.kernel.comm import Comm
14 from IPython.html import widgets
14 from IPython.html import widgets
15 from IPython.html.widgets import interact, interactive, Widget, interaction
15 from IPython.html.widgets import interact, interactive, Widget, interaction
16 from IPython.utils.py3compat import annotate
16 from IPython.utils.py3compat import annotate
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Utility stuff
19 # Utility stuff
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 class DummyComm(Comm):
22 class DummyComm(Comm):
23 comm_id = 'a-b-c-d'
23 comm_id = 'a-b-c-d'
24
24
25 def open(self, *args, **kwargs):
25 def open(self, *args, **kwargs):
26 pass
26 pass
27
27
28 def send(self, *args, **kwargs):
28 def send(self, *args, **kwargs):
29 pass
29 pass
30
30
31 def close(self, *args, **kwargs):
31 def close(self, *args, **kwargs):
32 pass
32 pass
33
33
34 _widget_attrs = {}
34 _widget_attrs = {}
35 displayed = []
35 displayed = []
36 undefined = object()
36 undefined = object()
37
37
38 def setup():
38 def setup():
39 _widget_attrs['_comm_default'] = getattr(Widget, '_comm_default', undefined)
39 _widget_attrs['_comm_default'] = getattr(Widget, '_comm_default', undefined)
40 Widget._comm_default = lambda self: DummyComm()
40 Widget._comm_default = lambda self: DummyComm()
41 _widget_attrs['_ipython_display_'] = Widget._ipython_display_
41 _widget_attrs['_ipython_display_'] = Widget._ipython_display_
42 def raise_not_implemented(*args, **kwargs):
42 def raise_not_implemented(*args, **kwargs):
43 raise NotImplementedError()
43 raise NotImplementedError()
44 Widget._ipython_display_ = raise_not_implemented
44 Widget._ipython_display_ = raise_not_implemented
45
45
46 def teardown():
46 def teardown():
47 for attr, value in _widget_attrs.items():
47 for attr, value in _widget_attrs.items():
48 if value is undefined:
48 if value is undefined:
49 delattr(Widget, attr)
49 delattr(Widget, attr)
50 else:
50 else:
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 c = interactive(f, tup=tuple(values), lis=list(values))
226 c = interactive(f, tup=tuple(values), lis=list(values))
227 nt.assert_equal(len(c.children), 2)
227 nt.assert_equal(len(c.children), 2)
228 d = dict(
228 d = dict(
229 cls=widgets.Dropdown,
229 cls=widgets.Dropdown,
230 value=first,
230 value=first,
231 values=values
231 values=values
232 )
232 )
233 check_widgets(c, tup=d, lis=d)
233 check_widgets(c, tup=d, lis=d)
234
234
235 def test_list_tuple_invalid():
235 def test_list_tuple_invalid():
236 for bad in [
236 for bad in [
237 (),
237 (),
238 (5, 'hi'),
238 (5, 'hi'),
239 ('hi', 5),
239 ('hi', 5),
240 ({},),
240 ({},),
241 (None,),
241 (None,),
242 ]:
242 ]:
243 with nt.assert_raises(ValueError):
243 with nt.assert_raises(ValueError):
244 print(bad) # because there is no custom message in assert_raises
244 print(bad) # because there is no custom message in assert_raises
245 c = interactive(f, tup=bad)
245 c = interactive(f, tup=bad)
246
246
247 def test_defaults():
247 def test_defaults():
248 @annotate(n=10)
248 @annotate(n=10)
249 def f(n, f=4.5, g=1):
249 def f(n, f=4.5, g=1):
250 pass
250 pass
251
251
252 c = interactive(f)
252 c = interactive(f)
253 check_widgets(c,
253 check_widgets(c,
254 n=dict(
254 n=dict(
255 cls=widgets.IntSlider,
255 cls=widgets.IntSlider,
256 value=10,
256 value=10,
257 ),
257 ),
258 f=dict(
258 f=dict(
259 cls=widgets.FloatSlider,
259 cls=widgets.FloatSlider,
260 value=4.5,
260 value=4.5,
261 ),
261 ),
262 g=dict(
262 g=dict(
263 cls=widgets.IntSlider,
263 cls=widgets.IntSlider,
264 value=1,
264 value=1,
265 ),
265 ),
266 )
266 )
267
267
268 def test_default_values():
268 def test_default_values():
269 @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there'])
269 @annotate(n=10, f=(0, 10.), g=5, h={'a': 1, 'b': 2}, j=['hi', 'there'])
270 def f(n, f=4.5, g=1, h=2, j='there'):
270 def f(n, f=4.5, g=1, h=2, j='there'):
271 pass
271 pass
272
272
273 c = interactive(f)
273 c = interactive(f)
274 check_widgets(c,
274 check_widgets(c,
275 n=dict(
275 n=dict(
276 cls=widgets.IntSlider,
276 cls=widgets.IntSlider,
277 value=10,
277 value=10,
278 ),
278 ),
279 f=dict(
279 f=dict(
280 cls=widgets.FloatSlider,
280 cls=widgets.FloatSlider,
281 value=4.5,
281 value=4.5,
282 ),
282 ),
283 g=dict(
283 g=dict(
284 cls=widgets.IntSlider,
284 cls=widgets.IntSlider,
285 value=5,
285 value=5,
286 ),
286 ),
287 h=dict(
287 h=dict(
288 cls=widgets.Dropdown,
288 cls=widgets.Dropdown,
289 values={'a': 1, 'b': 2},
289 values={'a': 1, 'b': 2},
290 value=2
290 value=2
291 ),
291 ),
292 j=dict(
292 j=dict(
293 cls=widgets.Dropdown,
293 cls=widgets.Dropdown,
294 values=['hi', 'there'],
294 values=['hi', 'there'],
295 value='there'
295 value='there'
296 ),
296 ),
297 )
297 )
298
298
299 def test_default_out_of_bounds():
299 def test_default_out_of_bounds():
300 @annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there'])
300 @annotate(f=(0, 10.), h={'a': 1}, j=['hi', 'there'])
301 def f(f='hi', h=5, j='other'):
301 def f(f='hi', h=5, j='other'):
302 pass
302 pass
303
303
304 c = interactive(f)
304 c = interactive(f)
305 check_widgets(c,
305 check_widgets(c,
306 f=dict(
306 f=dict(
307 cls=widgets.FloatSlider,
307 cls=widgets.FloatSlider,
308 value=5.,
308 value=5.,
309 ),
309 ),
310 h=dict(
310 h=dict(
311 cls=widgets.Dropdown,
311 cls=widgets.Dropdown,
312 values={'a': 1},
312 values={'a': 1},
313 value=1,
313 value=1,
314 ),
314 ),
315 j=dict(
315 j=dict(
316 cls=widgets.Dropdown,
316 cls=widgets.Dropdown,
317 values=['hi', 'there'],
317 values=['hi', 'there'],
318 value='hi',
318 value='hi',
319 ),
319 ),
320 )
320 )
321
321
322 def test_annotations():
322 def test_annotations():
323 @annotate(n=10, f=widgets.FloatText())
323 @annotate(n=10, f=widgets.FloatText())
324 def f(n, f):
324 def f(n, f):
325 pass
325 pass
326
326
327 c = interactive(f)
327 c = interactive(f)
328 check_widgets(c,
328 check_widgets(c,
329 n=dict(
329 n=dict(
330 cls=widgets.IntSlider,
330 cls=widgets.IntSlider,
331 value=10,
331 value=10,
332 ),
332 ),
333 f=dict(
333 f=dict(
334 cls=widgets.FloatText,
334 cls=widgets.FloatText,
335 ),
335 ),
336 )
336 )
337
337
338 def test_priority():
338 def test_priority():
339 @annotate(annotate='annotate', kwarg='annotate')
339 @annotate(annotate='annotate', kwarg='annotate')
340 def f(kwarg='default', annotate='default', default='default'):
340 def f(kwarg='default', annotate='default', default='default'):
341 pass
341 pass
342
342
343 c = interactive(f, kwarg='kwarg')
343 c = interactive(f, kwarg='kwarg')
344 check_widgets(c,
344 check_widgets(c,
345 kwarg=dict(
345 kwarg=dict(
346 cls=widgets.Text,
346 cls=widgets.Text,
347 value='kwarg',
347 value='kwarg',
348 ),
348 ),
349 annotate=dict(
349 annotate=dict(
350 cls=widgets.Text,
350 cls=widgets.Text,
351 value='annotate',
351 value='annotate',
352 ),
352 ),
353 )
353 )
354
354
355 @nt.with_setup(clear_display)
355 @nt.with_setup(clear_display)
356 def test_decorator_kwarg():
356 def test_decorator_kwarg():
357 with tt.monkeypatch(interaction, 'display', record_display):
357 with tt.monkeypatch(interaction, 'display', record_display):
358 @interact(a=5)
358 @interact(a=5)
359 def foo(a):
359 def foo(a):
360 pass
360 pass
361 nt.assert_equal(len(displayed), 1)
361 nt.assert_equal(len(displayed), 1)
362 w = displayed[0].children[0]
362 w = displayed[0].children[0]
363 check_widget(w,
363 check_widget(w,
364 cls=widgets.IntSlider,
364 cls=widgets.IntSlider,
365 value=5,
365 value=5,
366 )
366 )
367
367
368 @nt.with_setup(clear_display)
368 @nt.with_setup(clear_display)
369 def test_interact_instancemethod():
369 def test_interact_instancemethod():
370 class Foo(object):
370 class Foo(object):
371 def show(self, x):
371 def show(self, x):
372 print(x)
372 print(x)
373
373
374 f = Foo()
374 f = Foo()
375
375
376 with tt.monkeypatch(interaction, 'display', record_display):
376 with tt.monkeypatch(interaction, 'display', record_display):
377 g = interact(f.show, x=(1,10))
377 g = interact(f.show, x=(1,10))
378 nt.assert_equal(len(displayed), 1)
378 nt.assert_equal(len(displayed), 1)
379 w = displayed[0].children[0]
379 w = displayed[0].children[0]
380 check_widget(w,
380 check_widget(w,
381 cls=widgets.IntSlider,
381 cls=widgets.IntSlider,
382 value=5,
382 value=5,
383 )
383 )
384
384
385 @nt.with_setup(clear_display)
385 @nt.with_setup(clear_display)
386 def test_decorator_no_call():
386 def test_decorator_no_call():
387 with tt.monkeypatch(interaction, 'display', record_display):
387 with tt.monkeypatch(interaction, 'display', record_display):
388 @interact
388 @interact
389 def foo(a='default'):
389 def foo(a='default'):
390 pass
390 pass
391 nt.assert_equal(len(displayed), 1)
391 nt.assert_equal(len(displayed), 1)
392 w = displayed[0].children[0]
392 w = displayed[0].children[0]
393 check_widget(w,
393 check_widget(w,
394 cls=widgets.Text,
394 cls=widgets.Text,
395 value='default',
395 value='default',
396 )
396 )
397
397
398 @nt.with_setup(clear_display)
398 @nt.with_setup(clear_display)
399 def test_call_interact():
399 def test_call_interact():
400 def foo(a='default'):
400 def foo(a='default'):
401 pass
401 pass
402 with tt.monkeypatch(interaction, 'display', record_display):
402 with tt.monkeypatch(interaction, 'display', record_display):
403 ifoo = interact(foo)
403 ifoo = interact(foo)
404 nt.assert_equal(len(displayed), 1)
404 nt.assert_equal(len(displayed), 1)
405 w = displayed[0].children[0]
405 w = displayed[0].children[0]
406 check_widget(w,
406 check_widget(w,
407 cls=widgets.Text,
407 cls=widgets.Text,
408 value='default',
408 value='default',
409 )
409 )
410
410
411 @nt.with_setup(clear_display)
411 @nt.with_setup(clear_display)
412 def test_call_interact_kwargs():
412 def test_call_interact_kwargs():
413 def foo(a='default'):
413 def foo(a='default'):
414 pass
414 pass
415 with tt.monkeypatch(interaction, 'display', record_display):
415 with tt.monkeypatch(interaction, 'display', record_display):
416 ifoo = interact(foo, a=10)
416 ifoo = interact(foo, a=10)
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.IntSlider,
420 cls=widgets.IntSlider,
421 value=10,
421 value=10,
422 )
422 )
423
423
424 @nt.with_setup(clear_display)
424 @nt.with_setup(clear_display)
425 def test_call_decorated_on_trait_change():
425 def test_call_decorated_on_trait_change():
426 """test calling @interact decorated functions"""
426 """test calling @interact decorated functions"""
427 d = {}
427 d = {}
428 with tt.monkeypatch(interaction, 'display', record_display):
428 with tt.monkeypatch(interaction, 'display', record_display):
429 @interact
429 @interact
430 def foo(a='default'):
430 def foo(a='default'):
431 d['a'] = a
431 d['a'] = a
432 return a
432 return a
433 nt.assert_equal(len(displayed), 1)
433 nt.assert_equal(len(displayed), 1)
434 w = displayed[0].children[0]
434 w = displayed[0].children[0]
435 check_widget(w,
435 check_widget(w,
436 cls=widgets.Text,
436 cls=widgets.Text,
437 value='default',
437 value='default',
438 )
438 )
439 # test calling the function directly
439 # test calling the function directly
440 a = foo('hello')
440 a = foo('hello')
441 nt.assert_equal(a, 'hello')
441 nt.assert_equal(a, 'hello')
442 nt.assert_equal(d['a'], 'hello')
442 nt.assert_equal(d['a'], 'hello')
443
443
444 # test that setting trait values calls the function
444 # test that setting trait values calls the function
445 w.value = 'called'
445 w.value = 'called'
446 nt.assert_equal(d['a'], 'called')
446 nt.assert_equal(d['a'], 'called')
447
447
448 @nt.with_setup(clear_display)
448 @nt.with_setup(clear_display)
449 def test_call_decorated_kwargs_on_trait_change():
449 def test_call_decorated_kwargs_on_trait_change():
450 """test calling @interact(foo=bar) decorated functions"""
450 """test calling @interact(foo=bar) decorated functions"""
451 d = {}
451 d = {}
452 with tt.monkeypatch(interaction, 'display', record_display):
452 with tt.monkeypatch(interaction, 'display', record_display):
453 @interact(a='kwarg')
453 @interact(a='kwarg')
454 def foo(a='default'):
454 def foo(a='default'):
455 d['a'] = a
455 d['a'] = a
456 return a
456 return a
457 nt.assert_equal(len(displayed), 1)
457 nt.assert_equal(len(displayed), 1)
458 w = displayed[0].children[0]
458 w = displayed[0].children[0]
459 check_widget(w,
459 check_widget(w,
460 cls=widgets.Text,
460 cls=widgets.Text,
461 value='kwarg',
461 value='kwarg',
462 )
462 )
463 # test calling the function directly
463 # test calling the function directly
464 a = foo('hello')
464 a = foo('hello')
465 nt.assert_equal(a, 'hello')
465 nt.assert_equal(a, 'hello')
466 nt.assert_equal(d['a'], 'hello')
466 nt.assert_equal(d['a'], 'hello')
467
467
468 # test that setting trait values calls the function
468 # test that setting trait values calls the function
469 w.value = 'called'
469 w.value = 'called'
470 nt.assert_equal(d['a'], 'called')
470 nt.assert_equal(d['a'], 'called')
471
471
472 def test_fixed():
472 def test_fixed():
473 c = interactive(f, a=widgets.fixed(5), b='text')
473 c = interactive(f, a=widgets.fixed(5), b='text')
474 nt.assert_equal(len(c.children), 1)
474 nt.assert_equal(len(c.children), 1)
475 w = c.children[0]
475 w = c.children[0]
476 check_widget(w,
476 check_widget(w,
477 cls=widgets.Text,
477 cls=widgets.Text,
478 value='text',
478 value='text',
479 description='b',
479 description='b',
480 )
480 )
481
481
482 def test_default_description():
482 def test_default_description():
483 c = interactive(f, b='text')
483 c = interactive(f, b='text')
484 w = c.children[0]
484 w = c.children[0]
485 check_widget(w,
485 check_widget(w,
486 cls=widgets.Text,
486 cls=widgets.Text,
487 value='text',
487 value='text',
488 description='b',
488 description='b',
489 )
489 )
490
490
491 def test_custom_description():
491 def test_custom_description():
492 c = interactive(f, b=widgets.Text(value='text', description='foo'))
492 d = {}
493 def record_kwargs(**kwargs):
494 d.clear()
495 d.update(kwargs)
496
497 c = interactive(record_kwargs, b=widgets.Text(value='text', description='foo'))
493 w = c.children[0]
498 w = c.children[0]
494 check_widget(w,
499 check_widget(w,
495 cls=widgets.Text,
500 cls=widgets.Text,
496 value='text',
501 value='text',
497 description='foo',
502 description='foo',
498 )
503 )
504 w.value = 'different text'
505 nt.assert_equal(d, {'b': 'different text'})
499
506
500 def test_interact_manual_button():
507 def test_interact_manual_button():
501 c = interactive(f, __manual=True)
508 c = interactive(f, __manual=True)
502 w = c.children[0]
509 w = c.children[0]
503 check_widget(w, cls=widgets.Button)
510 check_widget(w, cls=widgets.Button)
504
511
505 def test_interact_manual_nocall():
512 def test_interact_manual_nocall():
506 callcount = 0
513 callcount = 0
507 def calltest(testarg):
514 def calltest(testarg):
508 callcount += 1
515 callcount += 1
509 c = interactive(calltest, testarg=5, __manual=True)
516 c = interactive(calltest, testarg=5, __manual=True)
510 c.children[0].value = 10
517 c.children[0].value = 10
511 nt.assert_equal(callcount, 0)
518 nt.assert_equal(callcount, 0)
512
519
513 def test_int_range_logic():
520 def test_int_range_logic():
514 irsw = widgets.IntRangeSlider
521 irsw = widgets.IntRangeSlider
515 w = irsw(value=(2, 4), min=0, max=6)
522 w = irsw(value=(2, 4), min=0, max=6)
516 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
523 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
517 w.value = (4, 2)
524 w.value = (4, 2)
518 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
525 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
519 w.value = (-1, 7)
526 w.value = (-1, 7)
520 check_widget(w, cls=irsw, value=(0, 6), min=0, max=6)
527 check_widget(w, cls=irsw, value=(0, 6), min=0, max=6)
521 w.min = 3
528 w.min = 3
522 check_widget(w, cls=irsw, value=(3, 6), min=3, max=6)
529 check_widget(w, cls=irsw, value=(3, 6), min=3, max=6)
523 w.max = 3
530 w.max = 3
524 check_widget(w, cls=irsw, value=(3, 3), min=3, max=3)
531 check_widget(w, cls=irsw, value=(3, 3), min=3, max=3)
525
532
526 w.min = 0
533 w.min = 0
527 w.max = 6
534 w.max = 6
528 w.lower = 2
535 w.lower = 2
529 w.upper = 4
536 w.upper = 4
530 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
537 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
531 w.value = (0, 1) #lower non-overlapping range
538 w.value = (0, 1) #lower non-overlapping range
532 check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
539 check_widget(w, cls=irsw, value=(0, 1), min=0, max=6)
533 w.value = (5, 6) #upper non-overlapping range
540 w.value = (5, 6) #upper non-overlapping range
534 check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
541 check_widget(w, cls=irsw, value=(5, 6), min=0, max=6)
535 w.value = (-1, 4) #semi out-of-range
542 w.value = (-1, 4) #semi out-of-range
536 check_widget(w, cls=irsw, value=(0, 4), min=0, max=6)
543 check_widget(w, cls=irsw, value=(0, 4), min=0, max=6)
537 w.lower = 2
544 w.lower = 2
538 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
545 check_widget(w, cls=irsw, value=(2, 4), min=0, max=6)
539 w.value = (-2, -1) #wholly out of range
546 w.value = (-2, -1) #wholly out of range
540 check_widget(w, cls=irsw, value=(0, 0), min=0, max=6)
547 check_widget(w, cls=irsw, value=(0, 0), min=0, max=6)
541 w.value = (7, 8)
548 w.value = (7, 8)
542 check_widget(w, cls=irsw, value=(6, 6), min=0, max=6)
549 check_widget(w, cls=irsw, value=(6, 6), min=0, max=6)
543
550
544 with nt.assert_raises(ValueError):
551 with nt.assert_raises(ValueError):
545 w.min = 7
552 w.min = 7
546 with nt.assert_raises(ValueError):
553 with nt.assert_raises(ValueError):
547 w.max = -1
554 w.max = -1
548 with nt.assert_raises(ValueError):
555 with nt.assert_raises(ValueError):
549 w.lower = 5
556 w.lower = 5
550 with nt.assert_raises(ValueError):
557 with nt.assert_raises(ValueError):
551 w.upper = 1
558 w.upper = 1
552
559
553 w = irsw(min=2, max=3)
560 w = irsw(min=2, max=3)
554 check_widget(w, min=2, max=3)
561 check_widget(w, min=2, max=3)
555 w = irsw(min=100, max=200)
562 w = irsw(min=100, max=200)
556 check_widget(w, lower=125, upper=175, value=(125, 175))
563 check_widget(w, lower=125, upper=175, value=(125, 175))
557
564
558 with nt.assert_raises(ValueError):
565 with nt.assert_raises(ValueError):
559 irsw(value=(2, 4), lower=3)
566 irsw(value=(2, 4), lower=3)
560 with nt.assert_raises(ValueError):
567 with nt.assert_raises(ValueError):
561 irsw(value=(2, 4), upper=3)
568 irsw(value=(2, 4), upper=3)
562 with nt.assert_raises(ValueError):
569 with nt.assert_raises(ValueError):
563 irsw(value=(2, 4), lower=3, upper=3)
570 irsw(value=(2, 4), lower=3, upper=3)
564 with nt.assert_raises(ValueError):
571 with nt.assert_raises(ValueError):
565 irsw(min=2, max=1)
572 irsw(min=2, max=1)
566 with nt.assert_raises(ValueError):
573 with nt.assert_raises(ValueError):
567 irsw(lower=5)
574 irsw(lower=5)
568 with nt.assert_raises(ValueError):
575 with nt.assert_raises(ValueError):
569 irsw(upper=5)
576 irsw(upper=5)
570
577
571
578
572 def test_float_range_logic():
579 def test_float_range_logic():
573 frsw = widgets.FloatRangeSlider
580 frsw = widgets.FloatRangeSlider
574 w = frsw(value=(.2, .4), min=0., max=.6)
581 w = frsw(value=(.2, .4), min=0., max=.6)
575 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
582 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
576 w.value = (.4, .2)
583 w.value = (.4, .2)
577 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
584 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
578 w.value = (-.1, .7)
585 w.value = (-.1, .7)
579 check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6)
586 check_widget(w, cls=frsw, value=(0., .6), min=0., max=.6)
580 w.min = .3
587 w.min = .3
581 check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6)
588 check_widget(w, cls=frsw, value=(.3, .6), min=.3, max=.6)
582 w.max = .3
589 w.max = .3
583 check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3)
590 check_widget(w, cls=frsw, value=(.3, .3), min=.3, max=.3)
584
591
585 w.min = 0.
592 w.min = 0.
586 w.max = .6
593 w.max = .6
587 w.lower = .2
594 w.lower = .2
588 w.upper = .4
595 w.upper = .4
589 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
596 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
590 w.value = (0., .1) #lower non-overlapping range
597 w.value = (0., .1) #lower non-overlapping range
591 check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
598 check_widget(w, cls=frsw, value=(0., .1), min=0., max=.6)
592 w.value = (.5, .6) #upper non-overlapping range
599 w.value = (.5, .6) #upper non-overlapping range
593 check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
600 check_widget(w, cls=frsw, value=(.5, .6), min=0., max=.6)
594 w.value = (-.1, .4) #semi out-of-range
601 w.value = (-.1, .4) #semi out-of-range
595 check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6)
602 check_widget(w, cls=frsw, value=(0., .4), min=0., max=.6)
596 w.lower = .2
603 w.lower = .2
597 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
604 check_widget(w, cls=frsw, value=(.2, .4), min=0., max=.6)
598 w.value = (-.2, -.1) #wholly out of range
605 w.value = (-.2, -.1) #wholly out of range
599 check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6)
606 check_widget(w, cls=frsw, value=(0., 0.), min=0., max=.6)
600 w.value = (.7, .8)
607 w.value = (.7, .8)
601 check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6)
608 check_widget(w, cls=frsw, value=(.6, .6), min=.0, max=.6)
602
609
603 with nt.assert_raises(ValueError):
610 with nt.assert_raises(ValueError):
604 w.min = .7
611 w.min = .7
605 with nt.assert_raises(ValueError):
612 with nt.assert_raises(ValueError):
606 w.max = -.1
613 w.max = -.1
607 with nt.assert_raises(ValueError):
614 with nt.assert_raises(ValueError):
608 w.lower = .5
615 w.lower = .5
609 with nt.assert_raises(ValueError):
616 with nt.assert_raises(ValueError):
610 w.upper = .1
617 w.upper = .1
611
618
612 w = frsw(min=2, max=3)
619 w = frsw(min=2, max=3)
613 check_widget(w, min=2, max=3)
620 check_widget(w, min=2, max=3)
614 w = frsw(min=1., max=2.)
621 w = frsw(min=1., max=2.)
615 check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75))
622 check_widget(w, lower=1.25, upper=1.75, value=(1.25, 1.75))
616
623
617 with nt.assert_raises(ValueError):
624 with nt.assert_raises(ValueError):
618 frsw(value=(2, 4), lower=3)
625 frsw(value=(2, 4), lower=3)
619 with nt.assert_raises(ValueError):
626 with nt.assert_raises(ValueError):
620 frsw(value=(2, 4), upper=3)
627 frsw(value=(2, 4), upper=3)
621 with nt.assert_raises(ValueError):
628 with nt.assert_raises(ValueError):
622 frsw(value=(2, 4), lower=3, upper=3)
629 frsw(value=(2, 4), lower=3, upper=3)
623 with nt.assert_raises(ValueError):
630 with nt.assert_raises(ValueError):
624 frsw(min=.2, max=.1)
631 frsw(min=.2, max=.1)
625 with nt.assert_raises(ValueError):
632 with nt.assert_raises(ValueError):
626 frsw(lower=5)
633 frsw(lower=5)
627 with nt.assert_raises(ValueError):
634 with nt.assert_raises(ValueError):
628 frsw(upper=5)
635 frsw(upper=5)
General Comments 0
You need to be logged in to leave comments. Login now