steer-core 0.1.26__tar.gz → 0.1.28__tar.gz

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.
Files changed (44) hide show
  1. {steer_core-0.1.26 → steer_core-0.1.28}/PKG-INFO +1 -1
  2. {steer_core-0.1.26/steer_core/Apps → steer_core-0.1.28/steer_core/ContextManagers}/ContextManagers.py +1 -1
  3. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Data/database.db +0 -0
  4. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/DataManager.py +21 -0
  5. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Coordinates.py +49 -3
  6. steer_core-0.1.28/steer_core/__init__.py +13 -0
  7. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core.egg-info/PKG-INFO +1 -1
  8. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core.egg-info/SOURCES.txt +1 -13
  9. steer_core-0.1.26/steer_core/Apps/Callbacks/ConfigInteractions.py +0 -377
  10. steer_core-0.1.26/steer_core/Apps/Callbacks/StyleManagement.py +0 -60
  11. steer_core-0.1.26/steer_core/Apps/Components/MaterialSelectors.py +0 -836
  12. steer_core-0.1.26/steer_core/Apps/Components/RangeSliderComponents.py +0 -552
  13. steer_core-0.1.26/steer_core/Apps/Components/SliderComponents.py +0 -693
  14. steer_core-0.1.26/steer_core/Apps/Performance/CallbackTimer.py +0 -18
  15. steer_core-0.1.26/steer_core/Apps/Utils/SliderControls.py +0 -728
  16. steer_core-0.1.26/steer_core/ContextManagers/__init__.py +0 -0
  17. steer_core-0.1.26/steer_core/Data/__init__.py +0 -0
  18. steer_core-0.1.26/steer_core/Decorators/Electrochemical.py +0 -29
  19. steer_core-0.1.26/steer_core/Decorators/__init__.py +0 -0
  20. steer_core-0.1.26/steer_core/Mixins/__init__.py +0 -0
  21. steer_core-0.1.26/steer_core/__init__.py +0 -4
  22. {steer_core-0.1.26 → steer_core-0.1.28}/README.md +0 -0
  23. {steer_core-0.1.26 → steer_core-0.1.28}/pyproject.toml +0 -0
  24. {steer_core-0.1.26 → steer_core-0.1.28}/setup.cfg +0 -0
  25. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Constants/Units.py +0 -0
  26. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Constants/Universal.py +0 -0
  27. {steer_core-0.1.26/steer_core/Apps/Components → steer_core-0.1.28/steer_core/Constants}/__init__.py +0 -0
  28. {steer_core-0.1.26/steer_core/Apps/Performance → steer_core-0.1.28/steer_core/ContextManagers}/__init__.py +0 -0
  29. {steer_core-0.1.26/steer_core/Apps/Utils → steer_core-0.1.28/steer_core/Data}/__init__.py +0 -0
  30. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Decorators/Coordinates.py +0 -0
  31. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Decorators/General.py +0 -0
  32. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Decorators/Objects.py +0 -0
  33. {steer_core-0.1.26/steer_core/Apps → steer_core-0.1.28/steer_core/Decorators}/__init__.py +0 -0
  34. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Colors.py +0 -0
  35. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Data.py +0 -0
  36. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Dunder.py +0 -0
  37. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Plotter.py +0 -0
  38. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/Serializer.py +0 -0
  39. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core/Mixins/TypeChecker.py +0 -0
  40. {steer_core-0.1.26/steer_core/Constants → steer_core-0.1.28/steer_core/Mixins}/__init__.py +0 -0
  41. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core.egg-info/dependency_links.txt +0 -0
  42. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core.egg-info/requires.txt +0 -0
  43. {steer_core-0.1.26 → steer_core-0.1.28}/steer_core.egg-info/top_level.txt +0 -0
  44. {steer_core-0.1.26 → steer_core-0.1.28}/test/test_validation_mixin.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steer-core
3
- Version: 0.1.26
3
+ Version: 0.1.28
4
4
  Summary: Modelling energy storage from cell to site - STEER OpenCell Design
5
5
  Author-email: Nicholas Siemons <nsiemons@stanford.edu>
6
6
  Maintainer-email: Nicholas Siemons <nsiemons@stanford.edu>
@@ -58,4 +58,4 @@ def capture_warnings(
58
58
  )
59
59
 
60
60
  # Add new warnings
61
- existing_warnings.extend(new_warnings)
61
+ existing_warnings.extend(new_warnings)
@@ -7,6 +7,7 @@ from steer_core.Constants.Units import *
7
7
 
8
8
 
9
9
  class DataManager:
10
+
10
11
  def __init__(self):
11
12
  with importlib.resources.path("steer_core.Data", "database.db") as db_path:
12
13
  self._db_path = db_path
@@ -280,6 +281,26 @@ class DataManager:
280
281
 
281
282
  return data
282
283
 
284
+ def get_prismatic_container_materials(self, most_recent: bool = True) -> pd.DataFrame:
285
+ """
286
+ Retrieves prismatic container materials from the database.
287
+
288
+ :param most_recent: If True, returns only the most recent entry.
289
+ :return: DataFrame with prismatic container materials.
290
+ """
291
+ data = (
292
+ self.get_data(table_name="prismatic_container_materials")
293
+ .groupby("name", group_keys=False)
294
+ .apply(
295
+ lambda x: x.sort_values("date", ascending=False).head(1)
296
+ if most_recent
297
+ else x
298
+ )
299
+ .reset_index(drop=True)
300
+ )
301
+
302
+ return data
303
+
283
304
  @staticmethod
284
305
  def read_half_cell_curve(half_cell_path) -> pd.DataFrame:
285
306
  """
@@ -130,7 +130,10 @@ class CoordinateMixin:
130
130
 
131
131
  @staticmethod
132
132
  def rotate_coordinates(
133
- coords: np.ndarray, axis: str, angle: float, center: tuple = None
133
+ coords: np.ndarray,
134
+ axis: str,
135
+ angle: float,
136
+ center: tuple = None
134
137
  ) -> np.ndarray:
135
138
  """
136
139
  Rotate a (N, 3) NumPy array of 3D coordinates around the specified axis.
@@ -240,9 +243,52 @@ class CoordinateMixin:
240
243
  The width of the square.
241
244
  y_width : float
242
245
  The height of the square.
246
+
247
+ Returns
248
+ -------
249
+ Tuple[np.ndarray, np.ndarray]
250
+ Tuple containing x and y coordinate arrays defining the square/rectangle
243
251
  """
244
- x_coords = [x, x, x + x_width, x + x_width, x]
245
- y_coords = [y, y + y_width, y + y_width, y, y]
252
+ x_coords = np.array([x, x, x + x_width, x + x_width, x])
253
+ y_coords = np.array([y, y + y_width, y + y_width, y, y])
254
+ return x_coords, y_coords
255
+
256
+ @staticmethod
257
+ def build_circle_array(
258
+ center_x: float, center_y: float, radius: float, num_points: int = 64, anticlockwise: bool = True
259
+ ) -> Tuple[np.ndarray, np.ndarray]:
260
+ """
261
+ Build a NumPy array representing a circle defined by its center and radius.
262
+
263
+ Parameters
264
+ ----------
265
+ center_x : float
266
+ The x-coordinate of the circle center.
267
+ center_y : float
268
+ The y-coordinate of the circle center.
269
+ radius : float
270
+ The radius of the circle.
271
+ num_points : int, optional
272
+ Number of points to use for the circle approximation, by default 64
273
+ anticlockwise : bool, optional
274
+ If True, points are ordered anticlockwise; if False, clockwise, by default True
275
+
276
+ Returns
277
+ -------
278
+ Tuple[np.ndarray, np.ndarray]
279
+ Tuple containing x and y coordinate arrays defining the circle
280
+ """
281
+ # Generate angles from 0 to 2π
282
+ angles = np.linspace(0, 2 * np.pi, num_points + 1)
283
+
284
+ # Reverse angles for clockwise direction
285
+ if not anticlockwise:
286
+ angles = angles[::-1]
287
+
288
+ # Calculate x and y coordinates
289
+ x_coords = center_x + radius * np.cos(angles)
290
+ y_coords = center_y + radius * np.sin(angles)
291
+
246
292
  return x_coords, y_coords
247
293
 
248
294
  @staticmethod
@@ -0,0 +1,13 @@
1
+ __version__ = "0.1.28"
2
+
3
+ # datamanager import
4
+ from .DataManager import DataManager
5
+
6
+ from .Mixins.Colors import ColorMixin
7
+ from .Mixins.Coordinates import CoordinateMixin
8
+ from .Mixins.Plotter import PlotterMixin
9
+ from .Mixins.TypeChecker import ValidationMixin
10
+ from .Mixins.Dunder import DunderMixin
11
+ from .Mixins.Serializer import SerializerMixin
12
+ from .Mixins.Data import DataMixin
13
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: steer-core
3
- Version: 0.1.26
3
+ Version: 0.1.28
4
4
  Summary: Modelling energy storage from cell to site - STEER OpenCell Design
5
5
  Author-email: Nicholas Siemons <nsiemons@stanford.edu>
6
6
  Maintainer-email: Nicholas Siemons <nsiemons@stanford.edu>
@@ -7,26 +7,14 @@ steer_core.egg-info/SOURCES.txt
7
7
  steer_core.egg-info/dependency_links.txt
8
8
  steer_core.egg-info/requires.txt
9
9
  steer_core.egg-info/top_level.txt
10
- steer_core/Apps/ContextManagers.py
11
- steer_core/Apps/__init__.py
12
- steer_core/Apps/Callbacks/ConfigInteractions.py
13
- steer_core/Apps/Callbacks/StyleManagement.py
14
- steer_core/Apps/Components/MaterialSelectors.py
15
- steer_core/Apps/Components/RangeSliderComponents.py
16
- steer_core/Apps/Components/SliderComponents.py
17
- steer_core/Apps/Components/__init__.py
18
- steer_core/Apps/Performance/CallbackTimer.py
19
- steer_core/Apps/Performance/__init__.py
20
- steer_core/Apps/Utils/SliderControls.py
21
- steer_core/Apps/Utils/__init__.py
22
10
  steer_core/Constants/Units.py
23
11
  steer_core/Constants/Universal.py
24
12
  steer_core/Constants/__init__.py
13
+ steer_core/ContextManagers/ContextManagers.py
25
14
  steer_core/ContextManagers/__init__.py
26
15
  steer_core/Data/__init__.py
27
16
  steer_core/Data/database.db
28
17
  steer_core/Decorators/Coordinates.py
29
- steer_core/Decorators/Electrochemical.py
30
18
  steer_core/Decorators/General.py
31
19
  steer_core/Decorators/Objects.py
32
20
  steer_core/Decorators/__init__.py
@@ -1,377 +0,0 @@
1
- from typing import List, Tuple
2
- from dash import no_update
3
-
4
-
5
- def generate_parameters_and_ranges(object, config) -> Tuple[List[float], List[float], List[float]]:
6
- """
7
- Generate parameter value lists and their corresponding min/max ranges for any object.
8
-
9
- This function extracts parameter values from an object based on a configuration's
10
- parameter list, and retrieves the minimum and maximum values for each parameter
11
- if range attributes exist (e.g., '{param}_range'), otherwise uses the current
12
- value as both min and max.
13
-
14
- Parameters
15
- ----------
16
- object : Any
17
- The object from which to extract parameter values. Must have attributes
18
- corresponding to the parameters listed in config.parameter_list.
19
- config : Type
20
- Configuration class or object that contains a 'parameter_list' attribute
21
- specifying which parameters to extract from the object.
22
-
23
- Returns
24
- -------
25
- Tuple[List[float], List[float], List[float]]
26
- A tuple containing three lists:
27
- - parameter_values: Current values of each parameter
28
- - min_values: Minimum values for each parameter (from {param}_range[0]
29
- or current value if no range exists)
30
- - max_values: Maximum values for each parameter (from {param}_range[1]
31
- or current value if no range exists)
32
-
33
- Examples
34
- --------
35
- >>> class MyObject:
36
- ... def __init__(self):
37
- ... self.temperature = 25.0
38
- ... self.temperature_range = (0.0, 100.0)
39
- ... self.pressure = 1.0
40
- >>>
41
- >>> class Config:
42
- ... parameter_list = ['temperature', 'pressure']
43
- >>>
44
- >>> obj = MyObject()
45
- >>> values, mins, maxs = generate_parameter_and_list_ranges(obj, Config)
46
- >>> print(values) # [25.0, 1.0]
47
- >>> print(mins) # [0.0, 1.0]
48
- >>> print(maxs) # [100.0, 1.0]
49
-
50
- Notes
51
- -----
52
- - If an object has a '{param}_range' attribute, it should be a tuple/list
53
- with exactly two elements: (min_value, max_value)
54
- - If no range attribute exists for a parameter, the current value is used
55
- for both minimum and maximum values
56
- - All extracted values are expected to be numeric (convertible to float)
57
- """
58
- parameter_values = []
59
- min_values = []
60
- max_values = []
61
-
62
- parameter_list = config.parameter_list
63
-
64
- for param in parameter_list:
65
-
66
- value = getattr(object, param)
67
- parameter_values.append(value)
68
-
69
- if hasattr(object, f"{param}_range"):
70
- min_values.append(getattr(object, f"{param}_range")[0])
71
- max_values.append(getattr(object, f"{param}_range")[1])
72
- else:
73
- min_values.append(value)
74
- max_values.append(value)
75
-
76
- return parameter_values, min_values, max_values
77
-
78
-
79
-
80
- def generate_rangeslider_parameters_and_ranges(object, config) -> Tuple[
81
- List[float],
82
- List[float],
83
- List[float],
84
- List[float],
85
- ]:
86
- """
87
- Generate range slider parameter values and their corresponding min/max bounds for any object.
88
-
89
- This function extracts range parameter values from an object based on a configuration's
90
- range_slider_parameters list. Each parameter is expected to be a tuple/list representing
91
- a range (start, end). It also retrieves the absolute minimum and maximum bounds for each
92
- parameter from corresponding '{param}_range' attributes, or uses the current range values
93
- as bounds if no range attribute exists.
94
-
95
- Parameters
96
- ----------
97
- object : Any
98
- The object from which to extract range parameter values. Must have attributes
99
- corresponding to the parameters listed in config.range_slider_parameters, where
100
- each attribute contains a tuple/list of (start, end) values. Optionally has
101
- '{param}_range' attributes defining the absolute bounds for each parameter.
102
- config : Any
103
- Configuration class or object that contains a 'range_slider_parameters' attribute
104
- specifying which range parameters to extract from the object.
105
-
106
- Returns
107
- -------
108
- Tuple[List[float], List[float], List[float], List[float]]
109
- A tuple containing four lists:
110
- - start_values: Start values for each range parameter (from param[0])
111
- - end_values: End values for each range parameter (from param[1])
112
- - min_values: Absolute minimum bounds for each parameter (from {param}_range[0]
113
- or param[0] if no range exists)
114
- - max_values: Absolute maximum bounds for each parameter (from {param}_range[1]
115
- or param[1] if no range exists)
116
-
117
- Examples
118
- --------
119
- >>> class MyCollector:
120
- ... def __init__(self):
121
- ... self.voltage_window = (2.5, 4.2) # Current range setting
122
- ... self.voltage_window_range = (0.0, 5.0) # Absolute bounds
123
- ... self.current_limit = (0.1, 2.0) # Current range setting
124
- ... # No current_limit_range, so uses current values as bounds
125
- >>>
126
- >>> class Config:
127
- ... range_slider_parameters = ['voltage_window', 'current_limit']
128
- >>>
129
- >>> collector = MyCollector()
130
- >>> starts, ends, mins, maxs = generate_rangeslider_parameters_and_ranges_from_config(
131
- ... collector, Config)
132
- >>> print(starts) # [2.5, 0.1]
133
- >>> print(ends) # [4.2, 2.0]
134
- >>> print(mins) # [0.0, 0.1] # Uses range for voltage, current value for current
135
- >>> print(maxs) # [5.0, 2.0] # Uses range for voltage, current value for current
136
-
137
- Notes
138
- -----
139
- - If config.range_slider_parameters is empty, returns four empty lists
140
- - Each parameter in range_slider_parameters must exist as an attribute on the object
141
- and contain exactly two elements: (start_value, end_value)
142
- - If a parameter has a corresponding '{param}_range' attribute, those bounds are used
143
- - If no range attribute exists for a parameter, the current start/end values are used
144
- as the minimum/maximum bounds respectively
145
- - All values are expected to be numeric (convertible to float)
146
- - This function is typically used for range slider UI components where
147
- users can select a range within predefined bounds
148
-
149
- Raises
150
- ------
151
- AttributeError
152
- If the object doesn't have the required parameter attributes or if config
153
- doesn't have range_slider_parameters attribute
154
- IndexError
155
- If parameter values don't contain exactly two elements
156
- """
157
- start_values = []
158
- end_values = []
159
- min_values = []
160
- max_values = []
161
-
162
- parameter_list = config.range_slider_parameters
163
-
164
- for param in parameter_list:
165
-
166
- value = getattr(object, param)
167
- start_values.append(value[0])
168
- end_values.append(value[1])
169
-
170
- if hasattr(object, f"{param}_range"):
171
- min_values.append(getattr(object, f"{param}_range")[0])
172
- max_values.append(getattr(object, f"{param}_range")[1])
173
- else:
174
- min_values.append(value[0])
175
- max_values.append(value[1])
176
-
177
- return start_values, end_values, min_values, max_values
178
-
179
-
180
- def validate_dependent_properties(object, config) -> None:
181
- """
182
- Validate and clamp dependent properties to their valid hard ranges for any object.
183
-
184
- This function validates parameter values from an object based on a configuration's
185
- parameter list, checking each parameter against its corresponding '{param}_hard_range'
186
- attribute. If a parameter value falls outside its hard range, it is automatically
187
- clamped to the nearest valid boundary (minimum or maximum).
188
-
189
- Parameters
190
- ----------
191
- object : Any
192
- The object whose parameter values will be validated and potentially modified.
193
- Must have attributes corresponding to the parameters listed in config.parameter_list.
194
- Should have '{param}_hard_range' attributes defining the valid bounds for validation.
195
- config : Any
196
- Configuration class or object that contains a 'parameter_list' attribute
197
- specifying which parameters to validate on the object.
198
-
199
- Returns
200
- -------
201
- None
202
- This function modifies the object in-place and does not return any values.
203
-
204
- Examples
205
- --------
206
- >>> class MyObject:
207
- ... def __init__(self):
208
- ... self.temperature = 150.0 # Outside valid range
209
- ... self.temperature_hard_range = (0.0, 100.0)
210
- ... self.pressure = 0.5 # Within valid range
211
- ... self.pressure_hard_range = (0.0, 10.0)
212
- >>>
213
- >>> class Config:
214
- ... parameter_list = ['temperature', 'pressure']
215
- >>>
216
- >>> obj = MyObject()
217
- >>> print(obj.temperature) # 150.0 (before validation)
218
- >>> validate_dependent_properties(obj, Config)
219
- >>> print(obj.temperature) # 100.0 (clamped to maximum)
220
- >>> print(obj.pressure) # 0.5 (unchanged, within range)
221
-
222
- Notes
223
- -----
224
- - Only parameters with corresponding '{param}_hard_range' attributes are validated
225
- - Parameters without hard range attributes are silently skipped (no validation performed)
226
- - Hard range attributes should be tuples/lists with exactly two elements: (min_value, max_value)
227
- - Values are clamped to the nearest boundary if they fall outside the valid range
228
- - This function modifies the object in-place, changing parameter values as needed
229
- - Typically used after parameter updates to ensure all values remain within valid bounds
230
-
231
- Raises
232
- ------
233
- AttributeError
234
- If the object doesn't have a parameter attribute listed in config.parameter_list,
235
- or if config doesn't have a parameter_list attribute
236
- IndexError
237
- If a hard_range attribute doesn't contain exactly two elements
238
- """
239
- parameter_list = config.parameter_list
240
-
241
- for param in parameter_list:
242
- try:
243
- # Get the hard range and current value for this parameter
244
- param_range = getattr(object, f"{param}_hard_range")
245
- param_value = getattr(object, param)
246
-
247
- # Clamp value to valid range if necessary
248
- if param_value < param_range[0]:
249
- setattr(object, param, param_range[0])
250
- elif param_value > param_range[1]:
251
- setattr(object, param, param_range[1])
252
-
253
- except AttributeError:
254
- # Parameter or hard range doesn't exist, skip validation
255
- continue
256
-
257
-
258
- def create_no_update_response(
259
- config=None,
260
- existing_warnings: List[str] = [],
261
- n: int = None,
262
- n_rangeslider: int = None,
263
- ) -> Tuple:
264
- """
265
- Create a no-update response tuple for Dash callbacks based on configuration parameters.
266
-
267
- This function generates a standardized response tuple containing `no_update` values
268
- for all UI components defined in a configuration object. This is typically used in
269
- Dash callbacks when no updates should be made to the UI components, preserving
270
- their current state while potentially updating warning messages.
271
-
272
- Parameters
273
- ----------
274
- config : Any, optional
275
- Configuration object that defines the UI components and their parameters.
276
- Should contain attributes like 'parameter_list', 'range_slider_parameters',
277
- 'dropdown_menu', 'radioitem_parameters', and 'text_parameters'.
278
- If None, only basic response structure is created.
279
- existing_warnings : List[str], default []
280
- List of existing warning messages to include in the response.
281
- These warnings will be preserved in the callback output.
282
- n : int, optional
283
- Number of regular slider/input parameters. If None, determined from
284
- config.parameter_list length. Used to create the correct number of
285
- no_update responses for sliders and inputs.
286
- n_rangeslider : int, optional
287
- Number of range slider parameters. If None, determined from
288
- config.range_slider_parameters length. Used to create the correct
289
- number of no_update responses for range sliders.
290
-
291
- Returns
292
- -------
293
- Tuple
294
- A tuple containing warning messages followed by no_update responses for all
295
- UI components defined in the configuration:
296
- - warnings: List[str] - Warning messages (first element)
297
- - cache_key: no_update - Cache key for callback optimization
298
- - slider_values: List[no_update] - Current slider values
299
- - slider_mins: List[no_update] - Slider minimum values
300
- - slider_maxs: List[no_update] - Slider maximum values
301
- - slider_marks: List[no_update] - Slider tick marks
302
- - slider_steps: List[no_update] - Slider step sizes
303
- - input_steps: List[no_update] - Input field step sizes
304
-
305
- Additional elements based on config attributes:
306
- - dropdown_value: no_update (if config.dropdown_menu exists)
307
- - range_slider_*: List[no_update] (if config.range_slider_parameters exists)
308
- - radioitem_values: List[no_update] (if config.radioitem_parameters exists)
309
- - text_values: List[no_update] (if config.text_parameters exists)
310
-
311
- Examples
312
- --------
313
- >>> class Config:
314
- ... parameter_list = ['temperature', 'pressure']
315
- ... dropdown_menu = True
316
- ... range_slider_parameters = ['voltage_window']
317
- ... radioitem_parameters = ['mode']
318
- ... text_parameters = ['label']
319
- >>>
320
- >>> config = Config()
321
- >>> warnings = ['Temperature out of range']
322
- >>> response = create_no_update_response(config, warnings)
323
- >>> print(len(response)) # Number of response elements
324
- >>> print(response[0]) # ['Temperature out of range']
325
- >>> print(response[1]) # no_update (cache_key)
326
-
327
- Notes
328
- -----
329
- - This function is primarily used in Dash callback error handling or when
330
- callback conditions are not met and no UI updates should occur
331
- - The response tuple structure must match the callback's Output specification
332
- - Optional UI components (dropdown, range sliders, radio items, text inputs)
333
- are only included in the response if they exist in the configuration
334
- - All UI component responses use Dash's `no_update` to preserve current state
335
- - The function automatically determines response tuple length based on config
336
-
337
- Raises
338
- ------
339
- AttributeError
340
- If config object doesn't have expected attributes when accessed
341
- """
342
- n = len(config.parameter_list) if n is None else n
343
-
344
- response = (
345
- no_update, # cache_key
346
- [no_update] * n, # slider values
347
- [no_update] * n, # slider mins
348
- [no_update] * n, # slider maxs
349
- [no_update] * n, # slider marks
350
- [no_update] * n, # slider steps
351
- [no_update] * n, # input steps
352
- )
353
-
354
- if hasattr(config, "dropdown_menu") and config.dropdown_menu:
355
- response += (no_update,)
356
-
357
- if hasattr(config, "range_slider_parameters") and config.range_slider_parameters:
358
- n_rangeslider = len(config.range_slider_parameters) if n_rangeslider is None else n_rangeslider
359
- response += (
360
- [no_update] * n_rangeslider, # range_slider_values
361
- [no_update] * n_rangeslider, # range slider mins
362
- [no_update] * n_rangeslider, # range slider maxs
363
- [no_update] * n_rangeslider, # range slider marks
364
- [no_update] * n_rangeslider, # range slider steps
365
- [no_update] * n_rangeslider, # range slider start values
366
- [no_update] * n_rangeslider, # range slider end values
367
- )
368
-
369
- if hasattr(config, "radioitem_parameters") and config.radioitem_parameters:
370
- num_radioitem_params = len(config.radioitem_parameters)
371
- response += ([no_update] * num_radioitem_params,) # radioitem values
372
-
373
- if hasattr(config, "text_parameters") and config.text_parameters:
374
- num_text_params = len(config.text_parameters)
375
- response += ([no_update] * num_text_params,) # text item values
376
-
377
- return (existing_warnings,) + tuple(response)
@@ -1,60 +0,0 @@
1
- from dash import no_update
2
- from typing import List
3
-
4
- def update_style_display(current_style, target_display):
5
- """
6
- Helper function to update style display property with safe None handling.
7
-
8
- Args:
9
- current_style: Current style dict or None
10
- target_display: Target display value ("block" or "none")
11
-
12
- Returns:
13
- no_update if style already has target display, otherwise updated style dict
14
- """
15
- current_display = (current_style or {}).get("display")
16
- if current_display == target_display:
17
- return no_update
18
- return {**(current_style or {}), "display": target_display}
19
-
20
-
21
-
22
- def update_tab_styles(active_tab: str, tab_names: List[str], current_styles: List[dict]) -> List:
23
- """
24
- Helper function to update tab styles based on the active tab.
25
- Only updates styles when the display property needs to change.
26
-
27
- Parameters
28
- ----------
29
- active_tab : str
30
- The currently active tab name
31
- tab_names : List[str]
32
- List of all tab names to check against
33
- current_styles : List[dict]
34
- List of current style dictionaries for each tab
35
-
36
- Returns
37
- -------
38
- List
39
- List of updated styles or no_update for each tab
40
- """
41
- updated_styles = []
42
-
43
- for tab_name, current_style in zip(tab_names, current_styles):
44
- # Determine what the display should be
45
- should_display = "block" if active_tab == tab_name else "none"
46
-
47
- # Get current display value (handle None style case)
48
- current_display = (current_style or {}).get("display")
49
-
50
- # If display is already correct, return no_update
51
- if current_display == should_display:
52
- updated_styles.append(no_update)
53
- else:
54
- # Create new style preserving existing properties
55
- new_style = {**(current_style or {}), "display": should_display}
56
- updated_styles.append(new_style)
57
-
58
- return updated_styles
59
-
60
-