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/support.py ADDED
@@ -0,0 +1,195 @@
1
+ from abc import ABCMeta
2
+ from typing import Any, List
3
+ from warnings import warn
4
+ from contextlib import contextmanager
5
+ import matplotlib.pyplot as plt
6
+
7
+
8
+ @contextmanager
9
+ def plot_context():
10
+ plt.ioff()
11
+ try:
12
+ yield
13
+ finally:
14
+ plt.ion()
15
+
16
+
17
+ class NoUpdate:
18
+ """Singleton class to represent a non-update in parameter operations."""
19
+
20
+ _instance = None
21
+ _noupdate_identifier = "NO_UPDATE"
22
+
23
+ def __new__(cls):
24
+ if cls._instance is None:
25
+ cls._instance = super().__new__(cls)
26
+ return cls._instance
27
+
28
+ def __eq__(self, other: Any):
29
+ """This makes sure all comparisons of NoUpdate objects return True"""
30
+ return isinstance(other, NoUpdate) or (
31
+ hasattr(other, "_noupdate_identifier")
32
+ and other._noupdate_identifier == self._noupdate_identifier
33
+ )
34
+
35
+ def __repr__(self):
36
+ return "NotUpdated"
37
+
38
+
39
+ class NoInitialValue:
40
+ """Singleton class to represent a non-initial value in parameter operations."""
41
+
42
+ _instance = None
43
+ _noinitialvalue_identifier = "NO_INITIAL_VALUE"
44
+
45
+ def __new__(cls):
46
+ if cls._instance is None:
47
+ cls._instance = super().__new__(cls)
48
+ return cls._instance
49
+
50
+ def __eq__(self, other: Any):
51
+ """This makes sure all comparisons of NoInitialValue objects return True"""
52
+ return isinstance(other, NoInitialValue) or (
53
+ hasattr(other, "_noinitialvalue_identifier")
54
+ and other._noinitialvalue_identifier == self._noinitialvalue_identifier
55
+ )
56
+
57
+ def __repr__(self):
58
+ return "NotInitialized"
59
+
60
+
61
+ # Keep original Parameter class and exceptions unchanged
62
+ class ParameterAddError(Exception):
63
+ """
64
+ Exception raised when there is an error creating a new parameter.
65
+
66
+ Parameters
67
+ ----------
68
+ parameter_name : str
69
+ Name of the parameter that failed to be created
70
+ parameter_type : str
71
+ Type of the parameter that failed to be created
72
+ message : str, optional
73
+ Additional error details
74
+ """
75
+
76
+ def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
77
+ self.parameter_name = parameter_name
78
+ self.parameter_type = parameter_type
79
+ super().__init__(
80
+ f"Failed to create {parameter_type} parameter '{parameter_name}'"
81
+ + (f": {message}" if message else "")
82
+ )
83
+
84
+
85
+ class ParameterUpdateError(Exception):
86
+ """
87
+ Exception raised when there is an error updating an existing parameter.
88
+
89
+ Parameters
90
+ ----------
91
+ parameter_name : str
92
+ Name of the parameter that failed to update
93
+ parameter_type : str
94
+ Type of the parameter that failed to update
95
+ message : str, optional
96
+ Additional error details
97
+ """
98
+
99
+ def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
100
+ self.parameter_name = parameter_name
101
+ self.parameter_type = parameter_type
102
+ super().__init__(
103
+ f"Failed to update {parameter_type} parameter '{parameter_name}'"
104
+ + (f": {message}" if message else "")
105
+ )
106
+
107
+
108
+ class ParameterUpdateWarning(Warning):
109
+ """
110
+ Warning raised when there is a non-critical issue updating a parameter.
111
+
112
+ Parameters
113
+ ----------
114
+ parameter_name : str
115
+ Name of the parameter that had the warning
116
+ parameter_type : str
117
+ Type of the parameter
118
+ message : str, optional
119
+ Additional warning details
120
+ """
121
+
122
+ def __init__(self, parameter_name: str, parameter_type: str, message: str = None):
123
+ self.parameter_name = parameter_name
124
+ self.parameter_type = parameter_type
125
+ super().__init__(
126
+ f"Warning updating {parameter_type} parameter '{parameter_name}'"
127
+ + (f": {message}" if message else "")
128
+ )
129
+
130
+
131
+ def warn_parameter_update(
132
+ parameter_name: str, parameter_type: str, message: str = None
133
+ ):
134
+ """
135
+ Warn the user that a parameter has been updated to a value behind the scenes.
136
+ """
137
+ warn(ParameterUpdateWarning(parameter_name, parameter_type, message))
138
+
139
+
140
+ def get_parameter_attributes(param_class) -> List[str]:
141
+ """
142
+ Get all valid attributes for a parameter class.
143
+
144
+ Parameters
145
+ ----------
146
+ param_class : class
147
+ The parameter class to inspect
148
+
149
+ Returns
150
+ -------
151
+ list of str
152
+ Names of all valid attributes for the parameter class
153
+ """
154
+ attributes = []
155
+
156
+ # Walk through class hierarchy in reverse (most specific to most general)
157
+ for cls in reversed(param_class.__mro__):
158
+ if hasattr(cls, "__annotations__"):
159
+ # Only add annotations that haven't been specified by a more specific class
160
+ for name in cls.__annotations__:
161
+ if not name.startswith("_"):
162
+ attributes.append(name)
163
+
164
+ return attributes
165
+
166
+
167
+ class ParameterMeta(ABCMeta):
168
+ _parameter_types = {}
169
+ _parameter_ids = {} # Store unique identifiers for our parameter types
170
+
171
+ def __new__(cls, name, bases, namespace):
172
+ parameter_class = super().__new__(cls, name, bases, namespace)
173
+ if name != "Parameter":
174
+ # Generate a unique ID for this parameter type
175
+ type_id = f"syd.parameters.{name}" # Using fully qualified name
176
+ cls._parameter_ids[name] = type_id
177
+
178
+ # Add ID to the class
179
+ if not hasattr(parameter_class, "_parameter_type_id"):
180
+ setattr(parameter_class, "_parameter_type_id", type_id)
181
+ else:
182
+ if getattr(parameter_class, "_parameter_type_id") != type_id:
183
+ raise ValueError(
184
+ f"Parameter type {name} has multiple IDs: {type_id} and {getattr(parameter_class, '_parameter_type_id')}"
185
+ )
186
+ cls._parameter_types[name] = parameter_class
187
+ return parameter_class
188
+
189
+ def __instancecheck__(cls, instance):
190
+ type_id = cls._parameter_ids.get(cls.__name__)
191
+ if not type_id:
192
+ return False
193
+
194
+ # Check if instance has our type ID
195
+ return getattr(instance.__class__, "_parameter_type_id", None) == type_id