syd 0.1.7__py3-none-any.whl → 1.0.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/parameters.py CHANGED
@@ -1,140 +1,18 @@
1
1
  from typing import List, Any, Tuple, Generic, TypeVar, Optional, Dict, Callable, Union
2
2
  from dataclasses import dataclass, field
3
- from abc import ABC, ABCMeta, abstractmethod
3
+ from abc import ABC, abstractmethod
4
4
  from enum import Enum
5
5
  from copy import deepcopy
6
- from warnings import warn
7
- import numpy as np
8
6
 
9
- T = TypeVar("T")
10
-
11
-
12
- # Keep original Parameter class and exceptions unchanged
13
- class ParameterAddError(Exception):
14
- """
15
- Exception raised when there is an error creating a new parameter.
16
-
17
- Parameters
18
- ----------
19
- parameter_name : str
20
- Name of the parameter that failed to be created
21
- parameter_type : str
22
- Type of the parameter that failed to be created
23
- message : str, optional
24
- Additional error details
25
- """
26
-
27
- def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
28
- self.parameter_name = parameter_name
29
- self.parameter_type = parameter_type
30
- super().__init__(
31
- f"Failed to create {parameter_type} parameter '{parameter_name}'"
32
- + (f": {message}" if message else "")
33
- )
34
-
35
-
36
- class ParameterUpdateError(Exception):
37
- """
38
- Exception raised when there is an error updating an existing parameter.
39
-
40
- Parameters
41
- ----------
42
- parameter_name : str
43
- Name of the parameter that failed to update
44
- parameter_type : str
45
- Type of the parameter that failed to update
46
- message : str, optional
47
- Additional error details
48
- """
49
-
50
- def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
51
- self.parameter_name = parameter_name
52
- self.parameter_type = parameter_type
53
- super().__init__(
54
- f"Failed to update {parameter_type} parameter '{parameter_name}'"
55
- + (f": {message}" if message else "")
56
- )
57
-
58
-
59
- class ParameterUpdateWarning(Warning):
60
- """
61
- Warning raised when there is a non-critical issue updating a parameter.
62
-
63
- Parameters
64
- ----------
65
- parameter_name : str
66
- Name of the parameter that had the warning
67
- parameter_type : str
68
- Type of the parameter
69
- message : str, optional
70
- Additional warning details
71
- """
72
-
73
- def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
74
- self.parameter_name = parameter_name
75
- self.parameter_type = parameter_type
76
- super().__init__(
77
- f"Warning updating {parameter_type} parameter '{parameter_name}'"
78
- + (f": {message}" if message else "")
79
- )
80
-
81
-
82
- def get_parameter_attributes(param_class) -> List[str]:
83
- """
84
- Get all valid attributes for a parameter class.
85
-
86
- Parameters
87
- ----------
88
- param_class : class
89
- The parameter class to inspect
90
-
91
- Returns
92
- -------
93
- list of str
94
- Names of all valid attributes for the parameter class
95
- """
96
- attributes = []
7
+ from .support import (
8
+ NoInitialValue,
9
+ ParameterMeta,
10
+ ParameterUpdateError,
11
+ get_parameter_attributes,
12
+ warn_parameter_update,
13
+ )
97
14
 
98
- # Walk through class hierarchy in reverse (most specific to most general)
99
- for cls in reversed(param_class.__mro__):
100
- if hasattr(cls, "__annotations__"):
101
- # Only add annotations that haven't been specified by a more specific class
102
- for name in cls.__annotations__:
103
- if not name.startswith("_"):
104
- attributes.append(name)
105
-
106
- return attributes
107
-
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
15
+ T = TypeVar("T")
138
16
 
139
17
 
140
18
  @dataclass
@@ -216,8 +94,8 @@ class Parameter(Generic[T], ABC, metaclass=ParameterMeta):
216
94
 
217
95
  Examples
218
96
  --------
219
- >>> param = FloatParameter("temperature", 20.0, min_value=0, max_value=100)
220
- >>> param.update({"value": 25.0, "max_value": 150})
97
+ >>> param = FloatParameter("temperature", 20.0, min=0, max=100)
98
+ >>> param.update({"value": 25.0, "max": 150})
221
99
  """
222
100
  param_copy = deepcopy(self)
223
101
 
@@ -292,7 +170,7 @@ class TextParameter(Parameter[str]):
292
170
  ----------
293
171
  name : str
294
172
  The name of the parameter
295
- value : str
173
+ value : Union[str, NoInitialValue]
296
174
  The initial text value
297
175
 
298
176
  Examples
@@ -305,8 +183,10 @@ class TextParameter(Parameter[str]):
305
183
  'Bob'
306
184
  """
307
185
 
308
- def __init__(self, name: str, value: str):
186
+ def __init__(self, name: str, value: Union[str, NoInitialValue]):
309
187
  self.name = name
188
+ if isinstance(value, NoInitialValue):
189
+ value = ""
310
190
  self._value = self._validate(value)
311
191
 
312
192
  def _validate(self, new_value: Any) -> str:
@@ -335,7 +215,7 @@ class BooleanParameter(Parameter[bool]):
335
215
  ----------
336
216
  name : str
337
217
  The name of the parameter
338
- value : bool, optional
218
+ value : Union[bool, NoInitialValue]
339
219
  The initial state (default is True)
340
220
 
341
221
  Examples
@@ -348,8 +228,10 @@ class BooleanParameter(Parameter[bool]):
348
228
  False
349
229
  """
350
230
 
351
- def __init__(self, name: str, value: bool = True):
231
+ def __init__(self, name: str, value: Union[bool, NoInitialValue]):
352
232
  self.name = name
233
+ if isinstance(value, NoInitialValue):
234
+ value = True
353
235
  self._value = self._validate(value)
354
236
 
355
237
  def _validate(self, new_value: Any) -> bool:
@@ -378,7 +260,7 @@ class SelectionParameter(Parameter[Any]):
378
260
  ----------
379
261
  name : str
380
262
  The name of the parameter
381
- value : Any
263
+ value : Union[Any, NoInitialValue]
382
264
  The initially selected value (must be one of the options)
383
265
  options : sequence
384
266
  List, tuple, or 1D numpy array of valid choices that can be selected
@@ -401,9 +283,13 @@ class SelectionParameter(Parameter[Any]):
401
283
 
402
284
  options: List[Any]
403
285
 
404
- def __init__(self, name: str, value: Any, options: Union[List, Tuple]):
286
+ def __init__(
287
+ self, name: str, value: Union[Any, NoInitialValue], options: Union[List, Tuple]
288
+ ):
405
289
  self.name = name
406
290
  self.options = self._validate_options(options)
291
+ if isinstance(value, NoInitialValue):
292
+ value = self.options[0]
407
293
  self._value = self._validate(value)
408
294
 
409
295
  def _validate_options(self, options: Any) -> List[Any]:
@@ -458,9 +344,42 @@ class SelectionParameter(Parameter[Any]):
458
344
  Raises:
459
345
  ValueError: If value is not in options list
460
346
  """
461
- if new_value not in self.options:
462
- raise ValueError(f"Value {new_value} not in options: {self.options}")
463
- return new_value
347
+ # Direct check for non-float values or when new_value is exactly in options
348
+ if new_value in self.options:
349
+ return new_value
350
+
351
+ # Special handling for numeric values to account for type mismatches
352
+ if isinstance(new_value, (int, float)):
353
+ for option in self.options:
354
+ # For numeric options, compare as floats
355
+ if (
356
+ isinstance(option, (int, float))
357
+ and abs(float(new_value) - float(option)) < 1e-10
358
+ ):
359
+ return option
360
+ # Also try string conversion for numeric strings
361
+ elif isinstance(option, str):
362
+ try:
363
+ if abs(float(new_value) - float(option)) < 1e-10:
364
+ return option
365
+ except ValueError:
366
+ pass
367
+
368
+ # Handle string conversion - when new_value is a string but options might be numeric
369
+ if isinstance(new_value, str):
370
+ try:
371
+ # Try to convert to float if possible
372
+ float_value = float(new_value)
373
+ for option in self.options:
374
+ if (
375
+ isinstance(option, (int, float))
376
+ and abs(float_value - float(option)) < 1e-10
377
+ ):
378
+ return option
379
+ except ValueError:
380
+ pass
381
+
382
+ raise ValueError(f"Value {new_value} not in options: {self.options}")
464
383
 
465
384
  def _validate_update(self) -> None:
466
385
  """
@@ -473,13 +392,50 @@ class SelectionParameter(Parameter[Any]):
473
392
  TypeError: If options is not a list or tuple
474
393
  """
475
394
  self.options = self._validate_options(self.options)
476
- if self.value not in self.options:
477
- warn(
478
- ParameterUpdateWarning(
479
- self.name,
480
- type(self).__name__,
481
- f"Value {self.value} not in options, setting to first option ({self.options[0]})",
482
- )
395
+
396
+ # Check if value is directly in options
397
+ if self.value in self.options:
398
+ return
399
+
400
+ # For numeric values, try flexible comparison
401
+ value_found = False
402
+ if isinstance(self.value, (int, float)):
403
+ for option in self.options:
404
+ if (
405
+ isinstance(option, (int, float))
406
+ and abs(float(self.value) - float(option)) < 1e-10
407
+ ):
408
+ # Don't update self.value here as we want to keep the original type if possible
409
+ value_found = True
410
+ break
411
+ elif isinstance(option, str):
412
+ try:
413
+ if abs(float(self.value) - float(option)) < 1e-10:
414
+ value_found = True
415
+ break
416
+ except ValueError:
417
+ pass
418
+
419
+ # For string values that might be numeric
420
+ if not value_found and isinstance(self.value, str):
421
+ try:
422
+ float_value = float(self.value)
423
+ for option in self.options:
424
+ if (
425
+ isinstance(option, (int, float))
426
+ and abs(float_value - float(option)) < 1e-10
427
+ ):
428
+ value_found = True
429
+ break
430
+ except ValueError:
431
+ pass
432
+
433
+ # If value is not found after all checks, reset to first option
434
+ if not value_found:
435
+ warn_parameter_update(
436
+ self.name,
437
+ type(self).__name__,
438
+ f"Value {self.value} not in options, setting to first option ({self.options[0]})",
483
439
  )
484
440
  self.value = self.options[0]
485
441
 
@@ -497,8 +453,8 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
497
453
  ----------
498
454
  name : str
499
455
  The name of the parameter
500
- value : list
501
- List of initially selected values (must all be from options)
456
+ value : Union[List[Any], NoInitialValue]
457
+ List of initially selected values (must all be from options, can be empty)
502
458
  options : sequence
503
459
  List, tuple, or 1D numpy array of valid choices that can be selected
504
460
 
@@ -520,9 +476,16 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
520
476
 
521
477
  options: List[Any]
522
478
 
523
- def __init__(self, name: str, value: List[Any], options: Union[List, Tuple]):
479
+ def __init__(
480
+ self,
481
+ name: str,
482
+ value: Union[List[Any], NoInitialValue],
483
+ options: Union[List, Tuple],
484
+ ):
524
485
  self.name = name
525
486
  self.options = self._validate_options(options)
487
+ if isinstance(value, NoInitialValue):
488
+ value = []
526
489
  self._value = self._validate(value)
527
490
 
528
491
  def _validate_options(self, options: Any) -> List[Any]:
@@ -592,22 +555,18 @@ class MultipleSelectionParameter(Parameter[List[Any]]):
592
555
  def _validate_update(self) -> None:
593
556
  self.options = self._validate_options(self.options)
594
557
  if not isinstance(self.value, (list, tuple)):
595
- warn(
596
- ParameterUpdateWarning(
597
- self.name,
598
- type(self).__name__,
599
- f"For parameter {self.name}, value {self.value} is not a list or tuple. Setting to empty list.",
600
- )
558
+ warn_parameter_update(
559
+ self.name,
560
+ type(self).__name__,
561
+ f"For parameter {self.name}, value {self.value} is not a list or tuple. Setting to empty list.",
601
562
  )
602
563
  self.value = []
603
564
  if not all(val in self.options for val in self.value):
604
565
  invalid = [val for val in self.value if val not in self.options]
605
- warn(
606
- ParameterUpdateWarning(
607
- self.name,
608
- type(self).__name__,
609
- f"For parameter {self.name}, value {self.value} contains invalid selections: {invalid}. Setting to empty list.",
610
- )
566
+ warn_parameter_update(
567
+ self.name,
568
+ type(self).__name__,
569
+ f"For parameter {self.name}, value {self.value} contains invalid selections: {invalid}. Setting to empty list.",
611
570
  )
612
571
  self.value = []
613
572
  # Keep only unique values while preserving order based on self.options
@@ -628,39 +587,41 @@ class IntegerParameter(Parameter[int]):
628
587
  ----------
629
588
  name : str
630
589
  The name of the parameter
631
- value : int
632
- Initial value (will be clamped to fit between min_value and max_value)
633
- min_value : int
590
+ value : Union[int, NoInitialValue]
591
+ Initial value (will be clamped to fit between min and max)
592
+ min : int
634
593
  Minimum allowed value
635
- max_value : int
594
+ max : int
636
595
  Maximum allowed value
637
596
 
638
597
  Examples
639
598
  --------
640
- >>> age = IntegerParameter("age", value=25, min_value=0, max_value=120)
599
+ >>> age = IntegerParameter("age", value=25, min=0, max=120)
641
600
  >>> age.value
642
601
  25
643
- >>> age.update({"value": 150}) # Will be clamped to max_value
602
+ >>> age.update({"value": 150}) # Will be clamped to max
644
603
  >>> age.value
645
604
  120
646
- >>> age.update({"value": -10}) # Will be clamped to min_value
605
+ >>> age.update({"value": -10}) # Will be clamped to min
647
606
  >>> age.value
648
607
  0
649
608
  """
650
609
 
651
- min_value: int
652
- max_value: int
610
+ min: int
611
+ max: int
653
612
 
654
613
  def __init__(
655
614
  self,
656
615
  name: str,
657
- value: int,
658
- min_value: int,
659
- max_value: int,
616
+ value: Union[int, NoInitialValue],
617
+ min: int,
618
+ max: int,
660
619
  ):
661
620
  self.name = name
662
- self.min_value = self._validate(min_value, compare_to_range=False)
663
- self.max_value = self._validate(max_value, compare_to_range=False)
621
+ self.min = self._validate(min, compare_to_range=False)
622
+ self.max = self._validate(max, compare_to_range=False)
623
+ if isinstance(value, NoInitialValue):
624
+ value = self.min
664
625
  self._value = self._validate(value)
665
626
 
666
627
  def _validate(self, new_value: Any, compare_to_range: bool = True) -> int:
@@ -683,51 +644,45 @@ class IntegerParameter(Parameter[int]):
683
644
  raise ValueError(f"Value {new_value} cannot be converted to int")
684
645
 
685
646
  if compare_to_range:
686
- if new_value < self.min_value:
687
- warn(
688
- ParameterUpdateWarning(
689
- self.name,
690
- type(self).__name__,
691
- f"Value {new_value} below minimum {self.min_value}, clamping",
692
- )
647
+ if new_value < self.min:
648
+ warn_parameter_update(
649
+ self.name,
650
+ type(self).__name__,
651
+ f"Value {new_value} below minimum {self.min}, clamping",
693
652
  )
694
- new_value = self.min_value
695
- if new_value > self.max_value:
696
- warn(
697
- ParameterUpdateWarning(
698
- self.name,
699
- type(self).__name__,
700
- f"Value {new_value} above maximum {self.max_value}, clamping",
701
- )
653
+ new_value = self.min
654
+ if new_value > self.max:
655
+ warn_parameter_update(
656
+ self.name,
657
+ type(self).__name__,
658
+ f"Value {new_value} above maximum {self.max}, clamping",
702
659
  )
703
- new_value = self.max_value
660
+ new_value = self.max
704
661
  return int(new_value)
705
662
 
706
663
  def _validate_update(self) -> None:
707
664
  """
708
665
  Validate complete parameter state after updates.
709
666
 
710
- Ensures min_value <= max_value, swapping if needed.
667
+ Ensures min <= max, swapping if needed.
711
668
  Re-validates current value against potentially updated bounds.
712
669
 
713
670
  Raises:
714
671
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
715
672
  """
716
- if self.min_value is None or self.max_value is None:
673
+ if self.min is None or self.max is None:
717
674
  raise ParameterUpdateError(
718
675
  self.name,
719
676
  type(self).__name__,
720
- "IntegerParameter must have both min_value and max_value bounds",
677
+ "IntegerParameter must have both min and max bounds",
721
678
  )
722
- if self.min_value > self.max_value:
723
- warn(
724
- ParameterUpdateWarning(
725
- self.name,
726
- type(self).__name__,
727
- f"Min value greater than max value, swapping",
728
- )
679
+ if self.min > self.max:
680
+ warn_parameter_update(
681
+ self.name,
682
+ type(self).__name__,
683
+ f"Min value greater than max value, swapping",
729
684
  )
730
- self.min_value, self.max_value = self.max_value, self.min_value
685
+ self.min, self.max = self.max, self.min
731
686
  self.value = self._validate(self.value)
732
687
 
733
688
 
@@ -744,11 +699,11 @@ class FloatParameter(Parameter[float]):
744
699
  ----------
745
700
  name : str
746
701
  The name of the parameter
747
- value : float
748
- Initial value (will be clamped to fit between min_value and max_value)
749
- min_value : float
702
+ value : Union[float, NoInitialValue]
703
+ Initial value (will be clamped to fit between min and max)
704
+ min : float
750
705
  Minimum allowed value
751
- max_value : float
706
+ max : float
752
707
  Maximum allowed value
753
708
  step : float, optional
754
709
  Size of each increment (default is 0.001)
@@ -756,13 +711,13 @@ class FloatParameter(Parameter[float]):
756
711
  Examples
757
712
  --------
758
713
  >>> temp = FloatParameter("temperature", value=98.6,
759
- ... min_value=95.0, max_value=105.0, step=0.1)
714
+ ... min=95.0, max=105.0, step=0.1)
760
715
  >>> temp.value
761
716
  98.6
762
717
  >>> temp.update({"value": 98.67}) # Will be rounded to nearest step
763
718
  >>> temp.value
764
719
  98.7
765
- >>> temp.update({"value": 110.0}) # Will be clamped to max_value
720
+ >>> temp.update({"value": 110.0}) # Will be clamped to max
766
721
  >>> temp.value
767
722
  105.0
768
723
 
@@ -774,22 +729,24 @@ class FloatParameter(Parameter[float]):
774
729
  - step=5.0 allows values like 0.0, 5.0, 10.0, etc.
775
730
  """
776
731
 
777
- min_value: float
778
- max_value: float
732
+ min: float
733
+ max: float
779
734
  step: float
780
735
 
781
736
  def __init__(
782
737
  self,
783
738
  name: str,
784
- value: float,
785
- min_value: float,
786
- max_value: float,
739
+ value: Union[float, NoInitialValue],
740
+ min: float,
741
+ max: float,
787
742
  step: float = 0.001,
788
743
  ):
789
744
  self.name = name
790
745
  self.step = step
791
- self.min_value = self._validate(min_value, compare_to_range=False)
792
- self.max_value = self._validate(max_value, compare_to_range=False)
746
+ self.min = self._validate(min, compare_to_range=False)
747
+ self.max = self._validate(max, compare_to_range=False)
748
+ if isinstance(value, NoInitialValue):
749
+ value = self.min
793
750
  self._value = self._validate(value)
794
751
 
795
752
  def _validate(self, new_value: Any, compare_to_range: bool = True) -> float:
@@ -817,24 +774,20 @@ class FloatParameter(Parameter[float]):
817
774
  new_value = round(new_value / self.step) * self.step
818
775
 
819
776
  if compare_to_range:
820
- if new_value < self.min_value:
821
- warn(
822
- ParameterUpdateWarning(
823
- self.name,
824
- type(self).__name__,
825
- f"Value {new_value} below minimum {self.min_value}, clamping",
826
- )
777
+ if new_value < self.min:
778
+ warn_parameter_update(
779
+ self.name,
780
+ type(self).__name__,
781
+ f"Value {new_value} below minimum {self.min}, clamping",
827
782
  )
828
- new_value = self.min_value
829
- if new_value > self.max_value:
830
- warn(
831
- ParameterUpdateWarning(
832
- self.name,
833
- type(self).__name__,
834
- f"Value {new_value} above maximum {self.max_value}, clamping",
835
- )
783
+ new_value = self.min
784
+ if new_value > self.max:
785
+ warn_parameter_update(
786
+ self.name,
787
+ type(self).__name__,
788
+ f"Value {new_value} above maximum {self.max}, clamping",
836
789
  )
837
- new_value = self.max_value
790
+ new_value = self.max
838
791
 
839
792
  return float(new_value)
840
793
 
@@ -842,27 +795,25 @@ class FloatParameter(Parameter[float]):
842
795
  """
843
796
  Validate complete parameter state after updates.
844
797
 
845
- Ensures min_value <= max_value, swapping if needed.
798
+ Ensures min <= max, swapping if needed.
846
799
  Re-validates current value against potentially updated bounds.
847
800
 
848
801
  Raises:
849
802
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
850
803
  """
851
- if self.min_value is None or self.max_value is None:
804
+ if self.min is None or self.max is None:
852
805
  raise ParameterUpdateError(
853
806
  self.name,
854
807
  type(self).__name__,
855
- "FloatParameter must have both min_value and max_value bounds",
808
+ "FloatParameter must have both min and max bounds",
856
809
  )
857
- if self.min_value > self.max_value:
858
- warn(
859
- ParameterUpdateWarning(
860
- self.name,
861
- type(self).__name__,
862
- f"Min value greater than max value, swapping",
863
- )
810
+ if self.min > self.max:
811
+ warn_parameter_update(
812
+ self.name,
813
+ type(self).__name__,
814
+ f"Min value greater than max value, swapping",
864
815
  )
865
- self.min_value, self.max_value = self.max_value, self.min_value
816
+ self.min, self.max = self.max, self.min
866
817
  self.value = self._validate(self.value)
867
818
 
868
819
 
@@ -879,17 +830,17 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
879
830
  ----------
880
831
  name : str
881
832
  The name of the parameter
882
- value : tuple[int, int]
833
+ value : Union[Tuple[int, int], NoInitialValue]
883
834
  Initial (low, high) values
884
- min_value : int
835
+ min : int
885
836
  Minimum allowed value for both low and high
886
- max_value : int
837
+ max : int
887
838
  Maximum allowed value for both low and high
888
839
 
889
840
  Examples
890
841
  --------
891
842
  >>> age_range = IntegerRangeParameter("age_range",
892
- ... value=(25, 35), min_value=18, max_value=100)
843
+ ... value=(25, 35), min=18, max=100)
893
844
  >>> age_range.value
894
845
  (25, 35)
895
846
  >>> age_range.update({"value": (35, 25)}) # Values will be swapped
@@ -900,19 +851,21 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
900
851
  (18, 40)
901
852
  """
902
853
 
903
- min_value: int
904
- max_value: int
854
+ min: int
855
+ max: int
905
856
 
906
857
  def __init__(
907
858
  self,
908
859
  name: str,
909
- value: Tuple[int, int],
910
- min_value: int,
911
- max_value: int,
860
+ value: Union[Tuple[int, int], NoInitialValue],
861
+ min: int,
862
+ max: int,
912
863
  ):
913
864
  self.name = name
914
- self.min_value = self._validate_single(min_value, context="min_value")
915
- self.max_value = self._validate_single(max_value, context="max_value")
865
+ self.min = self._validate_single(min, context="min")
866
+ self.max = self._validate_single(max, context="max")
867
+ if isinstance(value, NoInitialValue):
868
+ value = (self.min, self.max)
916
869
  self._value = self._validate(value)
917
870
 
918
871
  def _validate_single(self, new_value: Any, context: Optional[str] = None) -> int:
@@ -960,33 +913,27 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
960
913
  high = self._validate_single(new_value[1])
961
914
 
962
915
  if low > high:
963
- warn(
964
- ParameterUpdateWarning(
965
- self.name,
966
- type(self).__name__,
967
- f"Low value {low} greater than high value {high}, swapping",
968
- )
916
+ warn_parameter_update(
917
+ self.name,
918
+ type(self).__name__,
919
+ f"Low value {low} greater than high value {high}, swapping",
969
920
  )
970
921
  low, high = high, low
971
922
 
972
- if low < self.min_value:
973
- warn(
974
- ParameterUpdateWarning(
975
- self.name,
976
- type(self).__name__,
977
- f"Low value {low} below minimum {self.min_value}, clamping",
978
- )
923
+ if low < self.min:
924
+ warn_parameter_update(
925
+ self.name,
926
+ type(self).__name__,
927
+ f"Low value {low} below minimum {self.min}, clamping",
979
928
  )
980
- low = self.min_value
981
- if high > self.max_value:
982
- warn(
983
- ParameterUpdateWarning(
984
- self.name,
985
- type(self).__name__,
986
- f"High value {high} above maximum {self.max_value}, clamping",
987
- )
929
+ low = self.min
930
+ if high > self.max:
931
+ warn_parameter_update(
932
+ self.name,
933
+ type(self).__name__,
934
+ f"High value {high} above maximum {self.max}, clamping",
988
935
  )
989
- high = self.max_value
936
+ high = self.max
990
937
 
991
938
  return (low, high)
992
939
 
@@ -994,27 +941,25 @@ class IntegerRangeParameter(Parameter[Tuple[int, int]]):
994
941
  """
995
942
  Validate complete parameter state after updates.
996
943
 
997
- Ensures min_value <= max_value, swapping if needed.
944
+ Ensures min <= max, swapping if needed.
998
945
  Re-validates current value against potentially updated bounds.
999
946
 
1000
947
  Raises:
1001
948
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
1002
949
  """
1003
- if self.min_value is None or self.max_value is None:
950
+ if self.min is None or self.max is None:
1004
951
  raise ParameterUpdateError(
1005
952
  self.name,
1006
953
  type(self).__name__,
1007
- "IntegerRangeParameter must have both min_value and max_value bounds",
954
+ "IntegerRangeParameter must have both min and max bounds",
1008
955
  )
1009
- if self.min_value > self.max_value:
1010
- warn(
1011
- ParameterUpdateWarning(
1012
- self.name,
1013
- type(self).__name__,
1014
- f"Min value greater than max value, swapping",
1015
- )
956
+ if self.min > self.max:
957
+ warn_parameter_update(
958
+ self.name,
959
+ type(self).__name__,
960
+ f"Min value greater than max value, swapping",
1016
961
  )
1017
- self.min_value, self.max_value = self.max_value, self.min_value
962
+ self.min, self.max = self.max, self.min
1018
963
  self.value = self._validate(self.value)
1019
964
 
1020
965
 
@@ -1031,11 +976,11 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1031
976
  ----------
1032
977
  name : str
1033
978
  The name of the parameter
1034
- value : tuple[float, float]
979
+ value : Union[Tuple[float, float], NoInitialValue]
1035
980
  Initial (low, high) values
1036
- min_value : float
981
+ min : float
1037
982
  Minimum allowed value for both low and high
1038
- max_value : float
983
+ max : float
1039
984
  Maximum allowed value for both low and high
1040
985
  step : float, optional
1041
986
  Size of each increment (default is 0.001)
@@ -1043,7 +988,7 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1043
988
  Examples
1044
989
  --------
1045
990
  >>> temp_range = FloatRangeParameter("temperature_range",
1046
- ... value=(98.6, 100.4), min_value=95.0, max_value=105.0, step=0.1)
991
+ ... value=(98.6, 100.4), min=95.0, max=105.0, step=0.1)
1047
992
  >>> temp_range.value
1048
993
  (98.6, 100.4)
1049
994
  >>> temp_range.update({"value": (98.67, 100.0)}) # Low will be rounded
@@ -1061,22 +1006,24 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1061
1006
  - step=5.0 allows values like 0.0, 5.0, 10.0, etc.
1062
1007
  """
1063
1008
 
1064
- min_value: float
1065
- max_value: float
1009
+ min: float
1010
+ max: float
1066
1011
  step: float
1067
1012
 
1068
1013
  def __init__(
1069
1014
  self,
1070
1015
  name: str,
1071
- value: Tuple[float, float],
1072
- min_value: float,
1073
- max_value: float,
1016
+ value: Union[Tuple[float, float], NoInitialValue],
1017
+ min: float,
1018
+ max: float,
1074
1019
  step: float = 0.001,
1075
1020
  ):
1076
1021
  self.name = name
1077
1022
  self.step = step
1078
- self.min_value = self._validate_single(min_value, context="min_value")
1079
- self.max_value = self._validate_single(max_value, context="max_value")
1023
+ self.min = self._validate_single(min, context="min")
1024
+ self.max = self._validate_single(max, context="max")
1025
+ if isinstance(value, NoInitialValue):
1026
+ value = (self.min, self.max)
1080
1027
  self._value = self._validate(value)
1081
1028
 
1082
1029
  def _validate_single(self, new_value: Any, context: Optional[str] = None) -> float:
@@ -1128,33 +1075,27 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1128
1075
  high = self._validate_single(new_value[1])
1129
1076
 
1130
1077
  if low > high:
1131
- warn(
1132
- ParameterUpdateWarning(
1133
- self.name,
1134
- type(self).__name__,
1135
- f"Low value {low} greater than high value {high}, swapping",
1136
- )
1078
+ warn_parameter_update(
1079
+ self.name,
1080
+ type(self).__name__,
1081
+ f"Low value {low} greater than high value {high}, swapping",
1137
1082
  )
1138
1083
  low, high = high, low
1139
1084
 
1140
- if low < self.min_value:
1141
- warn(
1142
- ParameterUpdateWarning(
1143
- self.name,
1144
- type(self).__name__,
1145
- f"Low value {low} below minimum {self.min_value}, clamping",
1146
- )
1085
+ if low < self.min:
1086
+ warn_parameter_update(
1087
+ self.name,
1088
+ type(self).__name__,
1089
+ f"Low value {low} below minimum {self.min}, clamping",
1147
1090
  )
1148
- low = self.min_value
1149
- if high > self.max_value:
1150
- warn(
1151
- ParameterUpdateWarning(
1152
- self.name,
1153
- type(self).__name__,
1154
- f"High value {high} above maximum {self.max_value}, clamping",
1155
- )
1091
+ low = self.min
1092
+ if high > self.max:
1093
+ warn_parameter_update(
1094
+ self.name,
1095
+ type(self).__name__,
1096
+ f"High value {high} above maximum {self.max}, clamping",
1156
1097
  )
1157
- high = self.max_value
1098
+ high = self.max
1158
1099
 
1159
1100
  return (low, high)
1160
1101
 
@@ -1162,27 +1103,25 @@ class FloatRangeParameter(Parameter[Tuple[float, float]]):
1162
1103
  """
1163
1104
  Validate complete parameter state after updates.
1164
1105
 
1165
- Ensures min_value <= max_value, swapping if needed.
1106
+ Ensures min <= max, swapping if needed.
1166
1107
  Re-validates current value against potentially updated bounds.
1167
1108
 
1168
1109
  Raises:
1169
1110
  ParameterUpdateError: If bounds are invalid (e.g. None when required)
1170
1111
  """
1171
- if self.min_value is None or self.max_value is None:
1112
+ if self.min is None or self.max is None:
1172
1113
  raise ParameterUpdateError(
1173
1114
  self.name,
1174
1115
  type(self).__name__,
1175
- "FloatRangeParameter must have both min_value and max_value bounds",
1116
+ "FloatRangeParameter must have both min and max bounds",
1176
1117
  )
1177
- if self.min_value > self.max_value:
1178
- warn(
1179
- ParameterUpdateWarning(
1180
- self.name,
1181
- type(self).__name__,
1182
- f"Min value greater than max value, swapping",
1183
- )
1118
+ if self.min > self.max:
1119
+ warn_parameter_update(
1120
+ self.name,
1121
+ type(self).__name__,
1122
+ f"Min value greater than max value, swapping",
1184
1123
  )
1185
- self.min_value, self.max_value = self.max_value, self.min_value
1124
+ self.min, self.max = self.max, self.min
1186
1125
  self.value = self._validate(self.value)
1187
1126
 
1188
1127
 
@@ -1199,7 +1138,7 @@ class UnboundedIntegerParameter(Parameter[int]):
1199
1138
  ----------
1200
1139
  name : str
1201
1140
  The name of the parameter
1202
- value : int
1141
+ value : Union[int, NoInitialValue]
1203
1142
  Initial value
1204
1143
 
1205
1144
  Examples
@@ -1221,9 +1160,11 @@ class UnboundedIntegerParameter(Parameter[int]):
1221
1160
  def __init__(
1222
1161
  self,
1223
1162
  name: str,
1224
- value: int,
1163
+ value: Union[int, NoInitialValue],
1225
1164
  ):
1226
1165
  self.name = name
1166
+ if isinstance(value, NoInitialValue):
1167
+ value = 0
1227
1168
  self._value = self._validate(value)
1228
1169
 
1229
1170
  def _validate(self, new_value: Any) -> int:
@@ -1269,7 +1210,7 @@ class UnboundedFloatParameter(Parameter[float]):
1269
1210
  ----------
1270
1211
  name : str
1271
1212
  The name of the parameter
1272
- value : float
1213
+ value : Union[float, NoInitialValue]
1273
1214
  Initial value
1274
1215
  step : float, optional
1275
1216
  Size of each increment (default is None, meaning no rounding)
@@ -1300,11 +1241,13 @@ class UnboundedFloatParameter(Parameter[float]):
1300
1241
  def __init__(
1301
1242
  self,
1302
1243
  name: str,
1303
- value: float,
1244
+ value: Union[float, NoInitialValue],
1304
1245
  step: Optional[float] = None,
1305
1246
  ):
1306
1247
  self.name = name
1307
1248
  self.step = step
1249
+ if isinstance(value, NoInitialValue):
1250
+ value = 0
1308
1251
  self._value = self._validate(value)
1309
1252
 
1310
1253
  def _validate(self, new_value: Any) -> float:
@@ -1336,7 +1279,7 @@ class UnboundedFloatParameter(Parameter[float]):
1336
1279
  """
1337
1280
  Validate complete parameter state after updates.
1338
1281
 
1339
- Ensures min_value <= max_value, swapping if needed.
1282
+ Ensures min <= max, swapping if needed.
1340
1283
  Re-validates current value against potentially updated bounds.
1341
1284
 
1342
1285
  Raises:
@@ -1358,8 +1301,8 @@ class ButtonAction(Parameter[None]):
1358
1301
  ----------
1359
1302
  name : str
1360
1303
  The name of the parameter
1361
- label : str
1362
- Text to display on the button
1304
+ label : Union[str, NoInitialValue]
1305
+ Text to display on the button (default is the button's name)
1363
1306
  callback : callable
1364
1307
  Function to execute when the button is clicked
1365
1308
 
@@ -1391,16 +1334,27 @@ class ButtonAction(Parameter[None]):
1391
1334
  value: None = field(default=None, repr=False)
1392
1335
  _is_action: bool = field(default=True, repr=False)
1393
1336
 
1394
- def __init__(self, name: str, label: str, callback: Callable):
1337
+ def __init__(
1338
+ self,
1339
+ name: str,
1340
+ label: Union[str, NoInitialValue],
1341
+ callback: Callable,
1342
+ ):
1395
1343
  """
1396
1344
  Initialize a button.
1397
1345
 
1398
- Args:
1399
- name: Internal name of the parameter
1400
- label: Text to display on the button
1401
- callback: Function to call when button is clicked
1346
+ Parameters
1347
+ ----------
1348
+ name : str
1349
+ The name of the parameter
1350
+ label : Union[str, NoInitialValue]
1351
+ Text to display on the button (default is the button's name)
1352
+ callback : callable
1353
+ Function to execute when the button is clicked
1402
1354
  """
1403
1355
  self.name = name
1356
+ if isinstance(label, NoInitialValue):
1357
+ label = name
1404
1358
  self.label = label
1405
1359
  self.callback = callback
1406
1360
  self._value = None