syd 0.1.4__py3-none-any.whl → 0.1.6__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 +11 -1
- syd/flask_deployment/__init__.py +0 -0
- syd/flask_deployment/components.py +497 -0
- syd/flask_deployment/deployer.py +338 -0
- syd/flask_deployment/static/css/styles.css +39 -0
- syd/flask_deployment/static/js/components.js +51 -0
- syd/flask_deployment/static/js/viewer.js +0 -0
- syd/flask_deployment/templates/base.html +26 -0
- syd/flask_deployment/templates/viewer.html +97 -0
- syd/interactive_viewer.py +1314 -87
- syd/notebook_deployment/__init__.py +1 -0
- syd/notebook_deployment/deployer.py +254 -0
- syd/notebook_deployment/widgets.py +478 -0
- syd/parameters.py +1421 -157
- syd-0.1.6.dist-info/METADATA +106 -0
- syd-0.1.6.dist-info/RECORD +18 -0
- syd/notebook_deploy.py +0 -277
- syd-0.1.4.dist-info/METADATA +0 -33
- syd-0.1.4.dist-info/RECORD +0 -8
- {syd-0.1.4.dist-info → syd-0.1.6.dist-info}/WHEEL +0 -0
- {syd-0.1.4.dist-info → syd-0.1.6.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
from typing import Any, Dict, Generic, List, TypeVar, Union, Callable
|
|
3
|
+
import ipywidgets as widgets
|
|
4
|
+
|
|
5
|
+
from ..parameters import (
|
|
6
|
+
Parameter,
|
|
7
|
+
TextParameter,
|
|
8
|
+
SelectionParameter,
|
|
9
|
+
MultipleSelectionParameter,
|
|
10
|
+
BooleanParameter,
|
|
11
|
+
IntegerParameter,
|
|
12
|
+
FloatParameter,
|
|
13
|
+
IntegerRangeParameter,
|
|
14
|
+
FloatRangeParameter,
|
|
15
|
+
UnboundedIntegerParameter,
|
|
16
|
+
UnboundedFloatParameter,
|
|
17
|
+
ButtonAction,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
T = TypeVar("T", bound=Parameter[Any])
|
|
21
|
+
W = TypeVar("W", bound=widgets.Widget)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class BaseWidget(Generic[T, W], ABC):
|
|
25
|
+
"""
|
|
26
|
+
Abstract base class for all parameter widgets.
|
|
27
|
+
|
|
28
|
+
This class defines the common interface and shared functionality
|
|
29
|
+
for widgets that correspond to different parameter types.
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
_widget: W
|
|
33
|
+
_callbacks: List[Dict[str, Union[Callable, Union[str, List[str]]]]]
|
|
34
|
+
_is_action: bool = False
|
|
35
|
+
|
|
36
|
+
def __init__(self, parameter: T, continuous: bool = False):
|
|
37
|
+
self._widget = self._create_widget(parameter, continuous)
|
|
38
|
+
self._updating = False # Flag to prevent circular updates
|
|
39
|
+
# List of callbacks to remember for quick disabling/enabling
|
|
40
|
+
self._callbacks = []
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def _create_widget(self, parameter: T, continuous: bool) -> W:
|
|
44
|
+
"""Create and return the appropriate ipywidget."""
|
|
45
|
+
pass
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def widget(self) -> W:
|
|
49
|
+
"""Get the underlying ipywidget."""
|
|
50
|
+
return self._widget
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def value(self) -> Any:
|
|
54
|
+
"""Get the current value of the widget."""
|
|
55
|
+
return self._widget.value
|
|
56
|
+
|
|
57
|
+
@value.setter
|
|
58
|
+
def value(self, new_value: Any) -> None:
|
|
59
|
+
"""Set the value of the widget."""
|
|
60
|
+
self._widget.value = new_value
|
|
61
|
+
|
|
62
|
+
def matches_parameter(self, parameter: T) -> bool:
|
|
63
|
+
"""Check if the widget matches the parameter."""
|
|
64
|
+
return self.value == parameter.value
|
|
65
|
+
|
|
66
|
+
def update_from_parameter(self, parameter: T) -> None:
|
|
67
|
+
"""Update the widget from the parameter."""
|
|
68
|
+
try:
|
|
69
|
+
self._updating = True
|
|
70
|
+
self.disable_callbacks()
|
|
71
|
+
self.extra_updates_from_parameter(parameter)
|
|
72
|
+
self.value = parameter.value
|
|
73
|
+
finally:
|
|
74
|
+
self.reenable_callbacks()
|
|
75
|
+
self._updating = False
|
|
76
|
+
|
|
77
|
+
def extra_updates_from_parameter(self, parameter: T) -> None:
|
|
78
|
+
"""Extra updates from the parameter."""
|
|
79
|
+
pass
|
|
80
|
+
|
|
81
|
+
def observe(self, callback: Callable) -> None:
|
|
82
|
+
"""Observe the widget and call the callback when the value changes."""
|
|
83
|
+
full_callback = dict(handler=callback, names="value")
|
|
84
|
+
self._widget.observe(**full_callback)
|
|
85
|
+
self._callbacks.append(full_callback)
|
|
86
|
+
|
|
87
|
+
def unobserve(self, callback: Callable[[Any], None]) -> None:
|
|
88
|
+
"""Unobserve the widget and stop calling the callback when the value changes."""
|
|
89
|
+
full_callback = dict(handler=callback, names="value")
|
|
90
|
+
self._widget.unobserve(**full_callback)
|
|
91
|
+
self._callbacks.remove(full_callback)
|
|
92
|
+
|
|
93
|
+
def reenable_callbacks(self) -> None:
|
|
94
|
+
"""Reenable all callbacks from the widget."""
|
|
95
|
+
for callback in self._callbacks:
|
|
96
|
+
self._widget.observe(**callback)
|
|
97
|
+
|
|
98
|
+
def disable_callbacks(self) -> None:
|
|
99
|
+
"""Disable all callbacks from the widget."""
|
|
100
|
+
for callback in self._callbacks:
|
|
101
|
+
self._widget.unobserve(**callback)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class TextWidget(BaseWidget[TextParameter, widgets.Text]):
|
|
105
|
+
"""Widget for text parameters."""
|
|
106
|
+
|
|
107
|
+
def _create_widget(
|
|
108
|
+
self, parameter: TextParameter, continuous: bool
|
|
109
|
+
) -> widgets.Text:
|
|
110
|
+
return widgets.Text(
|
|
111
|
+
value=parameter.value,
|
|
112
|
+
description=parameter.name,
|
|
113
|
+
continuous=continuous,
|
|
114
|
+
layout=widgets.Layout(width="95%"),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class BooleanWidget(BaseWidget[BooleanParameter, widgets.Checkbox]):
|
|
119
|
+
"""Widget for boolean parameters."""
|
|
120
|
+
|
|
121
|
+
def _create_widget(
|
|
122
|
+
self, parameter: BooleanParameter, continuous: bool
|
|
123
|
+
) -> widgets.Checkbox:
|
|
124
|
+
return widgets.Checkbox(value=parameter.value, description=parameter.name)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class SelectionWidget(BaseWidget[SelectionParameter, widgets.Dropdown]):
|
|
128
|
+
"""Widget for single selection parameters."""
|
|
129
|
+
|
|
130
|
+
def _create_widget(
|
|
131
|
+
self, parameter: SelectionParameter, continuous: bool
|
|
132
|
+
) -> widgets.Dropdown:
|
|
133
|
+
return widgets.Dropdown(
|
|
134
|
+
value=parameter.value,
|
|
135
|
+
options=parameter.options,
|
|
136
|
+
description=parameter.name,
|
|
137
|
+
layout=widgets.Layout(width="95%"),
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
def matches_parameter(self, parameter: SelectionParameter) -> bool:
|
|
141
|
+
"""Check if the widget matches the parameter."""
|
|
142
|
+
return (
|
|
143
|
+
self.value == parameter.value and self._widget.options == parameter.options
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
def extra_updates_from_parameter(self, parameter: SelectionParameter) -> None:
|
|
147
|
+
"""Extra updates from the parameter."""
|
|
148
|
+
new_options = parameter.options
|
|
149
|
+
current_value = self._widget.value
|
|
150
|
+
new_value = current_value if current_value in new_options else new_options[0]
|
|
151
|
+
self._widget.options = new_options
|
|
152
|
+
self._widget.value = new_value
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class MultipleSelectionWidget(
|
|
156
|
+
BaseWidget[MultipleSelectionParameter, widgets.SelectMultiple]
|
|
157
|
+
):
|
|
158
|
+
"""Widget for multiple selection parameters."""
|
|
159
|
+
|
|
160
|
+
def _create_widget(
|
|
161
|
+
self, parameter: MultipleSelectionParameter, continuous: bool
|
|
162
|
+
) -> widgets.SelectMultiple:
|
|
163
|
+
return widgets.SelectMultiple(
|
|
164
|
+
value=parameter.value,
|
|
165
|
+
options=parameter.options,
|
|
166
|
+
description=parameter.name,
|
|
167
|
+
rows=min(len(parameter.options), 4),
|
|
168
|
+
layout=widgets.Layout(width="95%"),
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
def matches_parameter(self, parameter: MultipleSelectionParameter) -> bool:
|
|
172
|
+
"""Check if the widget matches the parameter."""
|
|
173
|
+
return (
|
|
174
|
+
self.value == parameter.value and self._widget.options == parameter.options
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
def extra_updates_from_parameter(
|
|
178
|
+
self, parameter: MultipleSelectionParameter
|
|
179
|
+
) -> None:
|
|
180
|
+
"""Extra updates from the parameter."""
|
|
181
|
+
new_options = parameter.options
|
|
182
|
+
current_values = set(self._widget.value)
|
|
183
|
+
new_values = [v for v in current_values if v in new_options]
|
|
184
|
+
self._widget.options = new_options
|
|
185
|
+
self._widget.value = new_values
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
|
|
189
|
+
"""Widget for integer parameters."""
|
|
190
|
+
|
|
191
|
+
def _create_widget(
|
|
192
|
+
self, parameter: IntegerParameter, continuous: bool
|
|
193
|
+
) -> widgets.IntSlider:
|
|
194
|
+
return widgets.IntSlider(
|
|
195
|
+
value=parameter.value,
|
|
196
|
+
min=parameter.min_value,
|
|
197
|
+
max=parameter.max_value,
|
|
198
|
+
description=parameter.name,
|
|
199
|
+
continuous=continuous,
|
|
200
|
+
layout=widgets.Layout(width="95%"),
|
|
201
|
+
style={"description_width": "initial"},
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
def matches_parameter(self, parameter: IntegerParameter) -> bool:
|
|
205
|
+
"""Check if the widget matches the parameter."""
|
|
206
|
+
return (
|
|
207
|
+
self.value == parameter.value
|
|
208
|
+
and self._widget.min == parameter.min_value
|
|
209
|
+
and self._widget.max == parameter.max_value
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
def extra_updates_from_parameter(self, parameter: IntegerParameter) -> None:
|
|
213
|
+
"""Extra updates from the parameter."""
|
|
214
|
+
current_value = self._widget.value
|
|
215
|
+
self._widget.min = parameter.min_value
|
|
216
|
+
self._widget.max = parameter.max_value
|
|
217
|
+
self.value = max(parameter.min_value, min(parameter.max_value, current_value))
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
|
|
221
|
+
"""Widget for float parameters."""
|
|
222
|
+
|
|
223
|
+
def _create_widget(
|
|
224
|
+
self, parameter: FloatParameter, continuous: bool
|
|
225
|
+
) -> widgets.FloatSlider:
|
|
226
|
+
return widgets.FloatSlider(
|
|
227
|
+
value=parameter.value,
|
|
228
|
+
min=parameter.min_value,
|
|
229
|
+
max=parameter.max_value,
|
|
230
|
+
step=parameter.step,
|
|
231
|
+
description=parameter.name,
|
|
232
|
+
continuous=continuous,
|
|
233
|
+
layout=widgets.Layout(width="95%"),
|
|
234
|
+
style={"description_width": "initial"},
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
def matches_parameter(self, parameter: FloatParameter) -> bool:
|
|
238
|
+
"""Check if the widget matches the parameter."""
|
|
239
|
+
return (
|
|
240
|
+
self.value == parameter.value
|
|
241
|
+
and self._widget.min == parameter.min_value
|
|
242
|
+
and self._widget.max == parameter.max_value
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
def extra_updates_from_parameter(self, parameter: FloatParameter) -> None:
|
|
246
|
+
"""Extra updates from the parameter."""
|
|
247
|
+
current_value = self._widget.value
|
|
248
|
+
self._widget.min = parameter.min_value
|
|
249
|
+
self._widget.max = parameter.max_value
|
|
250
|
+
self._widget.step = parameter.step
|
|
251
|
+
self.value = max(parameter.min_value, min(parameter.max_value, current_value))
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlider]):
|
|
255
|
+
"""Widget for integer range parameters."""
|
|
256
|
+
|
|
257
|
+
def _create_widget(
|
|
258
|
+
self, parameter: IntegerRangeParameter, continuous: bool
|
|
259
|
+
) -> widgets.IntRangeSlider:
|
|
260
|
+
return widgets.IntRangeSlider(
|
|
261
|
+
value=parameter.value,
|
|
262
|
+
min=parameter.min_value,
|
|
263
|
+
max=parameter.max_value,
|
|
264
|
+
description=parameter.name,
|
|
265
|
+
continuous=continuous,
|
|
266
|
+
layout=widgets.Layout(width="95%"),
|
|
267
|
+
style={"description_width": "initial"},
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
def matches_parameter(self, parameter: IntegerRangeParameter) -> bool:
|
|
271
|
+
"""Check if the widget matches the parameter."""
|
|
272
|
+
return (
|
|
273
|
+
self.value == parameter.value
|
|
274
|
+
and self._widget.min == parameter.min_value
|
|
275
|
+
and self._widget.max == parameter.max_value
|
|
276
|
+
)
|
|
277
|
+
|
|
278
|
+
def extra_updates_from_parameter(self, parameter: IntegerRangeParameter) -> None:
|
|
279
|
+
"""Extra updates from the parameter."""
|
|
280
|
+
current_value = self._widget.value
|
|
281
|
+
self._widget.min = parameter.min_value
|
|
282
|
+
self._widget.max = parameter.max_value
|
|
283
|
+
low, high = current_value
|
|
284
|
+
low = max(parameter.min_value, min(parameter.max_value, low))
|
|
285
|
+
high = max(parameter.min_value, min(parameter.max_value, high))
|
|
286
|
+
self.value = (low, high)
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]):
|
|
290
|
+
"""Widget for float range parameters."""
|
|
291
|
+
|
|
292
|
+
def _create_widget(
|
|
293
|
+
self, parameter: FloatRangeParameter, continuous: bool
|
|
294
|
+
) -> widgets.FloatRangeSlider:
|
|
295
|
+
return widgets.FloatRangeSlider(
|
|
296
|
+
value=parameter.value,
|
|
297
|
+
min=parameter.min_value,
|
|
298
|
+
max=parameter.max_value,
|
|
299
|
+
step=parameter.step,
|
|
300
|
+
description=parameter.name,
|
|
301
|
+
continuous=continuous,
|
|
302
|
+
layout=widgets.Layout(width="95%"),
|
|
303
|
+
style={"description_width": "initial"},
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
def matches_parameter(self, parameter: FloatRangeParameter) -> bool:
|
|
307
|
+
"""Check if the widget matches the parameter."""
|
|
308
|
+
return (
|
|
309
|
+
self.value == parameter.value
|
|
310
|
+
and self._widget.min == parameter.min_value
|
|
311
|
+
and self._widget.max == parameter.max_value
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
def extra_updates_from_parameter(self, parameter: FloatRangeParameter) -> None:
|
|
315
|
+
"""Extra updates from the parameter."""
|
|
316
|
+
current_value = self._widget.value
|
|
317
|
+
self._widget.min = parameter.min_value
|
|
318
|
+
self._widget.max = parameter.max_value
|
|
319
|
+
self._widget.step = parameter.step
|
|
320
|
+
low, high = current_value
|
|
321
|
+
low = max(parameter.min_value, min(parameter.max_value, low))
|
|
322
|
+
high = max(parameter.min_value, min(parameter.max_value, high))
|
|
323
|
+
self.value = (low, high)
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
class UnboundedIntegerWidget(
|
|
327
|
+
BaseWidget[UnboundedIntegerParameter, widgets.BoundedIntText]
|
|
328
|
+
):
|
|
329
|
+
"""Widget for unbounded integer parameters."""
|
|
330
|
+
|
|
331
|
+
def _create_widget(
|
|
332
|
+
self, parameter: UnboundedIntegerParameter, continuous: bool
|
|
333
|
+
) -> widgets.BoundedIntText:
|
|
334
|
+
return widgets.BoundedIntText(
|
|
335
|
+
value=parameter.value,
|
|
336
|
+
min=parameter.min_value,
|
|
337
|
+
max=parameter.max_value,
|
|
338
|
+
description=parameter.name,
|
|
339
|
+
layout=widgets.Layout(width="95%"),
|
|
340
|
+
style={"description_width": "initial"},
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
def matches_parameter(self, parameter: UnboundedIntegerParameter) -> bool:
|
|
344
|
+
"""Check if the widget matches the parameter."""
|
|
345
|
+
return self.value == parameter.value
|
|
346
|
+
|
|
347
|
+
def extra_updates_from_parameter(
|
|
348
|
+
self, parameter: UnboundedIntegerParameter
|
|
349
|
+
) -> None:
|
|
350
|
+
"""Extra updates from the parameter."""
|
|
351
|
+
if parameter.min_value is not None:
|
|
352
|
+
self._widget.min = parameter.min_value
|
|
353
|
+
if parameter.max_value is not None:
|
|
354
|
+
self._widget.max = parameter.max_value
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
class UnboundedFloatWidget(
|
|
358
|
+
BaseWidget[UnboundedFloatParameter, widgets.BoundedFloatText]
|
|
359
|
+
):
|
|
360
|
+
"""Widget for unbounded float parameters."""
|
|
361
|
+
|
|
362
|
+
def _create_widget(
|
|
363
|
+
self, parameter: UnboundedFloatParameter, continuous: bool
|
|
364
|
+
) -> widgets.BoundedFloatText:
|
|
365
|
+
return widgets.BoundedFloatText(
|
|
366
|
+
value=parameter.value,
|
|
367
|
+
min=parameter.min_value,
|
|
368
|
+
max=parameter.max_value,
|
|
369
|
+
step=parameter.step,
|
|
370
|
+
description=parameter.name,
|
|
371
|
+
layout=widgets.Layout(width="95%"),
|
|
372
|
+
style={"description_width": "initial"},
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
def matches_parameter(self, parameter: UnboundedFloatParameter) -> bool:
|
|
376
|
+
"""Check if the widget matches the parameter."""
|
|
377
|
+
return self.value == parameter.value
|
|
378
|
+
|
|
379
|
+
def extra_updates_from_parameter(self, parameter: UnboundedFloatParameter) -> None:
|
|
380
|
+
"""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
|
+
self._widget.step = parameter.step
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
|
|
389
|
+
"""Widget for button parameters."""
|
|
390
|
+
|
|
391
|
+
_is_action: bool = True
|
|
392
|
+
|
|
393
|
+
def _create_widget(
|
|
394
|
+
self, parameter: ButtonAction, continuous: bool
|
|
395
|
+
) -> widgets.Button:
|
|
396
|
+
button = widgets.Button(
|
|
397
|
+
description=parameter.label,
|
|
398
|
+
layout=widgets.Layout(width="auto"),
|
|
399
|
+
style={"description_width": "initial"},
|
|
400
|
+
)
|
|
401
|
+
button.on_click(parameter.callback)
|
|
402
|
+
return button
|
|
403
|
+
|
|
404
|
+
def matches_parameter(self, parameter: ButtonAction) -> bool:
|
|
405
|
+
"""Check if the widget matches the parameter."""
|
|
406
|
+
return self._widget.description == parameter.label
|
|
407
|
+
|
|
408
|
+
def extra_updates_from_parameter(self, parameter: ButtonAction) -> None:
|
|
409
|
+
"""Extra updates from the parameter."""
|
|
410
|
+
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
|
+
|
|
415
|
+
def observe(self, callback: Callable) -> None:
|
|
416
|
+
"""Observe the widget and call the callback when the value changes."""
|
|
417
|
+
self._widget.on_click(callback)
|
|
418
|
+
self._callbacks.append(callback)
|
|
419
|
+
|
|
420
|
+
def unobserve(self, callback: Callable[[Any], None]) -> None:
|
|
421
|
+
"""Unobserve the widget and stop calling the callback when the value changes."""
|
|
422
|
+
self._widget.on_click(None)
|
|
423
|
+
self._callbacks.remove(callback)
|
|
424
|
+
|
|
425
|
+
def reenable_callbacks(self) -> None:
|
|
426
|
+
"""Reenable all callbacks from the widget."""
|
|
427
|
+
for callback in self._callbacks:
|
|
428
|
+
self._widget.on_click(callback)
|
|
429
|
+
|
|
430
|
+
def disable_callbacks(self) -> None:
|
|
431
|
+
"""Disable all callbacks from the widget."""
|
|
432
|
+
for callback in self._callbacks:
|
|
433
|
+
self._widget.on_click(None)
|
|
434
|
+
|
|
435
|
+
|
|
436
|
+
def create_widget(
|
|
437
|
+
parameter: Union[Parameter[Any], ButtonAction],
|
|
438
|
+
continuous: bool = False,
|
|
439
|
+
) -> BaseWidget[Union[Parameter[Any], ButtonAction], widgets.Widget]:
|
|
440
|
+
"""Create and return the appropriate widget for the given parameter.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
parameter: The parameter to create a widget for
|
|
444
|
+
continuous: Whether to update the widget value continuously during user interaction
|
|
445
|
+
"""
|
|
446
|
+
widget_map = {
|
|
447
|
+
TextParameter: TextWidget,
|
|
448
|
+
SelectionParameter: SelectionWidget,
|
|
449
|
+
MultipleSelectionParameter: MultipleSelectionWidget,
|
|
450
|
+
BooleanParameter: BooleanWidget,
|
|
451
|
+
IntegerParameter: IntegerWidget,
|
|
452
|
+
FloatParameter: FloatWidget,
|
|
453
|
+
IntegerRangeParameter: IntegerRangeWidget,
|
|
454
|
+
FloatRangeParameter: FloatRangeWidget,
|
|
455
|
+
UnboundedIntegerParameter: UnboundedIntegerWidget,
|
|
456
|
+
UnboundedFloatParameter: UnboundedFloatWidget,
|
|
457
|
+
ButtonAction: ButtonWidget,
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
# Try direct type lookup first
|
|
461
|
+
widget_class = widget_map.get(type(parameter))
|
|
462
|
+
|
|
463
|
+
# If that fails, try matching by class name
|
|
464
|
+
if widget_class is None:
|
|
465
|
+
param_type_name = type(parameter).__name__
|
|
466
|
+
for key_class, value_class in widget_map.items():
|
|
467
|
+
if key_class.__name__ == param_type_name:
|
|
468
|
+
widget_class = value_class
|
|
469
|
+
break
|
|
470
|
+
|
|
471
|
+
if widget_class is None:
|
|
472
|
+
raise ValueError(
|
|
473
|
+
f"No widget implementation for parameter type: {type(parameter)}\n"
|
|
474
|
+
f"Parameter type name: {type(parameter).__name__}\n"
|
|
475
|
+
f"Available types: {[k.__name__ for k in widget_map.keys()]}"
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
return widget_class(parameter, continuous)
|