syd 0.1.6__py3-none-any.whl → 0.2.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- syd/__init__.py +3 -3
- syd/flask_deployment/__init__.py +7 -0
- syd/flask_deployment/deployer.py +594 -291
- syd/flask_deployment/static/__init__.py +1 -0
- syd/flask_deployment/static/css/styles.css +226 -19
- syd/flask_deployment/static/js/viewer.js +744 -0
- syd/flask_deployment/templates/__init__.py +1 -0
- syd/flask_deployment/templates/index.html +34 -0
- syd/flask_deployment/testing_principles.md +300 -0
- syd/notebook_deployment/__init__.py +1 -1
- syd/notebook_deployment/deployer.py +139 -53
- syd/notebook_deployment/widgets.py +214 -123
- syd/parameters.py +295 -393
- syd/support.py +168 -0
- syd/{interactive_viewer.py → viewer.py} +393 -470
- syd-0.2.0.dist-info/METADATA +126 -0
- syd-0.2.0.dist-info/RECORD +19 -0
- syd/flask_deployment/components.py +0 -497
- syd/flask_deployment/static/js/components.js +0 -51
- syd/flask_deployment/templates/base.html +0 -26
- syd/flask_deployment/templates/viewer.html +0 -97
- syd-0.1.6.dist-info/METADATA +0 -106
- syd-0.1.6.dist-info/RECORD +0 -18
- {syd-0.1.6.dist-info → syd-0.2.0.dist-info}/WHEEL +0 -0
- {syd-0.1.6.dist-info → syd-0.2.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -33,14 +33,30 @@ class BaseWidget(Generic[T, W], ABC):
|
|
|
33
33
|
_callbacks: List[Dict[str, Union[Callable, Union[str, List[str]]]]]
|
|
34
34
|
_is_action: bool = False
|
|
35
35
|
|
|
36
|
-
def __init__(
|
|
37
|
-
self
|
|
36
|
+
def __init__(
|
|
37
|
+
self,
|
|
38
|
+
parameter: T,
|
|
39
|
+
continuous: bool = False,
|
|
40
|
+
width: str = "auto",
|
|
41
|
+
margin: str = "3px 0px",
|
|
42
|
+
description_width: str = "initial",
|
|
43
|
+
):
|
|
44
|
+
self._widget = self._create_widget(
|
|
45
|
+
parameter, continuous, width, margin, description_width
|
|
46
|
+
)
|
|
38
47
|
self._updating = False # Flag to prevent circular updates
|
|
39
48
|
# List of callbacks to remember for quick disabling/enabling
|
|
40
49
|
self._callbacks = []
|
|
41
50
|
|
|
42
51
|
@abstractmethod
|
|
43
|
-
def _create_widget(
|
|
52
|
+
def _create_widget(
|
|
53
|
+
self,
|
|
54
|
+
parameter: T,
|
|
55
|
+
continuous: bool,
|
|
56
|
+
width: str = "auto",
|
|
57
|
+
margin: str = "3px 0px",
|
|
58
|
+
description_width: str = "initial",
|
|
59
|
+
) -> W:
|
|
44
60
|
"""Create and return the appropriate ipywidget."""
|
|
45
61
|
pass
|
|
46
62
|
|
|
@@ -105,36 +121,58 @@ class TextWidget(BaseWidget[TextParameter, widgets.Text]):
|
|
|
105
121
|
"""Widget for text parameters."""
|
|
106
122
|
|
|
107
123
|
def _create_widget(
|
|
108
|
-
self,
|
|
124
|
+
self,
|
|
125
|
+
parameter: TextParameter,
|
|
126
|
+
continuous: bool,
|
|
127
|
+
width: str = "auto",
|
|
128
|
+
margin: str = "3px 0px",
|
|
129
|
+
description_width: str = "initial",
|
|
109
130
|
) -> widgets.Text:
|
|
110
131
|
return widgets.Text(
|
|
111
132
|
value=parameter.value,
|
|
112
133
|
description=parameter.name,
|
|
113
134
|
continuous=continuous,
|
|
114
|
-
layout=widgets.Layout(width=
|
|
135
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
136
|
+
style={"description_width": description_width},
|
|
115
137
|
)
|
|
116
138
|
|
|
117
139
|
|
|
118
|
-
class BooleanWidget(BaseWidget[BooleanParameter, widgets.
|
|
140
|
+
class BooleanWidget(BaseWidget[BooleanParameter, widgets.ToggleButton]):
|
|
119
141
|
"""Widget for boolean parameters."""
|
|
120
142
|
|
|
121
143
|
def _create_widget(
|
|
122
|
-
self,
|
|
123
|
-
|
|
124
|
-
|
|
144
|
+
self,
|
|
145
|
+
parameter: BooleanParameter,
|
|
146
|
+
continuous: bool,
|
|
147
|
+
width: str = "auto",
|
|
148
|
+
margin: str = "3px 0px",
|
|
149
|
+
description_width: str = "initial",
|
|
150
|
+
) -> widgets.ToggleButton:
|
|
151
|
+
return widgets.ToggleButton(
|
|
152
|
+
value=parameter.value,
|
|
153
|
+
description=parameter.name,
|
|
154
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
155
|
+
style={"description_width": description_width},
|
|
156
|
+
)
|
|
125
157
|
|
|
126
158
|
|
|
127
159
|
class SelectionWidget(BaseWidget[SelectionParameter, widgets.Dropdown]):
|
|
128
160
|
"""Widget for single selection parameters."""
|
|
129
161
|
|
|
130
162
|
def _create_widget(
|
|
131
|
-
self,
|
|
163
|
+
self,
|
|
164
|
+
parameter: SelectionParameter,
|
|
165
|
+
continuous: bool,
|
|
166
|
+
width: str = "auto",
|
|
167
|
+
margin: str = "3px 0px",
|
|
168
|
+
description_width: str = "initial",
|
|
132
169
|
) -> widgets.Dropdown:
|
|
133
170
|
return widgets.Dropdown(
|
|
134
171
|
value=parameter.value,
|
|
135
172
|
options=parameter.options,
|
|
136
173
|
description=parameter.name,
|
|
137
|
-
layout=widgets.Layout(width=
|
|
174
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
175
|
+
style={"description_width": description_width},
|
|
138
176
|
)
|
|
139
177
|
|
|
140
178
|
def matches_parameter(self, parameter: SelectionParameter) -> bool:
|
|
@@ -158,14 +196,20 @@ class MultipleSelectionWidget(
|
|
|
158
196
|
"""Widget for multiple selection parameters."""
|
|
159
197
|
|
|
160
198
|
def _create_widget(
|
|
161
|
-
self,
|
|
199
|
+
self,
|
|
200
|
+
parameter: MultipleSelectionParameter,
|
|
201
|
+
continuous: bool,
|
|
202
|
+
width: str = "auto",
|
|
203
|
+
margin: str = "3px 0px",
|
|
204
|
+
description_width: str = "initial",
|
|
162
205
|
) -> widgets.SelectMultiple:
|
|
163
206
|
return widgets.SelectMultiple(
|
|
164
207
|
value=parameter.value,
|
|
165
208
|
options=parameter.options,
|
|
166
209
|
description=parameter.name,
|
|
167
210
|
rows=min(len(parameter.options), 4),
|
|
168
|
-
layout=widgets.Layout(width=
|
|
211
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
212
|
+
style={"description_width": description_width},
|
|
169
213
|
)
|
|
170
214
|
|
|
171
215
|
def matches_parameter(self, parameter: MultipleSelectionParameter) -> bool:
|
|
@@ -189,155 +233,194 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
|
|
|
189
233
|
"""Widget for integer parameters."""
|
|
190
234
|
|
|
191
235
|
def _create_widget(
|
|
192
|
-
self,
|
|
236
|
+
self,
|
|
237
|
+
parameter: IntegerParameter,
|
|
238
|
+
continuous: bool,
|
|
239
|
+
width: str = "auto",
|
|
240
|
+
margin: str = "3px 0px",
|
|
241
|
+
description_width: str = "initial",
|
|
193
242
|
) -> widgets.IntSlider:
|
|
243
|
+
"""Create the integer slider widget."""
|
|
194
244
|
return widgets.IntSlider(
|
|
195
245
|
value=parameter.value,
|
|
196
|
-
min=parameter.
|
|
197
|
-
max=parameter.
|
|
246
|
+
min=parameter.min,
|
|
247
|
+
max=parameter.max,
|
|
248
|
+
step=1,
|
|
198
249
|
description=parameter.name,
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
250
|
+
continuous_update=continuous,
|
|
251
|
+
style={"description_width": description_width},
|
|
252
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
202
253
|
)
|
|
203
254
|
|
|
204
255
|
def matches_parameter(self, parameter: IntegerParameter) -> bool:
|
|
205
|
-
"""Check if the widget
|
|
256
|
+
"""Check if the widget values match the parameter."""
|
|
206
257
|
return (
|
|
207
|
-
self.
|
|
208
|
-
and self._widget.
|
|
209
|
-
and self._widget.
|
|
258
|
+
self._widget.description == parameter.name
|
|
259
|
+
and self._widget.value == parameter.value
|
|
260
|
+
and self._widget.min == parameter.min
|
|
261
|
+
and self._widget.max == parameter.max
|
|
210
262
|
)
|
|
211
263
|
|
|
212
264
|
def extra_updates_from_parameter(self, parameter: IntegerParameter) -> None:
|
|
213
|
-
"""
|
|
265
|
+
"""Update the widget attributes from the parameter."""
|
|
214
266
|
current_value = self._widget.value
|
|
215
|
-
self._widget.min = parameter.
|
|
216
|
-
self._widget.max = parameter.
|
|
217
|
-
self.value = max(parameter.
|
|
267
|
+
self._widget.min = parameter.min
|
|
268
|
+
self._widget.max = parameter.max
|
|
269
|
+
self.value = max(parameter.min, min(parameter.max, current_value))
|
|
218
270
|
|
|
219
271
|
|
|
220
272
|
class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
|
|
221
273
|
"""Widget for float parameters."""
|
|
222
274
|
|
|
223
275
|
def _create_widget(
|
|
224
|
-
self,
|
|
276
|
+
self,
|
|
277
|
+
parameter: FloatParameter,
|
|
278
|
+
continuous: bool,
|
|
279
|
+
width: str = "auto",
|
|
280
|
+
margin: str = "3px 0px",
|
|
281
|
+
description_width: str = "initial",
|
|
225
282
|
) -> widgets.FloatSlider:
|
|
283
|
+
"""Create the float slider widget."""
|
|
226
284
|
return widgets.FloatSlider(
|
|
227
285
|
value=parameter.value,
|
|
228
|
-
min=parameter.
|
|
229
|
-
max=parameter.
|
|
286
|
+
min=parameter.min,
|
|
287
|
+
max=parameter.max,
|
|
230
288
|
step=parameter.step,
|
|
231
289
|
description=parameter.name,
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
290
|
+
continuous_update=continuous,
|
|
291
|
+
style={"description_width": description_width},
|
|
292
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
235
293
|
)
|
|
236
294
|
|
|
237
295
|
def matches_parameter(self, parameter: FloatParameter) -> bool:
|
|
238
|
-
"""Check if the widget
|
|
296
|
+
"""Check if the widget values match the parameter."""
|
|
239
297
|
return (
|
|
240
|
-
self.
|
|
241
|
-
and self._widget.
|
|
242
|
-
and self._widget.
|
|
298
|
+
self._widget.description == parameter.name
|
|
299
|
+
and self._widget.value == parameter.value
|
|
300
|
+
and self._widget.min == parameter.min
|
|
301
|
+
and self._widget.max == parameter.max
|
|
302
|
+
and self._widget.step == parameter.step
|
|
243
303
|
)
|
|
244
304
|
|
|
245
305
|
def extra_updates_from_parameter(self, parameter: FloatParameter) -> None:
|
|
246
|
-
"""
|
|
306
|
+
"""Update the widget attributes from the parameter."""
|
|
247
307
|
current_value = self._widget.value
|
|
248
|
-
self._widget.min = parameter.
|
|
249
|
-
self._widget.max = parameter.
|
|
308
|
+
self._widget.min = parameter.min
|
|
309
|
+
self._widget.max = parameter.max
|
|
250
310
|
self._widget.step = parameter.step
|
|
251
|
-
self.value = max(parameter.
|
|
311
|
+
self.value = max(parameter.min, min(parameter.max, current_value))
|
|
252
312
|
|
|
253
313
|
|
|
254
314
|
class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlider]):
|
|
255
315
|
"""Widget for integer range parameters."""
|
|
256
316
|
|
|
257
317
|
def _create_widget(
|
|
258
|
-
self,
|
|
318
|
+
self,
|
|
319
|
+
parameter: IntegerRangeParameter,
|
|
320
|
+
continuous: bool,
|
|
321
|
+
width: str = "auto",
|
|
322
|
+
margin: str = "3px 0px",
|
|
323
|
+
description_width: str = "initial",
|
|
259
324
|
) -> widgets.IntRangeSlider:
|
|
325
|
+
"""Create the integer range slider widget."""
|
|
326
|
+
low, high = parameter.value
|
|
260
327
|
return widgets.IntRangeSlider(
|
|
261
|
-
value=
|
|
262
|
-
min=parameter.
|
|
263
|
-
max=parameter.
|
|
328
|
+
value=[low, high],
|
|
329
|
+
min=parameter.min,
|
|
330
|
+
max=parameter.max,
|
|
331
|
+
step=1,
|
|
264
332
|
description=parameter.name,
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
333
|
+
continuous_update=continuous,
|
|
334
|
+
style={"description_width": description_width},
|
|
335
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
268
336
|
)
|
|
269
337
|
|
|
270
338
|
def matches_parameter(self, parameter: IntegerRangeParameter) -> bool:
|
|
271
|
-
"""Check if the widget
|
|
339
|
+
"""Check if the widget values match the parameter."""
|
|
340
|
+
low, high = parameter.value
|
|
272
341
|
return (
|
|
273
|
-
self.
|
|
274
|
-
and self._widget.
|
|
275
|
-
and self._widget.
|
|
342
|
+
self._widget.description == parameter.name
|
|
343
|
+
and self._widget.value[0] == low
|
|
344
|
+
and self._widget.value[1] == high
|
|
345
|
+
and self._widget.min == parameter.min
|
|
346
|
+
and self._widget.max == parameter.max
|
|
276
347
|
)
|
|
277
348
|
|
|
278
349
|
def extra_updates_from_parameter(self, parameter: IntegerRangeParameter) -> None:
|
|
279
|
-
"""
|
|
280
|
-
|
|
281
|
-
self._widget.min = parameter.
|
|
282
|
-
self._widget.max = parameter.
|
|
283
|
-
|
|
284
|
-
low = max(parameter.
|
|
285
|
-
high = max(parameter.
|
|
286
|
-
self.value =
|
|
350
|
+
"""Update the widget attributes from the parameter."""
|
|
351
|
+
low, high = self._widget.value
|
|
352
|
+
self._widget.min = parameter.min
|
|
353
|
+
self._widget.max = parameter.max
|
|
354
|
+
# Ensure values stay within bounds
|
|
355
|
+
low = max(parameter.min, min(parameter.max, low))
|
|
356
|
+
high = max(parameter.min, min(parameter.max, high))
|
|
357
|
+
self.value = [low, high]
|
|
287
358
|
|
|
288
359
|
|
|
289
360
|
class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]):
|
|
290
361
|
"""Widget for float range parameters."""
|
|
291
362
|
|
|
292
363
|
def _create_widget(
|
|
293
|
-
self,
|
|
364
|
+
self,
|
|
365
|
+
parameter: FloatRangeParameter,
|
|
366
|
+
continuous: bool,
|
|
367
|
+
width: str = "auto",
|
|
368
|
+
margin: str = "3px 0px",
|
|
369
|
+
description_width: str = "initial",
|
|
294
370
|
) -> widgets.FloatRangeSlider:
|
|
371
|
+
"""Create the float range slider widget."""
|
|
372
|
+
low, high = parameter.value
|
|
295
373
|
return widgets.FloatRangeSlider(
|
|
296
|
-
value=
|
|
297
|
-
min=parameter.
|
|
298
|
-
max=parameter.
|
|
374
|
+
value=[low, high],
|
|
375
|
+
min=parameter.min,
|
|
376
|
+
max=parameter.max,
|
|
299
377
|
step=parameter.step,
|
|
300
378
|
description=parameter.name,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
379
|
+
continuous_update=continuous,
|
|
380
|
+
style={"description_width": description_width},
|
|
381
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
304
382
|
)
|
|
305
383
|
|
|
306
384
|
def matches_parameter(self, parameter: FloatRangeParameter) -> bool:
|
|
307
|
-
"""Check if the widget
|
|
385
|
+
"""Check if the widget values match the parameter."""
|
|
386
|
+
low, high = parameter.value
|
|
308
387
|
return (
|
|
309
|
-
self.
|
|
310
|
-
and self._widget.
|
|
311
|
-
and self._widget.
|
|
388
|
+
self._widget.description == parameter.name
|
|
389
|
+
and self._widget.value[0] == low
|
|
390
|
+
and self._widget.value[1] == high
|
|
391
|
+
and self._widget.min == parameter.min
|
|
392
|
+
and self._widget.max == parameter.max
|
|
393
|
+
and self._widget.step == parameter.step
|
|
312
394
|
)
|
|
313
395
|
|
|
314
396
|
def extra_updates_from_parameter(self, parameter: FloatRangeParameter) -> None:
|
|
315
|
-
"""
|
|
316
|
-
|
|
317
|
-
self._widget.min = parameter.
|
|
318
|
-
self._widget.max = parameter.
|
|
397
|
+
"""Update the widget attributes from the parameter."""
|
|
398
|
+
low, high = self._widget.value
|
|
399
|
+
self._widget.min = parameter.min
|
|
400
|
+
self._widget.max = parameter.max
|
|
319
401
|
self._widget.step = parameter.step
|
|
320
|
-
|
|
321
|
-
low = max(parameter.
|
|
322
|
-
high = max(parameter.
|
|
323
|
-
self.value =
|
|
402
|
+
# Ensure values stay within bounds
|
|
403
|
+
low = max(parameter.min, min(parameter.max, low))
|
|
404
|
+
high = max(parameter.min, min(parameter.max, high))
|
|
405
|
+
self.value = [low, high]
|
|
324
406
|
|
|
325
407
|
|
|
326
|
-
class UnboundedIntegerWidget(
|
|
327
|
-
BaseWidget[UnboundedIntegerParameter, widgets.BoundedIntText]
|
|
328
|
-
):
|
|
408
|
+
class UnboundedIntegerWidget(BaseWidget[UnboundedIntegerParameter, widgets.IntText]):
|
|
329
409
|
"""Widget for unbounded integer parameters."""
|
|
330
410
|
|
|
331
411
|
def _create_widget(
|
|
332
|
-
self,
|
|
333
|
-
|
|
334
|
-
|
|
412
|
+
self,
|
|
413
|
+
parameter: UnboundedIntegerParameter,
|
|
414
|
+
continuous: bool,
|
|
415
|
+
width: str = "auto",
|
|
416
|
+
margin: str = "3px 0px",
|
|
417
|
+
description_width: str = "initial",
|
|
418
|
+
) -> widgets.IntText:
|
|
419
|
+
return widgets.IntText(
|
|
335
420
|
value=parameter.value,
|
|
336
|
-
min=parameter.min_value,
|
|
337
|
-
max=parameter.max_value,
|
|
338
421
|
description=parameter.name,
|
|
339
|
-
layout=widgets.Layout(width=
|
|
340
|
-
style={"description_width":
|
|
422
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
423
|
+
style={"description_width": description_width},
|
|
341
424
|
)
|
|
342
425
|
|
|
343
426
|
def matches_parameter(self, parameter: UnboundedIntegerParameter) -> bool:
|
|
@@ -348,28 +431,26 @@ class UnboundedIntegerWidget(
|
|
|
348
431
|
self, parameter: UnboundedIntegerParameter
|
|
349
432
|
) -> None:
|
|
350
433
|
"""Extra updates from the parameter."""
|
|
351
|
-
|
|
352
|
-
self._widget.min = parameter.min_value
|
|
353
|
-
if parameter.max_value is not None:
|
|
354
|
-
self._widget.max = parameter.max_value
|
|
434
|
+
pass
|
|
355
435
|
|
|
356
436
|
|
|
357
|
-
class UnboundedFloatWidget(
|
|
358
|
-
BaseWidget[UnboundedFloatParameter, widgets.BoundedFloatText]
|
|
359
|
-
):
|
|
437
|
+
class UnboundedFloatWidget(BaseWidget[UnboundedFloatParameter, widgets.FloatText]):
|
|
360
438
|
"""Widget for unbounded float parameters."""
|
|
361
439
|
|
|
362
440
|
def _create_widget(
|
|
363
|
-
self,
|
|
364
|
-
|
|
365
|
-
|
|
441
|
+
self,
|
|
442
|
+
parameter: UnboundedFloatParameter,
|
|
443
|
+
continuous: bool,
|
|
444
|
+
width: str = "auto",
|
|
445
|
+
margin: str = "3px 0px",
|
|
446
|
+
description_width: str = "initial",
|
|
447
|
+
) -> widgets.FloatText:
|
|
448
|
+
return widgets.FloatText(
|
|
366
449
|
value=parameter.value,
|
|
367
|
-
min=parameter.min_value,
|
|
368
|
-
max=parameter.max_value,
|
|
369
450
|
step=parameter.step,
|
|
370
451
|
description=parameter.name,
|
|
371
|
-
layout=widgets.Layout(width=
|
|
372
|
-
style={"description_width":
|
|
452
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
453
|
+
style={"description_width": description_width},
|
|
373
454
|
)
|
|
374
455
|
|
|
375
456
|
def matches_parameter(self, parameter: UnboundedFloatParameter) -> bool:
|
|
@@ -378,10 +459,6 @@ class UnboundedFloatWidget(
|
|
|
378
459
|
|
|
379
460
|
def extra_updates_from_parameter(self, parameter: UnboundedFloatParameter) -> None:
|
|
380
461
|
"""Extra updates from the parameter."""
|
|
381
|
-
if parameter.min_value is not None:
|
|
382
|
-
self._widget.min = parameter.min_value
|
|
383
|
-
if parameter.max_value is not None:
|
|
384
|
-
self._widget.max = parameter.max_value
|
|
385
462
|
self._widget.step = parameter.step
|
|
386
463
|
|
|
387
464
|
|
|
@@ -391,14 +468,18 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
|
|
|
391
468
|
_is_action: bool = True
|
|
392
469
|
|
|
393
470
|
def _create_widget(
|
|
394
|
-
self,
|
|
471
|
+
self,
|
|
472
|
+
parameter: ButtonAction,
|
|
473
|
+
continuous: bool,
|
|
474
|
+
width: str = "auto",
|
|
475
|
+
margin: str = "3px 0px",
|
|
476
|
+
description_width: str = "initial",
|
|
395
477
|
) -> widgets.Button:
|
|
396
478
|
button = widgets.Button(
|
|
397
479
|
description=parameter.label,
|
|
398
|
-
layout=widgets.Layout(width=
|
|
399
|
-
style={"description_width":
|
|
480
|
+
layout=widgets.Layout(width=width, margin=margin),
|
|
481
|
+
style={"description_width": description_width},
|
|
400
482
|
)
|
|
401
|
-
button.on_click(parameter.callback)
|
|
402
483
|
return button
|
|
403
484
|
|
|
404
485
|
def matches_parameter(self, parameter: ButtonAction) -> bool:
|
|
@@ -407,41 +488,45 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
|
|
|
407
488
|
|
|
408
489
|
def extra_updates_from_parameter(self, parameter: ButtonAction) -> None:
|
|
409
490
|
"""Extra updates from the parameter."""
|
|
491
|
+
# Callbacks are handled in the deployer, so the only relevant update is the label
|
|
410
492
|
self._widget.description = parameter.label
|
|
411
|
-
# Update click handler
|
|
412
|
-
self._widget.on_click(parameter.callback, remove=True) # Remove old handler
|
|
413
|
-
self._widget.on_click(parameter.callback) # Add new handler
|
|
414
493
|
|
|
415
494
|
def observe(self, callback: Callable) -> None:
|
|
416
495
|
"""Observe the widget and call the callback when the value changes."""
|
|
496
|
+
if self._callbacks:
|
|
497
|
+
raise ValueError("ButtonWidget already has a callback!")
|
|
417
498
|
self._widget.on_click(callback)
|
|
418
|
-
self._callbacks
|
|
499
|
+
self._callbacks = callback
|
|
419
500
|
|
|
420
|
-
def unobserve(self, callback: Callable
|
|
501
|
+
def unobserve(self, callback: Callable) -> None:
|
|
421
502
|
"""Unobserve the widget and stop calling the callback when the value changes."""
|
|
422
|
-
self._widget.on_click(
|
|
423
|
-
self._callbacks
|
|
503
|
+
self._widget.on_click(callback, remove=True)
|
|
504
|
+
self._callbacks = []
|
|
424
505
|
|
|
425
506
|
def reenable_callbacks(self) -> None:
|
|
426
507
|
"""Reenable all callbacks from the widget."""
|
|
427
|
-
|
|
428
|
-
self._widget.on_click(callback)
|
|
508
|
+
self._widget.on_click(self._callbacks)
|
|
429
509
|
|
|
430
510
|
def disable_callbacks(self) -> None:
|
|
431
511
|
"""Disable all callbacks from the widget."""
|
|
432
|
-
|
|
433
|
-
self._widget.on_click(None)
|
|
512
|
+
self._widget.on_click(self._callbacks, remove=True)
|
|
434
513
|
|
|
435
514
|
|
|
436
515
|
def create_widget(
|
|
437
516
|
parameter: Union[Parameter[Any], ButtonAction],
|
|
438
517
|
continuous: bool = False,
|
|
518
|
+
width: str = "auto",
|
|
519
|
+
margin: str = "3px 0px",
|
|
520
|
+
description_width: str = "initial",
|
|
439
521
|
) -> BaseWidget[Union[Parameter[Any], ButtonAction], widgets.Widget]:
|
|
440
522
|
"""Create and return the appropriate widget for the given parameter.
|
|
441
523
|
|
|
442
524
|
Args:
|
|
443
525
|
parameter: The parameter to create a widget for
|
|
444
526
|
continuous: Whether to update the widget value continuously during user interaction
|
|
527
|
+
width: Width of the widget
|
|
528
|
+
margin: Margin of the widget
|
|
529
|
+
description_width: Width of the description label
|
|
445
530
|
"""
|
|
446
531
|
widget_map = {
|
|
447
532
|
TextParameter: TextWidget,
|
|
@@ -475,4 +560,10 @@ def create_widget(
|
|
|
475
560
|
f"Available types: {[k.__name__ for k in widget_map.keys()]}"
|
|
476
561
|
)
|
|
477
562
|
|
|
478
|
-
return widget_class(
|
|
563
|
+
return widget_class(
|
|
564
|
+
parameter,
|
|
565
|
+
continuous,
|
|
566
|
+
width=width,
|
|
567
|
+
margin=margin,
|
|
568
|
+
description_width=description_width,
|
|
569
|
+
)
|