syd 0.1.6__py3-none-any.whl → 0.1.7__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.
@@ -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__(self, parameter: T, continuous: bool = False):
37
- self._widget = self._create_widget(parameter, continuous)
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(self, parameter: T, continuous: bool) -> W:
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, parameter: TextParameter, continuous: bool
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="95%"),
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.Checkbox]):
140
+ class BooleanWidget(BaseWidget[BooleanParameter, widgets.ToggleButton]):
119
141
  """Widget for boolean parameters."""
120
142
 
121
143
  def _create_widget(
122
- self, parameter: BooleanParameter, continuous: bool
123
- ) -> widgets.Checkbox:
124
- return widgets.Checkbox(value=parameter.value, description=parameter.name)
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, parameter: SelectionParameter, continuous: bool
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="95%"),
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, parameter: MultipleSelectionParameter, continuous: bool
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="95%"),
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,7 +233,12 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
189
233
  """Widget for integer parameters."""
190
234
 
191
235
  def _create_widget(
192
- self, parameter: IntegerParameter, continuous: bool
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:
194
243
  return widgets.IntSlider(
195
244
  value=parameter.value,
@@ -197,8 +246,8 @@ class IntegerWidget(BaseWidget[IntegerParameter, widgets.IntSlider]):
197
246
  max=parameter.max_value,
198
247
  description=parameter.name,
199
248
  continuous=continuous,
200
- layout=widgets.Layout(width="95%"),
201
- style={"description_width": "initial"},
249
+ layout=widgets.Layout(width=width, margin=margin),
250
+ style={"description_width": description_width},
202
251
  )
203
252
 
204
253
  def matches_parameter(self, parameter: IntegerParameter) -> bool:
@@ -221,7 +270,12 @@ class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
221
270
  """Widget for float parameters."""
222
271
 
223
272
  def _create_widget(
224
- self, parameter: FloatParameter, continuous: bool
273
+ self,
274
+ parameter: FloatParameter,
275
+ continuous: bool,
276
+ width: str = "auto",
277
+ margin: str = "3px 0px",
278
+ description_width: str = "initial",
225
279
  ) -> widgets.FloatSlider:
226
280
  return widgets.FloatSlider(
227
281
  value=parameter.value,
@@ -230,8 +284,8 @@ class FloatWidget(BaseWidget[FloatParameter, widgets.FloatSlider]):
230
284
  step=parameter.step,
231
285
  description=parameter.name,
232
286
  continuous=continuous,
233
- layout=widgets.Layout(width="95%"),
234
- style={"description_width": "initial"},
287
+ layout=widgets.Layout(width=width, margin=margin),
288
+ style={"description_width": description_width},
235
289
  )
236
290
 
237
291
  def matches_parameter(self, parameter: FloatParameter) -> bool:
@@ -255,7 +309,12 @@ class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlide
255
309
  """Widget for integer range parameters."""
256
310
 
257
311
  def _create_widget(
258
- self, parameter: IntegerRangeParameter, continuous: bool
312
+ self,
313
+ parameter: IntegerRangeParameter,
314
+ continuous: bool,
315
+ width: str = "auto",
316
+ margin: str = "3px 0px",
317
+ description_width: str = "initial",
259
318
  ) -> widgets.IntRangeSlider:
260
319
  return widgets.IntRangeSlider(
261
320
  value=parameter.value,
@@ -263,8 +322,8 @@ class IntegerRangeWidget(BaseWidget[IntegerRangeParameter, widgets.IntRangeSlide
263
322
  max=parameter.max_value,
264
323
  description=parameter.name,
265
324
  continuous=continuous,
266
- layout=widgets.Layout(width="95%"),
267
- style={"description_width": "initial"},
325
+ layout=widgets.Layout(width=width, margin=margin),
326
+ style={"description_width": description_width},
268
327
  )
269
328
 
270
329
  def matches_parameter(self, parameter: IntegerRangeParameter) -> bool:
@@ -290,7 +349,12 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
290
349
  """Widget for float range parameters."""
291
350
 
292
351
  def _create_widget(
293
- self, parameter: FloatRangeParameter, continuous: bool
352
+ self,
353
+ parameter: FloatRangeParameter,
354
+ continuous: bool,
355
+ width: str = "auto",
356
+ margin: str = "3px 0px",
357
+ description_width: str = "initial",
294
358
  ) -> widgets.FloatRangeSlider:
295
359
  return widgets.FloatRangeSlider(
296
360
  value=parameter.value,
@@ -299,8 +363,8 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
299
363
  step=parameter.step,
300
364
  description=parameter.name,
301
365
  continuous=continuous,
302
- layout=widgets.Layout(width="95%"),
303
- style={"description_width": "initial"},
366
+ layout=widgets.Layout(width=width, margin=margin),
367
+ style={"description_width": description_width},
304
368
  )
305
369
 
306
370
  def matches_parameter(self, parameter: FloatRangeParameter) -> bool:
@@ -323,21 +387,22 @@ class FloatRangeWidget(BaseWidget[FloatRangeParameter, widgets.FloatRangeSlider]
323
387
  self.value = (low, high)
324
388
 
325
389
 
326
- class UnboundedIntegerWidget(
327
- BaseWidget[UnboundedIntegerParameter, widgets.BoundedIntText]
328
- ):
390
+ class UnboundedIntegerWidget(BaseWidget[UnboundedIntegerParameter, widgets.IntText]):
329
391
  """Widget for unbounded integer parameters."""
330
392
 
331
393
  def _create_widget(
332
- self, parameter: UnboundedIntegerParameter, continuous: bool
333
- ) -> widgets.BoundedIntText:
334
- return widgets.BoundedIntText(
394
+ self,
395
+ parameter: UnboundedIntegerParameter,
396
+ continuous: bool,
397
+ width: str = "auto",
398
+ margin: str = "3px 0px",
399
+ description_width: str = "initial",
400
+ ) -> widgets.IntText:
401
+ return widgets.IntText(
335
402
  value=parameter.value,
336
- min=parameter.min_value,
337
- max=parameter.max_value,
338
403
  description=parameter.name,
339
- layout=widgets.Layout(width="95%"),
340
- style={"description_width": "initial"},
404
+ layout=widgets.Layout(width=width, margin=margin),
405
+ style={"description_width": description_width},
341
406
  )
342
407
 
343
408
  def matches_parameter(self, parameter: UnboundedIntegerParameter) -> bool:
@@ -348,28 +413,26 @@ class UnboundedIntegerWidget(
348
413
  self, parameter: UnboundedIntegerParameter
349
414
  ) -> None:
350
415
  """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
416
+ pass
355
417
 
356
418
 
357
- class UnboundedFloatWidget(
358
- BaseWidget[UnboundedFloatParameter, widgets.BoundedFloatText]
359
- ):
419
+ class UnboundedFloatWidget(BaseWidget[UnboundedFloatParameter, widgets.FloatText]):
360
420
  """Widget for unbounded float parameters."""
361
421
 
362
422
  def _create_widget(
363
- self, parameter: UnboundedFloatParameter, continuous: bool
364
- ) -> widgets.BoundedFloatText:
365
- return widgets.BoundedFloatText(
423
+ self,
424
+ parameter: UnboundedFloatParameter,
425
+ continuous: bool,
426
+ width: str = "auto",
427
+ margin: str = "3px 0px",
428
+ description_width: str = "initial",
429
+ ) -> widgets.FloatText:
430
+ return widgets.FloatText(
366
431
  value=parameter.value,
367
- min=parameter.min_value,
368
- max=parameter.max_value,
369
432
  step=parameter.step,
370
433
  description=parameter.name,
371
- layout=widgets.Layout(width="95%"),
372
- style={"description_width": "initial"},
434
+ layout=widgets.Layout(width=width, margin=margin),
435
+ style={"description_width": description_width},
373
436
  )
374
437
 
375
438
  def matches_parameter(self, parameter: UnboundedFloatParameter) -> bool:
@@ -378,10 +441,6 @@ class UnboundedFloatWidget(
378
441
 
379
442
  def extra_updates_from_parameter(self, parameter: UnboundedFloatParameter) -> None:
380
443
  """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
444
  self._widget.step = parameter.step
386
445
 
387
446
 
@@ -391,14 +450,18 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
391
450
  _is_action: bool = True
392
451
 
393
452
  def _create_widget(
394
- self, parameter: ButtonAction, continuous: bool
453
+ self,
454
+ parameter: ButtonAction,
455
+ continuous: bool,
456
+ width: str = "auto",
457
+ margin: str = "3px 0px",
458
+ description_width: str = "initial",
395
459
  ) -> widgets.Button:
396
460
  button = widgets.Button(
397
461
  description=parameter.label,
398
- layout=widgets.Layout(width="auto"),
399
- style={"description_width": "initial"},
462
+ layout=widgets.Layout(width=width, margin=margin),
463
+ style={"description_width": description_width},
400
464
  )
401
- button.on_click(parameter.callback)
402
465
  return button
403
466
 
404
467
  def matches_parameter(self, parameter: ButtonAction) -> bool:
@@ -407,41 +470,45 @@ class ButtonWidget(BaseWidget[ButtonAction, widgets.Button]):
407
470
 
408
471
  def extra_updates_from_parameter(self, parameter: ButtonAction) -> None:
409
472
  """Extra updates from the parameter."""
473
+ # Callbacks are handled in the deployer, so the only relevant update is the label
410
474
  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
475
 
415
476
  def observe(self, callback: Callable) -> None:
416
477
  """Observe the widget and call the callback when the value changes."""
478
+ if self._callbacks:
479
+ raise ValueError("ButtonWidget already has a callback!")
417
480
  self._widget.on_click(callback)
418
- self._callbacks.append(callback)
481
+ self._callbacks = callback
419
482
 
420
- def unobserve(self, callback: Callable[[Any], None]) -> None:
483
+ def unobserve(self, callback: Callable) -> None:
421
484
  """Unobserve the widget and stop calling the callback when the value changes."""
422
- self._widget.on_click(None)
423
- self._callbacks.remove(callback)
485
+ self._widget.on_click(callback, remove=True)
486
+ self._callbacks = []
424
487
 
425
488
  def reenable_callbacks(self) -> None:
426
489
  """Reenable all callbacks from the widget."""
427
- for callback in self._callbacks:
428
- self._widget.on_click(callback)
490
+ self._widget.on_click(self._callbacks)
429
491
 
430
492
  def disable_callbacks(self) -> None:
431
493
  """Disable all callbacks from the widget."""
432
- for callback in self._callbacks:
433
- self._widget.on_click(None)
494
+ self._widget.on_click(self._callbacks, remove=True)
434
495
 
435
496
 
436
497
  def create_widget(
437
498
  parameter: Union[Parameter[Any], ButtonAction],
438
499
  continuous: bool = False,
500
+ width: str = "auto",
501
+ margin: str = "3px 0px",
502
+ description_width: str = "initial",
439
503
  ) -> BaseWidget[Union[Parameter[Any], ButtonAction], widgets.Widget]:
440
504
  """Create and return the appropriate widget for the given parameter.
441
505
 
442
506
  Args:
443
507
  parameter: The parameter to create a widget for
444
508
  continuous: Whether to update the widget value continuously during user interaction
509
+ width: Width of the widget
510
+ margin: Margin of the widget
511
+ description_width: Width of the description label
445
512
  """
446
513
  widget_map = {
447
514
  TextParameter: TextWidget,
@@ -475,4 +542,10 @@ def create_widget(
475
542
  f"Available types: {[k.__name__ for k in widget_map.keys()]}"
476
543
  )
477
544
 
478
- return widget_class(parameter, continuous)
545
+ return widget_class(
546
+ parameter,
547
+ continuous,
548
+ width=width,
549
+ margin=margin,
550
+ description_width=description_width,
551
+ )