squirrels 0.3.3__py3-none-any.whl → 0.4.1__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.

Potentially problematic release.


This version of squirrels might be problematic. Click here for more details.

Files changed (56) hide show
  1. squirrels/__init__.py +7 -3
  2. squirrels/_api_response_models.py +96 -72
  3. squirrels/_api_server.py +375 -201
  4. squirrels/_authenticator.py +23 -22
  5. squirrels/_command_line.py +70 -46
  6. squirrels/_connection_set.py +23 -25
  7. squirrels/_constants.py +29 -78
  8. squirrels/_dashboards_io.py +61 -0
  9. squirrels/_environcfg.py +53 -50
  10. squirrels/_initializer.py +184 -141
  11. squirrels/_manifest.py +168 -195
  12. squirrels/_models.py +159 -292
  13. squirrels/_package_loader.py +7 -8
  14. squirrels/_parameter_configs.py +173 -141
  15. squirrels/_parameter_sets.py +49 -38
  16. squirrels/_py_module.py +7 -7
  17. squirrels/_seeds.py +13 -12
  18. squirrels/_utils.py +114 -54
  19. squirrels/_version.py +1 -1
  20. squirrels/arguments/init_time_args.py +16 -10
  21. squirrels/arguments/run_time_args.py +89 -24
  22. squirrels/dashboards.py +82 -0
  23. squirrels/data_sources.py +212 -232
  24. squirrels/dateutils.py +29 -26
  25. squirrels/package_data/assets/index.css +1 -1
  26. squirrels/package_data/assets/index.js +27 -18
  27. squirrels/package_data/base_project/.gitignore +2 -2
  28. squirrels/package_data/base_project/connections.yml +1 -1
  29. squirrels/package_data/base_project/dashboards/dashboard_example.py +32 -0
  30. squirrels/package_data/base_project/dashboards.yml +10 -0
  31. squirrels/package_data/base_project/docker/.dockerignore +9 -4
  32. squirrels/package_data/base_project/docker/Dockerfile +7 -6
  33. squirrels/package_data/base_project/docker/compose.yml +1 -1
  34. squirrels/package_data/base_project/env.yml +2 -2
  35. squirrels/package_data/base_project/models/dbviews/{database_view1.py → dbview_example.py} +2 -1
  36. squirrels/package_data/base_project/models/dbviews/{database_view1.sql → dbview_example.sql} +3 -2
  37. squirrels/package_data/base_project/models/federates/{dataset_example.py → federate_example.py} +6 -6
  38. squirrels/package_data/base_project/models/federates/{dataset_example.sql → federate_example.sql} +1 -1
  39. squirrels/package_data/base_project/parameters.yml +6 -4
  40. squirrels/package_data/base_project/pyconfigs/auth.py +1 -1
  41. squirrels/package_data/base_project/pyconfigs/connections.py +1 -1
  42. squirrels/package_data/base_project/pyconfigs/context.py +38 -10
  43. squirrels/package_data/base_project/pyconfigs/parameters.py +15 -7
  44. squirrels/package_data/base_project/squirrels.yml.j2 +14 -7
  45. squirrels/package_data/templates/index.html +3 -3
  46. squirrels/parameter_options.py +103 -106
  47. squirrels/parameters.py +347 -195
  48. squirrels/project.py +378 -0
  49. squirrels/user_base.py +14 -6
  50. {squirrels-0.3.3.dist-info → squirrels-0.4.1.dist-info}/METADATA +9 -21
  51. squirrels-0.4.1.dist-info/RECORD +60 -0
  52. squirrels/_timer.py +0 -23
  53. squirrels-0.3.3.dist-info/RECORD +0 -56
  54. {squirrels-0.3.3.dist-info → squirrels-0.4.1.dist-info}/LICENSE +0 -0
  55. {squirrels-0.3.3.dist-info → squirrels-0.4.1.dist-info}/WHEEL +0 -0
  56. {squirrels-0.3.3.dist-info → squirrels-0.4.1.dist-info}/entry_points.txt +0 -0
squirrels/parameters.py CHANGED
@@ -1,12 +1,14 @@
1
1
  from __future__ import annotations
2
- from typing import Callable, Type, Sequence, Optional, Union, Any
2
+ from typing import Callable, Type, TypeVar, Sequence, Any
3
3
  from dataclasses import dataclass
4
4
  from datetime import datetime, date
5
5
  from decimal import Decimal
6
6
  from abc import ABCMeta, abstractmethod
7
7
 
8
- from . import _parameter_configs as pc, _parameter_sets as ps, parameter_options as po, data_sources as d
9
- from . import _api_response_models as arm, _utils as u
8
+ from . import _parameter_configs as _pc, _parameter_sets as ps, parameter_options as _po, data_sources as d
9
+ from . import _api_response_models as arm, _utils as _u
10
+
11
+ IntOrFloat = TypeVar("IntOrFloat", int, float)
10
12
 
11
13
 
12
14
  @dataclass
@@ -14,7 +16,7 @@ class Parameter(metaclass=ABCMeta):
14
16
  """
15
17
  Abstract class for all parameter widgets
16
18
  """
17
- _config: pc.ParameterConfig
19
+ _config: _pc.ParameterConfig
18
20
 
19
21
  @abstractmethod
20
22
  def is_enabled(self) -> bool:
@@ -22,18 +24,39 @@ class Parameter(metaclass=ABCMeta):
22
24
 
23
25
  @staticmethod
24
26
  @abstractmethod
25
- def _ParameterConfigType() -> Type:
27
+ def _ParameterConfigType() -> Type[_pc.ParameterConfig]:
26
28
  pass
27
29
 
30
+ @classmethod
31
+ def _CreateWithOptionsHelper(
32
+ cls, name: str, label: str, all_options: Sequence[_po.ParameterOption | dict], *, description: str = "",
33
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
34
+ ) -> None:
35
+ param_config_type = cls._ParameterConfigType()
36
+ param_config = param_config_type(
37
+ name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name, **kwargs
38
+ )
39
+ ps.ParameterConfigsSetIO.obj.add(param_config)
40
+
41
+ @classmethod
42
+ def Create(
43
+ cls, name: str, label: str, all_options: Sequence[_po.ParameterOption | dict], *, description: str = "",
44
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
45
+ ) -> None:
46
+ """
47
+ DEPRECATED. Use CreateWithOptions instead
48
+ """
49
+ cls._CreateWithOptionsHelper(name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name)
50
+
28
51
  @classmethod
29
52
  def CreateWithOptions(
30
- cls, name: str, label: str, all_options: Sequence[Union[po.ParameterOption, dict]], *, description: str = "",
31
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
53
+ cls, name: str, label: str, all_options: Sequence[_po.ParameterOption | dict], *, description: str = "",
54
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
32
55
  ) -> None:
33
56
  """
34
57
  Method for creating the configurations for a Parameter that may include user attribute or parent
35
58
 
36
- Parameters:
59
+ Arguments:
37
60
  name: The name of the parameter
38
61
  label: The display label for the parameter
39
62
  all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
@@ -41,35 +64,33 @@ class Parameter(metaclass=ABCMeta):
41
64
  user_attribute: The user attribute that may cascade the options for this parameter. Default is None
42
65
  parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
43
66
  """
44
- param_config_type = cls._ParameterConfigType()
45
- param_config = param_config_type(name, label, all_options, description=description, user_attribute=user_attribute,
46
- parent_name=parent_name)
47
- ps.ParameterConfigsSetIO.obj.add(param_config)
48
-
49
- @classmethod
50
- def Create(
51
- cls, name: str, label: str, all_options: Sequence[Union[po.ParameterOption, dict]], *, description: str = "",
52
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
53
- ) -> None:
54
- """
55
- DEPRECATED. Use CreateWithOptions instead
56
- """
57
- cls.CreateWithOptions(name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name)
67
+ cls._CreateWithOptionsHelper(name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name)
58
68
 
59
69
  @classmethod
60
70
  @abstractmethod
61
71
  def CreateSimple(cls, name: str, label: str, *args, description: str = "", **kwargs) -> None:
62
72
  pass
73
+
74
+ @classmethod
75
+ def _CreateFromSourceHelper(
76
+ cls, name: str, label: str, data_source: d.DataSource | dict, *, extra_args: dict = {}, description: str = "",
77
+ user_attribute: str | None = None, parent_name: str | None = None
78
+ ) -> None:
79
+ param_config = _pc.DataSourceParameterConfig(
80
+ cls._ParameterConfigType(), name, label, data_source, description=description, user_attribute=user_attribute,
81
+ parent_name=parent_name, extra_args=extra_args
82
+ )
83
+ ps.ParameterConfigsSetIO.obj.add(param_config)
63
84
 
64
85
  @classmethod
65
86
  def CreateFromSource(
66
- cls, name: str, label: str, data_source: Union[d.DataSource , dict], *, description: str = "",
67
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
87
+ cls, name: str, label: str, data_source: d.DataSource | dict, *, description: str = "",
88
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
68
89
  ) -> None:
69
90
  """
70
91
  Method for creating the configurations for any Parameter that uses a DataSource to receive the options
71
92
 
72
- Parameters:
93
+ Arguments:
73
94
  name: The name of the parameter
74
95
  label: The display label for the parameter
75
96
  data_source: The lookup table to use for this parameter
@@ -77,25 +98,28 @@ class Parameter(metaclass=ABCMeta):
77
98
  user_attribute: The user attribute that may cascade the options for this parameter. Default is None
78
99
  parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
79
100
  """
80
- param_config_type = cls._ParameterConfigType()
81
- param_config = pc.DataSourceParameterConfig(param_config_type, name, label, data_source, description=description,
82
- user_attribute=user_attribute, parent_name=parent_name)
83
- ps.ParameterConfigsSetIO.obj.add(param_config)
101
+ cls._CreateFromSourceHelper(name, label, data_source, description=description, user_attribute=user_attribute, parent_name=parent_name)
84
102
 
85
103
  def _enquote(self, value: str) -> str:
86
104
  return "'" + value.replace("'", "''") + "'"
87
105
 
88
- def _validate_date(self, input_date: str) -> date:
106
+ def _validate_input_date(self, input_date: date | str, curr_option: _po._DateTypeParameterOption) -> date:
107
+ if isinstance(input_date, str):
108
+ try:
109
+ input_date = datetime.strptime(input_date.strip(), "%Y-%m-%d").date()
110
+ except ValueError:
111
+ raise self._config._invalid_input_error(str(input_date), "Must be a date in YYYY-MM-DD format.")
112
+
89
113
  try:
90
- return datetime.strptime(input_date.strip(), "%Y-%m-%d").date() if isinstance(input_date, str) else input_date
91
- except ValueError as e:
92
- self._config._raise_invalid_input_error(input_date, "Must be a date in YYYY-MM-DD format.", e)
114
+ return curr_option._validate_date(input_date)
115
+ except _u.ConfigurationError as e:
116
+ raise self._config._invalid_input_error(str(input_date), str(e))
93
117
 
94
- def _validate_number(self, input_number: po.Number, curr_option: po._NumericParameterOption) -> Decimal:
118
+ def _validate_number(self, input_number: _po.Number, curr_option: _po._NumericParameterOption) -> Decimal:
95
119
  try:
96
120
  return curr_option._validate_value(input_number)
97
- except u.ConfigurationError as e:
98
- self._config._raise_invalid_input_error(input_number, str(e), e)
121
+ except _u.ConfigurationError as e:
122
+ raise self._config._invalid_input_error(str(input_number), str(e))
99
123
 
100
124
  @abstractmethod
101
125
  def _to_json_dict0(self) -> dict:
@@ -120,8 +144,8 @@ class Parameter(metaclass=ABCMeta):
120
144
 
121
145
  @dataclass
122
146
  class _SelectionParameter(Parameter):
123
- _config: pc.SelectionParameterConfig
124
- _options: Sequence[po.SelectParameterOption]
147
+ _config: _pc.SelectionParameterConfig
148
+ _options: Sequence[_po.SelectParameterOption]
125
149
 
126
150
  def __post_init__(self):
127
151
  self._options = tuple(self._options)
@@ -135,7 +159,7 @@ class _SelectionParameter(Parameter):
135
159
 
136
160
  def _validate_selected_id_in_options(self, selected_id):
137
161
  if selected_id not in (x._identifier for x in self._options):
138
- self._config._raise_invalid_input_error(selected_id, f"The selected id {selected_id} does not exist in available options.")
162
+ raise self._config._invalid_input_error(selected_id, f"The selected id {selected_id} does not exist in available options.")
139
163
 
140
164
  @abstractmethod
141
165
  def _to_json_dict0(self) -> dict:
@@ -158,8 +182,8 @@ class SingleSelectParameter(_SelectionParameter):
158
182
  options: The parameter options that are currently selectable
159
183
  selected_id: The ID of the selected option
160
184
  """
161
- _config: pc.SingleSelectParameterConfig
162
- _selected_id: Optional[str]
185
+ _config: _pc.SingleSelectParameterConfig
186
+ _selected_id: str | None
163
187
 
164
188
  def __post_init__(self):
165
189
  super().__post_init__()
@@ -171,16 +195,16 @@ class SingleSelectParameter(_SelectionParameter):
171
195
 
172
196
  @staticmethod
173
197
  def _ParameterConfigType():
174
- return pc.SingleSelectParameterConfig
198
+ return _pc.SingleSelectParameterConfig
175
199
 
176
200
  @classmethod
177
201
  def CreateSimple(
178
- cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, description: str = "", **kwargs
202
+ cls, name: str, label: str, all_options: Sequence[_po.SelectParameterOption], *, description: str = "", **kwargs
179
203
  ) -> None:
180
204
  """
181
205
  Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
182
206
 
183
- Parameters:
207
+ Arguments:
184
208
  name: The name of the parameter
185
209
  label: The display label for the parameter
186
210
  all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
@@ -189,12 +213,12 @@ class SingleSelectParameter(_SelectionParameter):
189
213
  cls.CreateWithOptions(name, label, all_options, description=description)
190
214
 
191
215
  def get_selected(
192
- self, field: Optional[str] = None, *, default_field: Optional[str] = None, default: Any = None, **kwargs
193
- ) -> Union[po.SelectParameterOption, Any, None]:
216
+ self, field: str | None = None, *, default_field: str | None = None, default: Any = None, **kwargs
217
+ ) -> _po.SelectParameterOption | Any | None:
194
218
  """
195
219
  Gets the selected single-select option or selected custom field
196
220
 
197
- Parameters:
221
+ Arguments:
198
222
  field: If field is not None, the method gets this field from the "custom_fields" attribute of the selected option.
199
223
  Otherwise, returns the class object of the selected option
200
224
  default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
@@ -210,50 +234,76 @@ class SingleSelectParameter(_SelectionParameter):
210
234
  if field is not None:
211
235
  selected = selected.get_custom_field(field, default_field=default_field, default=default)
212
236
  return selected
213
- return u.process_if_not_none(self._selected_id, get_selected_from_id)
237
+ return _u.process_if_not_none(self._selected_id, get_selected_from_id)
238
+
239
+ def get_selected_quoted(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str | None:
240
+ """
241
+ Gets the selected single-select option surrounded by single quotes
242
+
243
+ Arguments:
244
+ field: The "custom_fields" attribute of the selected option.
245
+ default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
246
+ as the "field" instead.
247
+ default: If field does not exist for a parameter option, default_field is None, but default is not None, then the default
248
+ is returned as the selected field. Does nothing if default_field is not None
249
+
250
+ Returns:
251
+ A string surrounded by single quotes
252
+ """
253
+ selected_value = self.get_selected(field, default_field=default_field, default=default)
254
+
255
+ def _enquote(x: Any) -> str:
256
+ if not isinstance(selected_value, str):
257
+ raise _u.ConfigurationError(
258
+ f"Method 'get_selected_quoted' can only be used on fields with only string values"
259
+ )
260
+ return self._enquote(x)
261
+
262
+ return _u.process_if_not_none(selected_value, _enquote)
214
263
 
215
- def get_selected_id(self, **kwargs) -> Optional[str]:
264
+ def get_selected_id(self, **kwargs) -> str | None:
216
265
  """
217
266
  Gets the ID of the selected option
218
267
 
219
268
  Returns:
220
269
  A string ID or None if there are no selectable options
221
270
  """
222
- def get_id(x: po.SelectParameterOption): return x._identifier
223
- return u.process_if_not_none(self.get_selected(), get_id)
271
+ def get_id(x: _po.SelectParameterOption):
272
+ return x._identifier
273
+ return _u.process_if_not_none(self.get_selected(), get_id)
224
274
 
225
- def get_selected_id_quoted(self, **kwargs) -> Optional[str]:
275
+ def get_selected_id_quoted(self, **kwargs) -> str | None:
226
276
  """
227
277
  Gets the ID of the selected option surrounded by single quotes
228
278
 
229
279
  Returns:
230
280
  A string or None if there are no selectable options
231
281
  """
232
- return u.process_if_not_none(self.get_selected_id(), self._enquote)
282
+ return _u.process_if_not_none(self.get_selected_id(), self._enquote)
233
283
 
234
- def get_selected_label(self, **kwargs) -> Optional[str]:
284
+ def get_selected_label(self, **kwargs) -> str | None:
235
285
  """
236
286
  Gets the label of the selected option
237
287
 
238
288
  Returns:
239
289
  A string or None if there are no selectable options
240
290
  """
241
- def get_label(x: po.SelectParameterOption): return x._label
242
- return u.process_if_not_none(self.get_selected(), get_label)
291
+ def get_label(x: _po.SelectParameterOption): return x._label
292
+ return _u.process_if_not_none(self.get_selected(), get_label)
243
293
 
244
- def get_selected_label_quoted(self, **kwargs) -> Optional[str]:
294
+ def get_selected_label_quoted(self, **kwargs) -> str | None:
245
295
  """
246
296
  Gets the label of the selected option surrounded by single quotes
247
297
 
248
298
  Returns:
249
299
  A string or None if there are no selectable options
250
300
  """
251
- return u.process_if_not_none(self.get_selected_label(), self._enquote)
301
+ return _u.process_if_not_none(self.get_selected_label(), self._enquote)
252
302
 
253
303
  def _get_selected_ids_as_list(self) -> Sequence[str]:
254
304
  selected_id = self.get_selected_id()
255
305
  if selected_id is not None:
256
- return (self.get_selected_id(),)
306
+ return (selected_id,)
257
307
  else:
258
308
  return tuple()
259
309
 
@@ -269,7 +319,7 @@ class SingleSelectParameter(_SelectionParameter):
269
319
  return output
270
320
 
271
321
  def _get_response_model0(self):
272
- return arm.SingleSelectParameterModel
322
+ return arm.SingleSelectParameterModel if self.is_enabled() else arm.NoneParameterModel
273
323
 
274
324
 
275
325
  @dataclass
@@ -282,7 +332,7 @@ class MultiSelectParameter(_SelectionParameter):
282
332
  options: The parameter options that are currently selectable
283
333
  selected_ids: A sequence of IDs of the selected options
284
334
  """
285
- _config: pc.MultiSelectParameterConfig
335
+ _config: _pc.MultiSelectParameterConfig
286
336
  _selected_ids: Sequence[str]
287
337
 
288
338
  def __post_init__(self):
@@ -293,18 +343,18 @@ class MultiSelectParameter(_SelectionParameter):
293
343
 
294
344
  @staticmethod
295
345
  def _ParameterConfigType():
296
- return pc.MultiSelectParameterConfig
346
+ return _pc.MultiSelectParameterConfig
297
347
 
298
348
  @classmethod
299
349
  def CreateWithOptions(
300
- cls, name: str, label: str, all_options: Sequence[Union[po.SelectParameterOption, dict]], *, description: str = "",
350
+ cls, name: str, label: str, all_options: Sequence[_po.SelectParameterOption | dict], *, description: str = "",
301
351
  show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
302
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
352
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
303
353
  ) -> None:
304
354
  """
305
355
  Method for creating the configurations for a MultiSelectParameter that may include user attribute or parent
306
356
 
307
- Parameters:
357
+ Arguments:
308
358
  name: The name of the parameter
309
359
  label: The display label for the parameter
310
360
  all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
@@ -315,35 +365,34 @@ class MultiSelectParameter(_SelectionParameter):
315
365
  user_attribute: The user attribute that may cascade the options for this parameter. Default is None
316
366
  parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
317
367
  """
318
- param_config = pc.MultiSelectParameterConfig(
368
+ cls._CreateWithOptionsHelper(
319
369
  name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name,
320
370
  show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
321
371
  )
322
- ps.ParameterConfigsSetIO.obj.add(param_config)
323
372
 
324
373
  @classmethod
325
374
  def Create(
326
- cls, name: str, label: str, all_options: Sequence[Union[po.SelectParameterOption, dict]], *, description: str = "",
375
+ cls, name: str, label: str, all_options: Sequence[_po.SelectParameterOption | dict], *, description: str = "",
327
376
  show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
328
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
377
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
329
378
  ) -> None:
330
379
  """
331
380
  DEPRECATED. Use CreateWithOptions instead
332
381
  """
333
- cls.CreateWithOptions(
334
- name, label, all_options, description=description, show_select_all=show_select_all,
335
- order_matters=order_matters, none_is_all=none_is_all, user_attribute=user_attribute, parent_name=parent_name
382
+ cls._CreateWithOptionsHelper(
383
+ name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name,
384
+ show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
336
385
  )
337
386
 
338
387
  @classmethod
339
388
  def CreateSimple(
340
- cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, description: str = "",
389
+ cls, name: str, label: str, all_options: Sequence[_po.SelectParameterOption], *, description: str = "",
341
390
  show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True, **kwargs
342
391
  ) -> None:
343
392
  """
344
393
  Method for creating the configurations for a MultiSelectParameter that doesn't involve user attributes or parent parameters
345
394
 
346
- Parameters:
395
+ Arguments:
347
396
  name: The name of the parameter
348
397
  label: The display label for the parameter
349
398
  all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
@@ -359,14 +408,14 @@ class MultiSelectParameter(_SelectionParameter):
359
408
 
360
409
  @classmethod
361
410
  def CreateFromSource(
362
- cls, name: str, label: str, data_source: Union[d.SelectDataSource, dict], *, description: str = "",
411
+ cls, name: str, label: str, data_source: d.SelectDataSource | dict, *, description: str = "",
363
412
  show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
364
- user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
413
+ user_attribute: str | None = None, parent_name: str | None = None, **kwargs
365
414
  ) -> None:
366
415
  """
367
416
  Method for creating the configurations for a MultiSelectParameter that uses a SelectDataSource to receive the options
368
417
 
369
- Parameters:
418
+ Arguments:
370
419
  name: The name of the parameter
371
420
  label: The display label for the parameter
372
421
  data_source: The lookup table to use for this parameter
@@ -380,11 +429,10 @@ class MultiSelectParameter(_SelectionParameter):
380
429
  extra_args = {
381
430
  "show_select_all": show_select_all, "order_matters": order_matters, "none_is_all": none_is_all
382
431
  }
383
- param_config = pc.DataSourceParameterConfig(
384
- pc.MultiSelectParameterConfig, name, label, data_source, extra_args=extra_args, description=description,
432
+ cls._CreateFromSourceHelper(
433
+ name, label, data_source, extra_args=extra_args, description=description,
385
434
  user_attribute=user_attribute, parent_name=parent_name
386
435
  )
387
- ps.ParameterConfigsSetIO.obj.add(param_config)
388
436
 
389
437
  def has_non_empty_selection(self) -> bool:
390
438
  """
@@ -399,12 +447,12 @@ class MultiSelectParameter(_SelectionParameter):
399
447
  return len(self._selected_ids) > 0
400
448
 
401
449
  def get_selected_list(
402
- self, field: Optional[str] = None, *, default_field: Optional[str] = None, default: Any = None, **kwargs
403
- ) -> Sequence[Union[po.SelectParameterOption, Any]]:
450
+ self, field: str | None = None, *, default_field: str | None = None, default: Any = None, **kwargs
451
+ ) -> Sequence[_po.SelectParameterOption | Any]:
404
452
  """
405
453
  Gets the sequence of the selected option(s) or a sequence of selected custom fields
406
454
 
407
- Parameters:
455
+ Arguments:
408
456
  field: If field is not None, the method gets this field from the "custom_fields" attribute of the selected options.
409
457
  Otherwise, returns the class objects of the selected options
410
458
  default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
@@ -424,6 +472,70 @@ class MultiSelectParameter(_SelectionParameter):
424
472
  selected_list = [selected.get_custom_field(field, default_field=default_field, default=default) for selected in selected_list]
425
473
 
426
474
  return tuple(selected_list)
475
+
476
+ def _get_selected_list_of_strings(
477
+ self, method: str, field: str, default_field: str | None, default: str | None, **kwargs
478
+ ) -> list[str]:
479
+ selected_list = self.get_selected_list(field, default_field=default_field, default=default)
480
+ list_of_strings: list[str] = []
481
+ for selected in selected_list:
482
+ if not isinstance(selected, str):
483
+ raise _u.ConfigurationError(
484
+ f"Method '{method}' can only be used on fields with only string values"
485
+ )
486
+ list_of_strings.append(selected)
487
+ return list_of_strings
488
+
489
+ def get_selected_list_joined(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str:
490
+ """
491
+ Gets the selected custom fields joined by comma
492
+
493
+ Arguments:
494
+ field: The "custom_fields" attribute of the selected options.
495
+ default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
496
+ as the "field" instead.
497
+ default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
498
+ is returned as the selected field. Does nothing if default_field is not None
499
+
500
+ Returns:
501
+ A string
502
+ """
503
+ list_of_strings = self._get_selected_list_of_strings("get_selected_list_joined", field, default_field, default)
504
+ return ','.join(list_of_strings)
505
+
506
+ def get_selected_list_quoted(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> tuple[str, ...]:
507
+ """
508
+ Gets the selected custom fields surrounded by single quotes
509
+
510
+ Arguments:
511
+ field: The "custom_fields" attribute of the selected options.
512
+ default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
513
+ as the "field" instead.
514
+ default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
515
+ is returned as the selected field. Does nothing if default_field is not None
516
+
517
+ Returns:
518
+ A tuple of strings
519
+ """
520
+ list_of_strings = self._get_selected_list_of_strings("get_selected_list_quoted", field, default_field, default)
521
+ return tuple(self._enquote(x) for x in list_of_strings)
522
+
523
+ def get_selected_list_quoted_joined(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str:
524
+ """
525
+ Gets the selected custom fields surrounded by single quotes and joined by comma
526
+
527
+ Arguments:
528
+ field: The "custom_fields" attribute of the selected options.
529
+ default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
530
+ as the "field" instead.
531
+ default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
532
+ is returned as the selected field. Does nothing if default_field is not None
533
+
534
+ Returns:
535
+ A string
536
+ """
537
+ list_of_strings = self._get_selected_list_of_strings("get_selected_list_quoted_joined", field, default_field, default)
538
+ return ','.join(self._enquote(x) for x in list_of_strings)
427
539
 
428
540
  def get_selected_ids_as_list(self, **kwargs) -> Sequence[str]:
429
541
  """
@@ -514,11 +626,29 @@ class MultiSelectParameter(_SelectionParameter):
514
626
  return output
515
627
 
516
628
  def _get_response_model0(self):
517
- return arm.MultiSelectParameterModel
629
+ return arm.MultiSelectParameterModel if self.is_enabled() else arm.NoneParameterModel
630
+
631
+
632
+ @dataclass
633
+ class _DateTypeParameter(Parameter):
634
+ _curr_option: _po._DateTypeParameterOption | None
635
+
636
+ def is_enabled(self) -> bool:
637
+ return self._curr_option is not None
638
+
639
+ def _cast_optional_date_to_str(self, date: date | None) -> str | None:
640
+ return None if date is None else date.strftime("%Y-%m-%d")
641
+
642
+ def _to_json_dict0(self):
643
+ output = super()._to_json_dict0()
644
+ if self._curr_option is not None:
645
+ output["min_date"] = self._cast_optional_date_to_str(self._curr_option._min_date)
646
+ output["max_date"] = self._cast_optional_date_to_str(self._curr_option._max_date)
647
+ return output
518
648
 
519
649
 
520
650
  @dataclass
521
- class DateParameter(Parameter):
651
+ class DateParameter(_DateTypeParameter):
522
652
  """
523
653
  Class for date parameter widgets.
524
654
 
@@ -527,56 +657,58 @@ class DateParameter(Parameter):
527
657
  curr_option: The current option showing for defaults based on user attribute and selection of parent
528
658
  selected_date: The selected date
529
659
  """
530
- _config: pc.DateParameterConfig
531
- _curr_option: Optional[po.DateParameterOption]
532
- _selected_date: Union[date, str]
660
+ _config: _pc.DateParameterConfig
661
+ _curr_option: _po.DateParameterOption | None
662
+ _selected_date: date | str | None
533
663
 
534
664
  def __post_init__(self):
535
- self._selected_date: date = self._validate_date(self._selected_date)
665
+ if self._curr_option is not None and self._selected_date is not None:
666
+ self._selected_date = self._validate_input_date(self._selected_date, self._curr_option)
536
667
 
537
668
  def is_enabled(self) -> bool:
538
669
  return self._curr_option is not None
539
670
 
540
671
  @staticmethod
541
672
  def _ParameterConfigType():
542
- return pc.DateParameterConfig
673
+ return _pc.DateParameterConfig
543
674
 
544
675
  @classmethod
545
676
  def CreateSimple(
546
- cls, name: str, label: str, default_date: Union[str, date], *, description: str = "",
547
- date_format: str = '%Y-%m-%d', **kwargs
677
+ cls, name: str, label: str, default_date: str | date, *, description: str = "",
678
+ min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d', **kwargs
548
679
  ) -> None:
549
680
  """
550
681
  Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
551
682
 
552
- Parameters:
683
+ Arguments:
553
684
  name: The name of the parameter
554
685
  label: The display label for the parameter
555
686
  default_date: Default date for this option
556
687
  description: Explains the meaning of the parameter
557
688
  date_format: Format of the default date, default is '%Y-%m-%d'
558
689
  """
559
- single_param_option = po.DateParameterOption(default_date, date_format=date_format)
690
+ single_param_option = _po.DateParameterOption(default_date, min_date=min_date, max_date=max_date, date_format=date_format)
560
691
  cls.CreateWithOptions(name, label, (single_param_option,), description=description)
561
692
 
562
- def get_selected_date(self, *, date_format: str = None, **kwargs) -> str:
693
+ def get_selected_date(self, *, date_format: str | None = None, **kwargs) -> str:
563
694
  """
564
695
  Gets selected date as string
565
696
 
566
- Parameters:
697
+ Arguments:
567
698
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
568
699
 
569
700
  Returns:
570
701
  A string
571
702
  """
703
+ assert self._curr_option is not None and isinstance(self._selected_date, date), "Parameter is not enabled"
572
704
  date_format = self._curr_option._date_format if date_format is None else date_format
573
705
  return self._selected_date.strftime(date_format)
574
706
 
575
- def get_selected_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
707
+ def get_selected_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
576
708
  """
577
709
  Gets selected date as string surrounded by single quotes
578
710
 
579
- Parameters:
711
+ Arguments:
580
712
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
581
713
 
582
714
  Returns:
@@ -601,11 +733,11 @@ class DateParameter(Parameter):
601
733
  return output
602
734
 
603
735
  def _get_response_model0(self):
604
- return arm.DateParameterModel if self.is_enabled() else arm.ParameterModelBase
736
+ return arm.DateParameterModel if self.is_enabled() else arm.NoneParameterModel
605
737
 
606
738
 
607
739
  @dataclass
608
- class DateRangeParameter(Parameter):
740
+ class DateRangeParameter(_DateTypeParameter):
609
741
  """
610
742
  Class for date range parameter widgets.
611
743
 
@@ -615,31 +747,35 @@ class DateRangeParameter(Parameter):
615
747
  selected_start_date: The selected start date
616
748
  selected_end_date: The selected end date
617
749
  """
618
- _config: pc.DateRangeParameterConfig
619
- _curr_option: Optional[po.DateRangeParameterOption]
620
- _selected_start_date: Union[date, str]
621
- _selected_end_date: Union[date, str]
750
+ _config: _pc.DateRangeParameterConfig
751
+ _curr_option: _po.DateRangeParameterOption | None
752
+ _selected_start_date: date | str | None
753
+ _selected_end_date: date | str | None
622
754
 
623
755
  def __post_init__(self):
624
- self._selected_start_date: date = self._validate_date(self._selected_start_date)
625
- self._selected_end_date: date = self._validate_date(self._selected_end_date)
756
+ if self._curr_option is not None:
757
+ if self._selected_start_date is not None:
758
+ self._selected_start_date = self._validate_input_date(self._selected_start_date, self._curr_option)
759
+ if self._selected_end_date is not None:
760
+ self._selected_end_date = self._validate_input_date(self._selected_end_date, self._curr_option)
626
761
 
627
762
  def is_enabled(self) -> bool:
628
763
  return self._curr_option is not None
629
764
 
630
765
  @staticmethod
631
766
  def _ParameterConfigType():
632
- return pc.DateRangeParameterConfig
767
+ return _pc.DateRangeParameterConfig
633
768
 
634
769
  @classmethod
635
770
  def CreateSimple(
636
- cls, name: str, label: str, default_start_date: Union[str, date], default_end_date: Union[str, date], *,
637
- description: str = "", date_format: str = '%Y-%m-%d', **kwargs
771
+ cls, name: str, label: str, default_start_date: str | date, default_end_date: str | date, *,
772
+ description: str = "", min_date: str | date | None = None, max_date: str | date | None = None,
773
+ date_format: str = '%Y-%m-%d', **kwargs
638
774
  ) -> None:
639
775
  """
640
776
  Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
641
777
 
642
- Parameters:
778
+ Arguments:
643
779
  name: The name of the parameter
644
780
  label: The display label for the parameter
645
781
  default_start_date: Default start date for this option
@@ -647,27 +783,30 @@ class DateRangeParameter(Parameter):
647
783
  description: Explains the meaning of the parameter
648
784
  date_format: Format of the default date, default is '%Y-%m-%d'
649
785
  """
650
- single_param_option = po.DateRangeParameterOption(default_start_date, default_end_date, date_format=date_format)
786
+ single_param_option = _po.DateRangeParameterOption(
787
+ default_start_date, default_end_date, min_date=min_date, max_date=max_date, date_format=date_format
788
+ )
651
789
  cls.CreateWithOptions(name, label, (single_param_option,), description=description)
652
790
 
653
- def get_selected_start_date(self, *, date_format: str = None, **kwargs) -> str:
791
+ def get_selected_start_date(self, *, date_format: str | None = None, **kwargs) -> str:
654
792
  """
655
793
  Gets selected start date as string
656
794
 
657
- Parameters:
795
+ Arguments:
658
796
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
659
797
 
660
798
  Returns:
661
799
  A string
662
800
  """
801
+ assert self._curr_option is not None and isinstance(self._selected_start_date, date), "Parameter is not enabled"
663
802
  date_format = self._curr_option._date_format if date_format is None else date_format
664
803
  return self._selected_start_date.strftime(date_format)
665
804
 
666
- def get_selected_start_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
805
+ def get_selected_start_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
667
806
  """
668
807
  Gets selected start date as string surrounded by single quotes
669
808
 
670
- Parameters:
809
+ Arguments:
671
810
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
672
811
 
673
812
  Returns:
@@ -675,24 +814,25 @@ class DateRangeParameter(Parameter):
675
814
  """
676
815
  return self._enquote(self.get_selected_start_date(date_format=date_format))
677
816
 
678
- def get_selected_end_date(self, *, date_format: str = None, **kwargs) -> str:
817
+ def get_selected_end_date(self, *, date_format: str | None = None, **kwargs) -> str:
679
818
  """
680
819
  Gets selected end date as string
681
820
 
682
- Parameters:
821
+ Arguments:
683
822
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
684
823
 
685
824
  Returns:
686
825
  A string
687
826
  """
827
+ assert self._curr_option is not None and isinstance(self._selected_end_date, date), "Parameter is not enabled"
688
828
  date_format = self._curr_option._date_format if date_format is None else date_format
689
829
  return self._selected_end_date.strftime(date_format)
690
830
 
691
- def get_selected_end_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
831
+ def get_selected_end_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
692
832
  """
693
833
  Gets selected end date as string surrounded by single quotes
694
834
 
695
- Parameters:
835
+ Arguments:
696
836
  date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
697
837
 
698
838
  Returns:
@@ -716,11 +856,27 @@ class DateRangeParameter(Parameter):
716
856
  return output
717
857
 
718
858
  def _get_response_model0(self):
719
- return arm.DateRangeParameterModel if self.is_enabled() else arm.ParameterModelBase
859
+ return arm.DateRangeParameterModel if self.is_enabled() else arm.NoneParameterModel
720
860
 
721
861
 
722
862
  @dataclass
723
- class NumberParameter(Parameter):
863
+ class _NumberTypeParameter(Parameter):
864
+ _curr_option: _po._NumericParameterOption | None
865
+
866
+ def is_enabled(self) -> bool:
867
+ return self._curr_option is not None
868
+
869
+ def _to_json_dict0(self):
870
+ output = super()._to_json_dict0()
871
+ if self._curr_option is not None:
872
+ output["min_value"] = float(self._curr_option._min_value)
873
+ output["max_value"] = float(self._curr_option._max_value)
874
+ output["increment"] = float(self._curr_option._increment)
875
+ return output
876
+
877
+
878
+ @dataclass
879
+ class NumberParameter(_NumberTypeParameter):
724
880
  """
725
881
  Class for number parameter widgets.
726
882
 
@@ -729,31 +885,29 @@ class NumberParameter(Parameter):
729
885
  curr_option: The current option showing for defaults based on user attribute and selection of parent
730
886
  selected_value: The selected integer or decimal number
731
887
  """
732
- _config: pc.NumberParameterConfig
733
- _curr_option: Optional[po.NumberParameterOption]
734
- _selected_value: po.Number
888
+ _config: _pc.NumberParameterConfig
889
+ _curr_option: _po.NumberParameterOption | None
890
+ _selected_value: _po.Number | None
735
891
 
736
892
  def __post_init__(self):
737
- self._selected_value: Decimal = self._validate_number(self._selected_value, self._curr_option)
738
-
739
- def is_enabled(self) -> bool:
740
- return self._curr_option is not None
893
+ if self._curr_option is not None and self._selected_value is not None:
894
+ self._selected_value = self._validate_number(self._selected_value, self._curr_option)
741
895
 
742
896
  @staticmethod
743
897
  def _ParameterConfigType():
744
- return pc.NumberParameterConfig
898
+ return _pc.NumberParameterConfig
745
899
 
746
900
  @classmethod
747
901
  def CreateSimple(
748
- cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
749
- increment: po.Number = 1, default_value: Optional[po.Number] = None, **kwargs
902
+ cls, name: str, label: str, min_value: _po.Number, max_value: _po.Number, *, description: str = "",
903
+ increment: _po.Number = 1, default_value: _po.Number | None = None, **kwargs
750
904
  ) -> None:
751
905
  """
752
906
  Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
753
907
 
754
908
  * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
755
909
 
756
- Parameters:
910
+ Arguments:
757
911
  name: The name of the parameter
758
912
  label: The display label for the parameter
759
913
  min_value: Minimum selectable value
@@ -762,7 +916,7 @@ class NumberParameter(Parameter):
762
916
  increment: Increment of selectable values, and must fit evenly between min_value and max_value
763
917
  default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
764
918
  """
765
- single_param_option = po.NumberParameterOption(min_value, max_value, increment=increment, default_value=default_value)
919
+ single_param_option = _po.NumberParameterOption(min_value, max_value, increment=increment, default_value=default_value)
766
920
  cls.CreateWithOptions(name, label, (single_param_option,), description=description)
767
921
 
768
922
  def get_selected_value(self, **kwargs) -> float:
@@ -772,6 +926,7 @@ class NumberParameter(Parameter):
772
926
  Returns:
773
927
  float
774
928
  """
929
+ assert self._selected_value is not None, "Parameter is not enabled"
775
930
  return float(self._selected_value)
776
931
 
777
932
  def _to_json_dict0(self):
@@ -783,16 +938,15 @@ class NumberParameter(Parameter):
783
938
  """
784
939
  output = super()._to_json_dict0()
785
940
  if self.is_enabled():
786
- output.update(self._curr_option._to_json_dict())
787
941
  output["selected_value"] = self.get_selected_value()
788
942
  return output
789
943
 
790
944
  def _get_response_model0(self):
791
- return arm.NumberParameterModel if self.is_enabled() else arm.ParameterModelBase
945
+ return arm.NumberParameterModel if self.is_enabled() else arm.NoneParameterModel
792
946
 
793
947
 
794
948
  @dataclass
795
- class NumberRangeParameter(Parameter):
949
+ class NumberRangeParameter(_NumberTypeParameter):
796
950
  """
797
951
  Class for number range parameter widgets.
798
952
 
@@ -802,26 +956,26 @@ class NumberRangeParameter(Parameter):
802
956
  selected_lower_value: The selected lower integer or decimal number
803
957
  selected_upper_value: The selected upper integer or decimal number
804
958
  """
805
- _config: pc.NumberRangeParameterConfig
806
- _curr_option: Optional[po.NumberRangeParameterOption]
807
- _selected_lower_value: po.Number
808
- _selected_upper_value: po.Number
959
+ _config: _pc.NumberRangeParameterConfig
960
+ _curr_option: _po.NumberRangeParameterOption | None
961
+ _selected_lower_value: _po.Number | None
962
+ _selected_upper_value: _po.Number | None
809
963
 
810
964
  def __post_init__(self):
811
- self._selected_lower_value: Decimal = self._validate_number(self._selected_lower_value, self._curr_option)
812
- self._selected_upper_value: Decimal = self._validate_number(self._selected_upper_value, self._curr_option)
813
-
814
- def is_enabled(self) -> bool:
815
- return self._curr_option is not None
965
+ if self._curr_option is not None:
966
+ if self._selected_lower_value is not None:
967
+ self._selected_lower_value = self._validate_number(self._selected_lower_value, self._curr_option)
968
+ if self._selected_upper_value is not None:
969
+ self._selected_upper_value = self._validate_number(self._selected_upper_value, self._curr_option)
816
970
 
817
971
  @staticmethod
818
972
  def _ParameterConfigType():
819
- return pc.NumberRangeParameterConfig
973
+ return _pc.NumberRangeParameterConfig
820
974
 
821
975
  @classmethod
822
976
  def CreateSimple(
823
- cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
824
- increment: po.Number = 1, default_lower_value: Optional[po.Number] = None, default_upper_value: Optional[po.Number] = None,
977
+ cls, name: str, label: str, min_value: _po.Number, max_value: _po.Number, *, description: str = "",
978
+ increment: _po.Number = 1, default_lower_value: _po.Number | None = None, default_upper_value: _po.Number | None = None,
825
979
  **kwargs
826
980
  ) -> None:
827
981
  """
@@ -829,7 +983,7 @@ class NumberRangeParameter(Parameter):
829
983
 
830
984
  * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
831
985
 
832
- Parameters:
986
+ Arguments:
833
987
  name: The name of the parameter
834
988
  label: The display label for the parameter
835
989
  min_value: Minimum selectable value
@@ -840,7 +994,7 @@ class NumberRangeParameter(Parameter):
840
994
  default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
841
995
  Must also be greater than default_lower_value
842
996
  """
843
- single_param_option = po.NumberRangeParameterOption(
997
+ single_param_option = _po.NumberRangeParameterOption(
844
998
  min_value, max_value, increment=increment, default_lower_value=default_lower_value, default_upper_value=default_upper_value
845
999
  )
846
1000
  cls.CreateWithOptions(name, label, (single_param_option,), description=description)
@@ -852,6 +1006,7 @@ class NumberRangeParameter(Parameter):
852
1006
  Returns:
853
1007
  float
854
1008
  """
1009
+ assert self._selected_lower_value is not None, "Parameter is not enabled"
855
1010
  return float(self._selected_lower_value)
856
1011
 
857
1012
  def get_selected_upper_value(self, **kwargs) -> float:
@@ -861,6 +1016,7 @@ class NumberRangeParameter(Parameter):
861
1016
  Returns:
862
1017
  float
863
1018
  """
1019
+ assert self._selected_upper_value is not None, "Parameter is not enabled"
864
1020
  return float(self._selected_upper_value)
865
1021
 
866
1022
  def _to_json_dict0(self):
@@ -871,14 +1027,13 @@ class NumberRangeParameter(Parameter):
871
1027
  A dictionary for the JSON object
872
1028
  """
873
1029
  output = super()._to_json_dict0()
874
- if self._curr_option is not None:
875
- output.update(self._curr_option._to_json_dict())
1030
+ if self.is_enabled():
876
1031
  output['selected_lower_value'] = self.get_selected_lower_value()
877
1032
  output['selected_upper_value'] = self.get_selected_upper_value()
878
1033
  return output
879
1034
 
880
1035
  def _get_response_model0(self):
881
- return arm.NumberRangeParameterModel if self.is_enabled() else arm.ParameterModelBase
1036
+ return arm.NumberRangeParameterModel if self.is_enabled() else arm.NoneParameterModel
882
1037
 
883
1038
 
884
1039
  @dataclass
@@ -886,7 +1041,7 @@ class TextValue:
886
1041
  _value_do_not_touch: str
887
1042
 
888
1043
  def __repr__(self):
889
- raise u.ConfigurationError(
1044
+ raise _u.ConfigurationError(
890
1045
  "Cannot convert TextValue directly to string (to avoid SQL injection). Try using it through placeholders instead"
891
1046
  )
892
1047
 
@@ -896,7 +1051,7 @@ class TextValue:
896
1051
 
897
1052
  This method returns a new object and leaves the original the same.
898
1053
 
899
- Parameters:
1054
+ Arguments:
900
1055
  str_to_str_function: A function that accepts a string and returns a string
901
1056
 
902
1057
  Returns:
@@ -904,7 +1059,7 @@ class TextValue:
904
1059
  """
905
1060
  new_value = str_to_str_function(self._value_do_not_touch)
906
1061
  if not isinstance(new_value, str):
907
- raise u.ConfigurationError("Function provided must return string")
1062
+ raise _u.ConfigurationError("Function provided must return string")
908
1063
  return TextValue(new_value)
909
1064
 
910
1065
  def apply_percent_wrap(self) -> TextValue:
@@ -920,7 +1075,7 @@ class TextValue:
920
1075
  """
921
1076
  Transforms the entered text with a function that takes a string and returns a boolean.
922
1077
 
923
- Parameters:
1078
+ Arguments:
924
1079
  str_to_bool_function: A function that accepts a string and returns a boolean.
925
1080
 
926
1081
  Returns:
@@ -928,14 +1083,14 @@ class TextValue:
928
1083
  """
929
1084
  new_value = str_to_bool_function(self._value_do_not_touch)
930
1085
  if not isinstance(new_value, bool):
931
- raise u.ConfigurationError("Function provided must return bool")
1086
+ raise _u.ConfigurationError("Function provided must return bool")
932
1087
  return new_value
933
1088
 
934
- def apply_as_number(self, str_to_num_function: Callable[[str], Union[int, float]]) -> Union[int, float]:
1089
+ def apply_as_number(self, str_to_num_function: Callable[[str], IntOrFloat]) -> IntOrFloat:
935
1090
  """
936
1091
  Transforms the entered text with a function that takes a string and returns an int or float.
937
1092
 
938
- Parameters:
1093
+ Arguments:
939
1094
  str_to_num_function: A function that accepts a string and returns an int or float.
940
1095
 
941
1096
  Returns:
@@ -943,14 +1098,14 @@ class TextValue:
943
1098
  """
944
1099
  new_value = str_to_num_function(self._value_do_not_touch)
945
1100
  if not isinstance(new_value, (int, float)):
946
- raise u.ConfigurationError("Function provided must return a number")
1101
+ raise _u.ConfigurationError("Function provided must return a number")
947
1102
  return new_value
948
1103
 
949
1104
  def apply_as_datetime(self, str_to_datetime_function: Callable[[str], datetime]) -> datetime:
950
1105
  """
951
1106
  Transforms the entered text with a function that takes a string and returns a datetime object.
952
1107
 
953
- Parameters:
1108
+ Arguments:
954
1109
  str_to_datetime_function: A function that accepts a string and returns a datetime object.
955
1110
 
956
1111
  Returns:
@@ -958,7 +1113,7 @@ class TextValue:
958
1113
  """
959
1114
  new_value = str_to_datetime_function(self._value_do_not_touch)
960
1115
  if not isinstance(new_value, datetime):
961
- raise u.ConfigurationError("Function provided must return datetime")
1116
+ raise _u.ConfigurationError("Function provided must return datetime")
962
1117
  return new_value
963
1118
 
964
1119
 
@@ -967,33 +1122,33 @@ class TextParameter(Parameter):
967
1122
  """
968
1123
  Class for text parameter widgets.
969
1124
  """
970
- _config: pc.TextParameterConfig
971
- _curr_option: Optional[po.TextParameterOption]
972
- _entered_text: str
1125
+ _config: _pc.TextParameterConfig
1126
+ _curr_option: _po.TextParameterOption | None
1127
+ _entered_text: str | None
973
1128
 
974
1129
  def __post_init__(self):
975
- try:
976
- if self.is_enabled():
1130
+ if self.is_enabled() and isinstance(self._entered_text, str):
1131
+ try:
977
1132
  self._entered_text = self._config.validate_entered_text(self._entered_text)
978
- except u.ConfigurationError as e:
979
- self._config._raise_invalid_input_error(self._entered_text, str(e), e)
1133
+ except _u.ConfigurationError as e:
1134
+ raise self._config._invalid_input_error(self._entered_text, str(e))
980
1135
 
981
1136
  def is_enabled(self) -> bool:
982
1137
  return self._curr_option is not None
983
-
1138
+
984
1139
  @staticmethod
985
1140
  def _ParameterConfigType():
986
- return pc.TextParameterConfig
1141
+ return _pc.TextParameterConfig
987
1142
 
988
1143
  @classmethod
989
1144
  def CreateWithOptions(
990
- cls, name: str, label: str, all_options: Sequence[Union[po.TextParameterOption, dict]], *, description: str = "",
991
- input_type: str = "text", user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
1145
+ cls, name: str, label: str, all_options: Sequence[_po.TextParameterOption | dict], *, description: str = "",
1146
+ input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None, **kwargs
992
1147
  ) -> None:
993
1148
  """
994
1149
  Method for creating the configurations for a MultiSelectParameter that may include user attribute or parent
995
1150
 
996
- Parameters:
1151
+ Arguments:
997
1152
  name: The name of the parameter
998
1153
  label: The display label for the parameter
999
1154
  all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
@@ -1002,21 +1157,19 @@ class TextParameter(Parameter):
1002
1157
  user_attribute: The user attribute that may cascade the options for this parameter. Default is None
1003
1158
  parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
1004
1159
  """
1005
- param_config = pc.TextParameterConfig(
1006
- name, label, all_options, description=description, input_type=input_type, user_attribute=user_attribute,
1007
- parent_name=parent_name
1160
+ cls._CreateWithOptionsHelper(
1161
+ name, label, all_options, description=description, input_type=input_type, user_attribute=user_attribute, parent_name=parent_name
1008
1162
  )
1009
- ps.ParameterConfigsSetIO.obj.add(param_config)
1010
1163
 
1011
1164
  @classmethod
1012
1165
  def Create(
1013
- cls, name: str, label: str, all_options: Sequence[Union[po.SelectParameterOption, dict]], *, description: str = "",
1014
- input_type: str = "text", user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
1166
+ cls, name: str, label: str, all_options: Sequence[_po.TextParameterOption | dict], *, description: str = "",
1167
+ input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None, **kwargs
1015
1168
  ) -> None:
1016
1169
  """
1017
1170
  DEPRECATED. Use CreateWithOptions instead
1018
1171
  """
1019
- cls.CreateWithOptions(
1172
+ cls._CreateWithOptionsHelper(
1020
1173
  name, label, all_options, description=description, input_type=input_type, user_attribute=user_attribute, parent_name=parent_name
1021
1174
  )
1022
1175
 
@@ -1027,25 +1180,25 @@ class TextParameter(Parameter):
1027
1180
  """
1028
1181
  Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
1029
1182
 
1030
- Parameters:
1183
+ Arguments:
1031
1184
  name: The name of the parameter
1032
1185
  label: The display label for the parameter
1033
1186
  description: Explains the meaning of the parameter
1034
1187
  default_text: Default input text for this option. Optional, default is empty string.
1035
1188
  input_type: The type of input field to use. Must be one of "text", "textarea", "number", "color", "date", "datetime-local", "month", "time", and "password". Optional, default is "text". More information on input types other than "textarea" can be found at https://www.w3schools.com/html/html_form_input_types.asp. More information on "textarea" can be found at https://www.w3schools.com/tags/tag_textarea.asp
1036
1189
  """
1037
- single_param_option = po.TextParameterOption(default_text=default_text)
1190
+ single_param_option = _po.TextParameterOption(default_text=default_text)
1038
1191
  cls.CreateWithOptions(name, label, (single_param_option,), description=description, input_type=input_type)
1039
1192
 
1040
1193
  @classmethod
1041
1194
  def CreateFromSource(
1042
- cls, name: str, label: str, data_source: Union[d.TextDataSource, dict], *, description: str = "",
1043
- input_type: str = "text", user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
1195
+ cls, name: str, label: str, data_source: d.TextDataSource | dict, *, description: str = "",
1196
+ input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None, **kwargs
1044
1197
  ) -> None:
1045
1198
  """
1046
1199
  Method for creating the configurations for a MultiSelectParameter that uses a SelectDataSource to receive the options
1047
1200
 
1048
- Parameters:
1201
+ Arguments:
1049
1202
  name: The name of the parameter
1050
1203
  label: The display label for the parameter
1051
1204
  data_source: The lookup table to use for this parameter
@@ -1057,11 +1210,9 @@ class TextParameter(Parameter):
1057
1210
  extra_args = {
1058
1211
  "input_type": input_type
1059
1212
  }
1060
- param_config = pc.DataSourceParameterConfig(
1061
- pc.TextParameterConfig, name, label, data_source, extra_args=extra_args, description=description,
1062
- user_attribute=user_attribute, parent_name=parent_name
1213
+ cls._CreateFromSourceHelper(
1214
+ name, label, data_source, extra_args=extra_args, description=description, user_attribute=user_attribute, parent_name=parent_name
1063
1215
  )
1064
- ps.ParameterConfigsSetIO.obj.add(param_config)
1065
1216
 
1066
1217
  def get_entered_text(self, **kwargs) -> TextValue:
1067
1218
  """
@@ -1070,6 +1221,7 @@ class TextParameter(Parameter):
1070
1221
  Returns:
1071
1222
  A TextValue object
1072
1223
  """
1224
+ assert isinstance(self._entered_text, str), "Parameter is not enabled"
1073
1225
  return TextValue(self._entered_text)
1074
1226
 
1075
1227
  def get_entered_int(self, **kwargs) -> int:
@@ -1079,7 +1231,7 @@ class TextParameter(Parameter):
1079
1231
  Returns: int
1080
1232
  """
1081
1233
  if self._config.input_type != "number":
1082
- raise u.ConfigurationError("Method 'get_entered_int' requires TextParameter to have input type 'number'")
1234
+ raise _u.ConfigurationError("Method 'get_entered_int' requires TextParameter to have input type 'number'")
1083
1235
  text = self.get_entered_text()
1084
1236
  return text.apply_as_number(int)
1085
1237
 
@@ -1091,7 +1243,7 @@ class TextParameter(Parameter):
1091
1243
  """
1092
1244
  applicable_input_types = ["date", "datetime-local", "month", "time"]
1093
1245
  if self._config.input_type not in applicable_input_types:
1094
- raise u.ConfigurationError(f"Method 'get_entered_datetime' requires TextParameter to have one of these input types: {applicable_input_types}")
1246
+ raise _u.ConfigurationError(f"Method 'get_entered_datetime' requires TextParameter to have one of these input types: {applicable_input_types}")
1095
1247
  text = self.get_entered_text()
1096
1248
 
1097
1249
  date_formats = { "date": "%Y-%m-%d", "datetime-local": "%Y-%m-%dT%H:%M", "month": "%Y-%m", "time": "%H:%M" }
@@ -1106,9 +1258,9 @@ class TextParameter(Parameter):
1106
1258
  """
1107
1259
  output = super()._to_json_dict0()
1108
1260
  output['input_type'] = self._config.input_type
1109
- if self._curr_option is not None:
1261
+ if self.is_enabled():
1110
1262
  output['entered_text'] = self._entered_text
1111
1263
  return output
1112
1264
 
1113
1265
  def _get_response_model0(self):
1114
- return arm.TextParameterModel if self.is_enabled() else arm.ParameterModelBase
1266
+ return arm.TextParameterModel if self.is_enabled() else arm.NoneParameterModel