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.
syd/parameters.py CHANGED
@@ -1,17 +1,6 @@
1
- from typing import (
2
- List,
3
- Any,
4
- Tuple,
5
- Generic,
6
- TypeVar,
7
- Optional,
8
- Dict,
9
- Callable,
10
- Union,
11
- Sequence,
12
- )
1
+ from typing import List, Any, Tuple, Generic, TypeVar, Optional, Dict, Callable, Union
13
2
  from dataclasses import dataclass, field
14
- from abc import ABC, abstractmethod
3
+ from abc import ABC, ABCMeta, abstractmethod
15
4
  from enum import Enum
16
5
  from copy import deepcopy
17
6
  from warnings import warn
@@ -117,8 +106,39 @@ def get_parameter_attributes(param_class) -> List[str]:
117
106
  return attributes
118
107
 
119
108
 
109
+ class ParameterMeta(ABCMeta):
110
+ _parameter_types = {}
111
+ _parameter_ids = {} # Store unique identifiers for our parameter types
112
+
113
+ def __new__(cls, name, bases, namespace):
114
+ parameter_class = super().__new__(cls, name, bases, namespace)
115
+ if name != "Parameter":
116
+ # Generate a unique ID for this parameter type
117
+ type_id = f"syd.parameters.{name}" # Using fully qualified name
118
+ cls._parameter_ids[name] = type_id
119
+
120
+ # Add ID to the class
121
+ if not hasattr(parameter_class, "_parameter_type_id"):
122
+ setattr(parameter_class, "_parameter_type_id", type_id)
123
+ else:
124
+ if getattr(parameter_class, "_parameter_type_id") != type_id:
125
+ raise ValueError(
126
+ f"Parameter type {name} has multiple IDs: {type_id} and {getattr(parameter_class, '_parameter_type_id')}"
127
+ )
128
+ cls._parameter_types[name] = parameter_class
129
+ return parameter_class
130
+
131
+ def __instancecheck__(cls, instance):
132
+ type_id = cls._parameter_ids.get(cls.__name__)
133
+ if not type_id:
134
+ return False
135
+
136
+ # Check if instance has our type ID
137
+ return getattr(instance.__class__, "_parameter_type_id", None) == type_id
138
+
139
+
120
140
  @dataclass
121
- class Parameter(Generic[T], ABC):
141
+ class Parameter(Generic[T], ABC, metaclass=ParameterMeta):
122
142
  """
123
143
  Base class for all parameter types. Parameters are the building blocks
124
144
  for creating interactive GUI elements.
@@ -265,8 +285,8 @@ class TextParameter(Parameter[str]):
265
285
  Parameter for text input.
266
286
 
267
287
  Creates a text box in the GUI that accepts any string input.
268
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_text` and
269
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_text` for usage.
288
+ See :meth:`~syd.viewer.Viewer.add_text` and
289
+ :meth:`~syd.viewer.Viewer.update_text` for usage.
270
290
 
271
291
  Parameters
272
292
  ----------
@@ -308,8 +328,8 @@ class BooleanParameter(Parameter[bool]):
308
328
  Parameter for boolean values.
309
329
 
310
330
  Creates a checkbox in the GUI that can be toggled on/off.
311
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_boolean` and
312
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_boolean` for usage.
331
+ See :meth:`~syd.viewer.Viewer.add_boolean` and
332
+ :meth:`~syd.viewer.Viewer.update_boolean` for usage.
313
333
 
314
334
  Parameters
315
335
  ----------
@@ -351,8 +371,8 @@ class SelectionParameter(Parameter[Any]):
351
371
  Parameter for single selection from a list of options.
352
372
 
353
373
  Creates a dropdown menu in the GUI where users can select one option.
354
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_selection` and
355
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_selection` for usage.
374
+ See :meth:`~syd.viewer.Viewer.add_selection` and
375
+ :meth:`~syd.viewer.Viewer.update_selection` for usage.
356
376
 
357
377
  Parameters
358
378
  ----------
@@ -412,6 +432,9 @@ class SelectionParameter(Parameter[Any]):
412
432
  f"Options for parameter {self.name} must be a list or tuple"
413
433
  )
414
434
 
435
+ if not options:
436
+ raise ValueError(f"Options for parameter {self.name} must not be empty")
437
+
415
438
  # Verify all options are hashable (needed for comparison)
416
439
  try:
417
440
  for opt in options:
@@ -455,7 +478,7 @@ class SelectionParameter(Parameter[Any]):
455
478
  ParameterUpdateWarning(
456
479
  self.name,
457
480
  type(self).__name__,
458
- f"Value {self.value} not in options: {self.options}, setting to first option",
481
+ f"Value {self.value} not in options, setting to first option ({self.options[0]})",
459
482
  )
460
483
  )
461
484
  self.value = self.options[0]
@@ -467,8 +490,8 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
467
490
  Parameter for multiple selections from a list of options.
468
491
 
469
492
  Creates a set of checkboxes or multi-select dropdown in the GUI.
470
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_multiple_selection` and
471
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_multiple_selection` for usage.
493
+ See :meth:`~syd.viewer.Viewer.add_multiple_selection` and
494
+ :meth:`~syd.viewer.Viewer.update_multiple_selection` for usage.
472
495
 
473
496
  Parameters
474
497
  ----------
@@ -525,9 +548,12 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
525
548
  """
526
549
  if not isinstance(options, (list, tuple)):
527
550
  raise TypeError(
528
- f"Options for parameter {self.name} must be a list or tuple"
551
+ f"Options for parameter {self.name} must be a list or tuple, received {type(options)}"
529
552
  )
530
553
 
554
+ if not options:
555
+ raise ValueError(f"Options for parameter {self.name} must not be empty")
556
+
531
557
  # Verify all options are hashable (needed for comparison)
532
558
  try:
533
559
  for opt in options:
@@ -580,7 +606,7 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
580
606
  ParameterUpdateWarning(
581
607
  self.name,
582
608
  type(self).__name__,
583
- f"For parameter {self.name}, value {self.value} contains invalid options: {invalid}. Setting to empty list.",
609
+ f"For parameter {self.name}, value {self.value} contains invalid selections: {invalid}. Setting to empty list.",
584
610
  )
585
611
  )
586
612
  self.value = []
@@ -595,8 +621,8 @@ class IntegerParameter(Parameter[int]):
595
621
  Parameter for bounded integer values.
596
622
 
597
623
  Creates a slider in the GUI for selecting whole numbers between bounds.
598
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_integer` and
599
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_integer` for usage.
624
+ See :meth:`~syd.viewer.Viewer.add_integer` and
625
+ :meth:`~syd.viewer.Viewer.update_integer` for usage.
600
626
 
601
627
  Parameters
602
628
  ----------
@@ -711,8 +737,8 @@ class FloatParameter(Parameter[float]):
711
737
  Parameter for bounded decimal numbers.
712
738
 
713
739
  Creates a slider in the GUI for selecting numbers between bounds.
714
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_float` and
715
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_float` for usage.
740
+ See :meth:`~syd.viewer.Viewer.add_float` and
741
+ :meth:`~syd.viewer.Viewer.update_float` for usage.
716
742
 
717
743
  Parameters
718
744
  ----------
@@ -725,7 +751,7 @@ class FloatParameter(Parameter[float]):
725
751
  max_value : float
726
752
  Maximum allowed value
727
753
  step : float, optional
728
- Size of each increment (default is 0.1)
754
+ Size of each increment (default is 0.001)
729
755
 
730
756
  Examples
731
757
  --------
@@ -758,7 +784,7 @@ class FloatParameter(Parameter[float]):
758
784
  value: float,
759
785
  min_value: float,
760
786
  max_value: float,
761
- step: float = 0.1,
787
+ step: float = 0.001,
762
788
  ):
763
789
  self.name = name
764
790
  self.step = step
@@ -846,8 +872,8 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
846
872
  Parameter for a range of bounded integer values.
847
873
 
848
874
  Creates a range slider in the GUI for selecting a range of whole numbers.
849
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_integer_range` and
850
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_integer_range` for usage.
875
+ See :meth:`~syd.viewer.Viewer.add_integer_range` and
876
+ :meth:`~syd.viewer.Viewer.update_integer_range` for usage.
851
877
 
852
878
  Parameters
853
879
  ----------
@@ -885,11 +911,11 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
885
911
  max_value: int,
886
912
  ):
887
913
  self.name = name
888
- self.min_value = self._validate_single(min_value)
889
- self.max_value = self._validate_single(max_value)
914
+ self.min_value = self._validate_single(min_value, context="min_value")
915
+ self.max_value = self._validate_single(max_value, context="max_value")
890
916
  self._value = self._validate(value)
891
917
 
892
- def _validate_single(self, new_value: Any) -> int:
918
+ def _validate_single(self, new_value: Any, context: Optional[str] = None) -> int:
893
919
  """
894
920
  Validate and convert a single numeric value.
895
921
 
@@ -907,8 +933,11 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
907
933
  """
908
934
  try:
909
935
  return int(new_value)
910
- except ValueError:
911
- raise ValueError(f"Value {new_value} cannot be converted to int")
936
+ except Exception:
937
+ msg = f"Value {new_value} cannot be converted to int"
938
+ if context:
939
+ msg += f" for {context}"
940
+ raise ValueError(msg)
912
941
 
913
942
  def _validate(self, new_value: Any) -> Tuple[int, int]:
914
943
  """
@@ -995,8 +1024,8 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
995
1024
  Parameter for a range of bounded decimal numbers.
996
1025
 
997
1026
  Creates a range slider in the GUI for selecting a range of numbers.
998
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_float_range` and
999
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_float_range` for usage.
1027
+ See :meth:`~syd.viewer.Viewer.add_float_range` and
1028
+ :meth:`~syd.viewer.Viewer.update_float_range` for usage.
1000
1029
 
1001
1030
  Parameters
1002
1031
  ----------
@@ -1009,7 +1038,7 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1009
1038
  max_value : float
1010
1039
  Maximum allowed value for both low and high
1011
1040
  step : float, optional
1012
- Size of each increment (default is 0.1)
1041
+ Size of each increment (default is 0.001)
1013
1042
 
1014
1043
  Examples
1015
1044
  --------
@@ -1042,15 +1071,15 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1042
1071
  value: Tuple[float, float],
1043
1072
  min_value: float,
1044
1073
  max_value: float,
1045
- step: float = 0.1,
1074
+ step: float = 0.001,
1046
1075
  ):
1047
1076
  self.name = name
1048
1077
  self.step = step
1049
- self.min_value = self._validate_single(min_value)
1050
- self.max_value = self._validate_single(max_value)
1078
+ self.min_value = self._validate_single(min_value, context="min_value")
1079
+ self.max_value = self._validate_single(max_value, context="max_value")
1051
1080
  self._value = self._validate(value)
1052
1081
 
1053
- def _validate_single(self, new_value: Any) -> float:
1082
+ def _validate_single(self, new_value: Any, context: Optional[str] = None) -> float:
1054
1083
  """
1055
1084
  Validate and convert a single numeric value.
1056
1085
 
@@ -1068,8 +1097,11 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1068
1097
  """
1069
1098
  try:
1070
1099
  new_value = float(new_value)
1071
- except ValueError:
1072
- raise ValueError(f"Value {new_value} cannot be converted to float")
1100
+ except Exception:
1101
+ msg = f"Value {new_value} cannot be converted to float"
1102
+ if context:
1103
+ msg += f" for {context}"
1104
+ raise ValueError(msg)
1073
1105
 
1074
1106
  # Round to the nearest step
1075
1107
  new_value = round(new_value / self.step) * self.step
@@ -1160,8 +1192,8 @@ class UnboundedIntegerParameter(Parameter[int]):
1160
1192
  Parameter for optionally bounded integer values.
1161
1193
 
1162
1194
  Creates a text input box in the GUI for entering whole numbers.
1163
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_unbounded_integer` and
1164
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_unbounded_integer` for usage.
1195
+ See :meth:`~syd.viewer.Viewer.add_unbounded_integer` and
1196
+ :meth:`~syd.viewer.Viewer.update_unbounded_integer` for usage.
1165
1197
 
1166
1198
  Parameters
1167
1199
  ----------
@@ -1169,19 +1201,12 @@ class UnboundedIntegerParameter(Parameter[int]):
1169
1201
  The name of the parameter
1170
1202
  value : int
1171
1203
  Initial value
1172
- min_value : int, optional
1173
- Minimum allowed value (or None for no minimum)
1174
- max_value : int, optional
1175
- Maximum allowed value (or None for no maximum)
1176
1204
 
1177
1205
  Examples
1178
1206
  --------
1179
- >>> count = UnboundedIntegerParameter("count", value=10, min_value=0)
1207
+ >>> count = UnboundedIntegerParameter("count", value=10)
1180
1208
  >>> count.value
1181
1209
  10
1182
- >>> count.update({"value": -5}) # Will be clamped to min_value
1183
- >>> count.value
1184
- 0
1185
1210
  >>> count.update({"value": 1000000}) # No maximum, so this is allowed
1186
1211
  >>> count.value
1187
1212
  1000000
@@ -1189,43 +1214,24 @@ class UnboundedIntegerParameter(Parameter[int]):
1189
1214
  Notes
1190
1215
  -----
1191
1216
  Use this instead of IntegerParameter when you:
1192
- - Don't know a reasonable maximum value
1193
- - Only want to enforce a minimum or maximum, but not both
1217
+ - Don't have any reason to bound the value
1194
1218
  - Need to allow very large numbers that would be impractical with a slider
1195
1219
  """
1196
1220
 
1197
- min_value: Optional[int]
1198
- max_value: Optional[int]
1199
-
1200
1221
  def __init__(
1201
1222
  self,
1202
1223
  name: str,
1203
1224
  value: int,
1204
- min_value: Optional[int] = None,
1205
- max_value: Optional[int] = None,
1206
1225
  ):
1207
1226
  self.name = name
1208
- self.min_value = (
1209
- self._validate(min_value, compare_to_range=False)
1210
- if min_value is not None
1211
- else None
1212
- )
1213
- self.max_value = (
1214
- self._validate(max_value, compare_to_range=False)
1215
- if max_value is not None
1216
- else None
1217
- )
1218
1227
  self._value = self._validate(value)
1219
1228
 
1220
- def _validate(self, new_value: Any, compare_to_range: bool = True) -> int:
1229
+ def _validate(self, new_value: Any) -> int:
1221
1230
  """
1222
- Validate and convert value to integer, optionally checking bounds.
1223
-
1224
- Handles None min/max values by skipping those bound checks.
1231
+ Validate and convert value to integer.
1225
1232
 
1226
1233
  Args:
1227
1234
  new_value: Value to validate
1228
- compare_to_range: If True, clamps value to any defined min/max bounds
1229
1235
 
1230
1236
  Returns:
1231
1237
  Validated integer value
@@ -1238,50 +1244,15 @@ class UnboundedIntegerParameter(Parameter[int]):
1238
1244
  except ValueError:
1239
1245
  raise ValueError(f"Value {new_value} cannot be converted to int")
1240
1246
 
1241
- if compare_to_range:
1242
- if self.min_value is not None and new_value < self.min_value:
1243
- warn(
1244
- ParameterUpdateWarning(
1245
- self.name,
1246
- type(self).__name__,
1247
- f"Value {new_value} below minimum {self.min_value}, clamping",
1248
- )
1249
- )
1250
- new_value = self.min_value
1251
- if self.max_value is not None and new_value > self.max_value:
1252
- warn(
1253
- ParameterUpdateWarning(
1254
- self.name,
1255
- type(self).__name__,
1256
- f"Value {new_value} above maximum {self.max_value}, clamping",
1257
- )
1258
- )
1259
- new_value = self.max_value
1260
1247
  return int(new_value)
1261
1248
 
1262
1249
  def _validate_update(self) -> None:
1263
1250
  """
1264
1251
  Validate complete parameter state after updates.
1265
1252
 
1266
- Ensures min_value <= max_value, swapping if needed.
1267
- Re-validates current value against potentially updated bounds.
1268
-
1269
1253
  Raises:
1270
1254
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
1271
1255
  """
1272
- if (
1273
- self.min_value is not None
1274
- and self.max_value is not None
1275
- and self.min_value > self.max_value
1276
- ):
1277
- warn(
1278
- ParameterUpdateWarning(
1279
- self.name,
1280
- type(self).__name__,
1281
- f"Min value greater than max value, swapping",
1282
- )
1283
- )
1284
- self.min_value, self.max_value = self.max_value, self.min_value
1285
1256
  self.value = self._validate(self.value)
1286
1257
 
1287
1258
 
@@ -1291,8 +1262,8 @@ class UnboundedFloatParameter(Parameter[float]):
1291
1262
  Parameter for optionally bounded decimal numbers.
1292
1263
 
1293
1264
  Creates a text input box in the GUI for entering numbers.
1294
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_unbounded_float` and
1295
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_unbounded_float` for usage.
1265
+ See :meth:`~syd.viewer.Viewer.add_unbounded_float` and
1266
+ :meth:`~syd.viewer.Viewer.update_unbounded_float` for usage.
1296
1267
 
1297
1268
  Parameters
1298
1269
  ----------
@@ -1300,21 +1271,14 @@ class UnboundedFloatParameter(Parameter[float]):
1300
1271
  The name of the parameter
1301
1272
  value : float
1302
1273
  Initial value
1303
- min_value : float, optional
1304
- Minimum allowed value (or None for no minimum)
1305
- max_value : float, optional
1306
- Maximum allowed value (or None for no maximum)
1307
1274
  step : float, optional
1308
1275
  Size of each increment (default is None, meaning no rounding)
1309
1276
 
1310
1277
  Examples
1311
1278
  --------
1312
- >>> price = UnboundedFloatParameter("price", value=19.99, min_value=0.0, step=0.01)
1279
+ >>> price = UnboundedFloatParameter("price", value=19.99)
1313
1280
  >>> price.value
1314
1281
  19.99
1315
- >>> price.update({"value": -5.0}) # Will be clamped to min_value
1316
- >>> price.value
1317
- 0.0
1318
1282
  >>> price.update({"value": 19.987}) # Will be rounded to step
1319
1283
  >>> price.value
1320
1284
  19.99
@@ -1323,7 +1287,6 @@ class UnboundedFloatParameter(Parameter[float]):
1323
1287
  -----
1324
1288
  Use this instead of FloatParameter when you:
1325
1289
  - Don't know a reasonable maximum value
1326
- - Only want to enforce a minimum or maximum, but not both
1327
1290
  - Need to allow very large or precise numbers that would be impractical with a slider
1328
1291
 
1329
1292
  If step is provided, values will be rounded:
@@ -1332,42 +1295,25 @@ class UnboundedFloatParameter(Parameter[float]):
1332
1295
  - step=5.0 rounds to 0.0, 5.0, 10.0, etc.
1333
1296
  """
1334
1297
 
1335
- min_value: Optional[float]
1336
- max_value: Optional[float]
1337
- step: float
1298
+ step: Optional[float]
1338
1299
 
1339
1300
  def __init__(
1340
1301
  self,
1341
1302
  name: str,
1342
1303
  value: float,
1343
- min_value: Optional[float] = None,
1344
- max_value: Optional[float] = None,
1345
1304
  step: Optional[float] = None,
1346
1305
  ):
1347
1306
  self.name = name
1348
1307
  self.step = step
1349
- self.min_value = (
1350
- self._validate(min_value, compare_to_range=False)
1351
- if min_value is not None
1352
- else None
1353
- )
1354
- self.max_value = (
1355
- self._validate(max_value, compare_to_range=False)
1356
- if max_value is not None
1357
- else None
1358
- )
1359
1308
  self._value = self._validate(value)
1360
1309
 
1361
- def _validate(self, new_value: Any, compare_to_range: bool = True) -> float:
1310
+ def _validate(self, new_value: Any) -> float:
1362
1311
  """
1363
- Validate and convert value to float, optionally checking bounds.
1364
-
1365
- Handles None min/max values by skipping those bound checks.
1312
+ Validate and convert value to float.
1366
1313
  Only rounds to step if step is not None.
1367
1314
 
1368
1315
  Args:
1369
1316
  new_value: Value to validate
1370
- compare_to_range: If True, clamps value to any defined min/max bounds
1371
1317
 
1372
1318
  Returns:
1373
1319
  Validated and potentially rounded float value
@@ -1384,26 +1330,6 @@ class UnboundedFloatParameter(Parameter[float]):
1384
1330
  if self.step is not None:
1385
1331
  new_value = round(new_value / self.step) * self.step
1386
1332
 
1387
- if compare_to_range:
1388
- if self.min_value is not None and new_value < self.min_value:
1389
- warn(
1390
- ParameterUpdateWarning(
1391
- self.name,
1392
- type(self).__name__,
1393
- f"Value {new_value} below minimum {self.min_value}, clamping",
1394
- )
1395
- )
1396
- new_value = self.min_value
1397
- if self.max_value is not None and new_value > self.max_value:
1398
- warn(
1399
- ParameterUpdateWarning(
1400
- self.name,
1401
- type(self).__name__,
1402
- f"Value {new_value} above maximum {self.max_value}, clamping",
1403
- )
1404
- )
1405
- new_value = self.max_value
1406
-
1407
1333
  return float(new_value)
1408
1334
 
1409
1335
  def _validate_update(self) -> None:
@@ -1416,19 +1342,6 @@ class UnboundedFloatParameter(Parameter[float]):
1416
1342
  Raises:
1417
1343
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
1418
1344
  """
1419
- if (
1420
- self.min_value is not None
1421
- and self.max_value is not None
1422
- and self.min_value > self.max_value
1423
- ):
1424
- warn(
1425
- ParameterUpdateWarning(
1426
- self.name,
1427
- type(self).__name__,
1428
- f"Min value greater than max value, swapping",
1429
- )
1430
- )
1431
- self.min_value, self.max_value = self.max_value, self.min_value
1432
1345
  self.value = self._validate(self.value)
1433
1346
 
1434
1347
 
@@ -1438,8 +1351,8 @@ class ButtonAction(Parameter[None]):
1438
1351
  Parameter for creating clickable buttons with callbacks.
1439
1352
 
1440
1353
  Creates a button in the GUI that executes a callback function when clicked.
1441
- See :meth:`~syd.interactive_viewer.InteractiveViewer.add_button` and
1442
- :meth:`~syd.interactive_viewer.InteractiveViewer.update_button` for usage.
1354
+ See :meth:`~syd.viewer.Viewer.add_button` and
1355
+ :meth:`~syd.viewer.Viewer.update_button` for usage.
1443
1356
 
1444
1357
  Parameters
1445
1358
  ----------
@@ -0,0 +1 @@
1
+ from .deployer import PlotlyDeployer