squirrels 0.1.1.post1__py3-none-any.whl → 0.2.0.dev0__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 (74) hide show
  1. squirrels/__init__.py +10 -16
  2. squirrels/_api_server.py +234 -80
  3. squirrels/_authenticator.py +84 -0
  4. squirrels/_command_line.py +60 -72
  5. squirrels/_connection_set.py +96 -0
  6. squirrels/_constants.py +114 -33
  7. squirrels/_environcfg.py +77 -0
  8. squirrels/_initializer.py +126 -67
  9. squirrels/_manifest.py +195 -168
  10. squirrels/_models.py +495 -0
  11. squirrels/_package_loader.py +26 -0
  12. squirrels/_parameter_configs.py +401 -0
  13. squirrels/_parameter_sets.py +188 -0
  14. squirrels/_py_module.py +60 -0
  15. squirrels/_timer.py +36 -0
  16. squirrels/_utils.py +81 -49
  17. squirrels/_version.py +2 -2
  18. squirrels/arguments/init_time_args.py +32 -0
  19. squirrels/arguments/run_time_args.py +82 -0
  20. squirrels/data_sources.py +380 -155
  21. squirrels/dateutils.py +86 -57
  22. squirrels/package_data/base_project/Dockerfile +15 -0
  23. squirrels/package_data/base_project/connections.yml +7 -0
  24. squirrels/package_data/base_project/database/{sample_database.db → expenses.db} +0 -0
  25. squirrels/package_data/base_project/environcfg.yml +29 -0
  26. squirrels/package_data/base_project/ignores/.dockerignore +8 -0
  27. squirrels/package_data/base_project/ignores/.gitignore +7 -0
  28. squirrels/package_data/base_project/models/dbviews/database_view1.py +36 -0
  29. squirrels/package_data/base_project/models/dbviews/database_view1.sql +15 -0
  30. squirrels/package_data/base_project/models/federates/dataset_example.py +20 -0
  31. squirrels/package_data/base_project/models/federates/dataset_example.sql +3 -0
  32. squirrels/package_data/base_project/parameters.yml +109 -0
  33. squirrels/package_data/base_project/pyconfigs/auth.py +47 -0
  34. squirrels/package_data/base_project/pyconfigs/connections.py +28 -0
  35. squirrels/package_data/base_project/pyconfigs/context.py +45 -0
  36. squirrels/package_data/base_project/pyconfigs/parameters.py +55 -0
  37. squirrels/package_data/base_project/seeds/mocks/category.csv +3 -0
  38. squirrels/package_data/base_project/seeds/mocks/max_filter.csv +2 -0
  39. squirrels/package_data/base_project/seeds/mocks/subcategory.csv +6 -0
  40. squirrels/package_data/base_project/squirrels.yml.j2 +57 -0
  41. squirrels/package_data/base_project/tmp/.gitignore +2 -0
  42. squirrels/package_data/static/script.js +159 -63
  43. squirrels/package_data/static/style.css +79 -15
  44. squirrels/package_data/static/widgets.js +133 -0
  45. squirrels/package_data/templates/index.html +65 -23
  46. squirrels/package_data/templates/index2.html +22 -0
  47. squirrels/parameter_options.py +216 -119
  48. squirrels/parameters.py +407 -478
  49. squirrels/user_base.py +58 -0
  50. squirrels-0.2.0.dev0.dist-info/METADATA +126 -0
  51. squirrels-0.2.0.dev0.dist-info/RECORD +56 -0
  52. {squirrels-0.1.1.post1.dist-info → squirrels-0.2.0.dev0.dist-info}/WHEEL +1 -2
  53. squirrels-0.2.0.dev0.dist-info/entry_points.txt +3 -0
  54. squirrels/_credentials_manager.py +0 -87
  55. squirrels/_module_loader.py +0 -37
  56. squirrels/_parameter_set.py +0 -151
  57. squirrels/_renderer.py +0 -286
  58. squirrels/_timed_imports.py +0 -37
  59. squirrels/connection_set.py +0 -126
  60. squirrels/package_data/base_project/.gitignore +0 -4
  61. squirrels/package_data/base_project/connections.py +0 -20
  62. squirrels/package_data/base_project/datasets/sample_dataset/context.py +0 -22
  63. squirrels/package_data/base_project/datasets/sample_dataset/database_view1.py +0 -29
  64. squirrels/package_data/base_project/datasets/sample_dataset/database_view1.sql.j2 +0 -12
  65. squirrels/package_data/base_project/datasets/sample_dataset/final_view.py +0 -11
  66. squirrels/package_data/base_project/datasets/sample_dataset/final_view.sql.j2 +0 -3
  67. squirrels/package_data/base_project/datasets/sample_dataset/parameters.py +0 -47
  68. squirrels/package_data/base_project/datasets/sample_dataset/selections.cfg +0 -9
  69. squirrels/package_data/base_project/squirrels.yaml +0 -22
  70. squirrels-0.1.1.post1.dist-info/METADATA +0 -67
  71. squirrels-0.1.1.post1.dist-info/RECORD +0 -40
  72. squirrels-0.1.1.post1.dist-info/entry_points.txt +0 -2
  73. squirrels-0.1.1.post1.dist-info/top_level.txt +0 -1
  74. {squirrels-0.1.1.post1.dist-info → squirrels-0.2.0.dev0.dist-info}/LICENSE +0 -0
squirrels/parameters.py CHANGED
@@ -1,210 +1,164 @@
1
1
  from __future__ import annotations
2
- from typing import Type, Sequence, Dict, List, Any, Iterator, Optional, Union
2
+ from typing import Type, Sequence, Optional, Union, Any
3
3
  from dataclasses import dataclass
4
- from datetime import datetime
4
+ from datetime import datetime, date
5
5
  from decimal import Decimal
6
- import copy
6
+ from abc import ABCMeta, abstractmethod
7
7
 
8
- from squirrels import parameter_options as po, _utils as u
9
- from squirrels.data_sources import DataSource
10
- from squirrels._parameter_set import ParameterSetBase
11
- from squirrels._timed_imports import pandas as pd
8
+ from . import _parameter_configs as pc, _parameter_sets as ps, parameter_options as po, data_sources as d, _utils as u
12
9
 
13
10
 
14
11
  @dataclass
15
- class Parameter:
12
+ class Parameter(metaclass=ABCMeta):
16
13
  """
17
- Abstract class for all parameter classes. Useful for type hints.
14
+ Abstract class for all parameter widgets
18
15
  """
19
- widget_type: str
20
- name: str
21
- label: str
22
- all_options: Sequence[po.ParameterOption]
23
- is_hidden: bool
24
- parent: Optional[_SelectionParameter]
16
+ _config: pc.ParameterConfig
25
17
 
26
- def WithParent(all_options: Sequence[po.ParameterOption], parent: SingleSelectParameter, new_param: Parameter):
27
- """
28
- Helper class method to assign a SingleSelectParameter as the parent for another parameter
29
-
30
- Parameters:
31
- all_options: The list of options with one of "parent_option_id" or "parent_option_ids" attribute set.
32
- parent: The parent parameter. All option ids of the parent must exist at least once in "parent_option_ids" of all_options
33
- new_param: The child parameter to modify. Usually not a selection parameter
34
- """
35
- new_param._set_parent_and_options(parent, all_options)
36
- new_param.parent._add_child_mutate(new_param)
37
- return new_param.refresh(parent)
38
-
39
- def refresh(self, parent: Optional[_SelectionParameter] = None) -> Parameter:
18
+ @staticmethod
19
+ @abstractmethod
20
+ def _ParameterConfigType() -> Type:
21
+ pass
22
+
23
+ @classmethod
24
+ def Create(
25
+ cls, name: str, label: str, all_options: Sequence[Union[po.ParameterOption, dict]], *, is_hidden: bool = False,
26
+ user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
27
+ ) -> None:
40
28
  """
41
- Refreshes the selectable options (or change of default value) based on the selection of the parent parameter
29
+ Method for creating the configurations for a Parameter that may include user attribute or parent
42
30
 
43
31
  Parameters:
44
- parent: The parent parameter subscribed to for updates
45
-
46
- Returns:
47
- A copy of self for the new selectable options based on current selection of parent
32
+ name: The name of the parameter
33
+ label: The display label for the parameter
34
+ all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
35
+ is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
36
+ user_attribute: The user attribute that may cascade the options for this parameter. Default is None
37
+ parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
48
38
  """
49
- param_copy = copy.copy(self)
50
- if parent is not None:
51
- param_copy.parent = parent
52
- param_copy._refresh_mutate()
53
- return param_copy
39
+ param_config_type = cls._ParameterConfigType()
40
+ param_config = param_config_type(name, label, all_options, is_hidden=is_hidden, user_attribute=user_attribute,
41
+ parent_name=parent_name, **kwargs)
42
+ ps.ParameterConfigsSetIO.obj.add(param_config)
54
43
 
55
- def with_selection(self, _: str) -> Parameter:
56
- """
57
- Abstract method for applying the selection to the parameter
58
- """
59
- raise u.AbstractMethodCallError(self.__class__, "with_selection")
44
+ @classmethod
45
+ @abstractmethod
46
+ def CreateSimple(cls, name: str, label: str, *args, is_hidden: bool = False, **kwargs) -> None:
47
+ pass
60
48
 
61
- def get_all_dependent_params(self) -> ParameterSetBase:
49
+ @classmethod
50
+ def CreateFromSource(
51
+ cls, name: str, label: str, data_source: Union[d.DataSource , dict], *, is_hidden: bool = False,
52
+ user_attribute: Optional[str] = None, parent_name: Optional[str] = None, **kwargs
53
+ ) -> None:
62
54
  """
63
- Gets the collection of descendent parameters with changes applied based on the selection of this parameter
55
+ Method for creating the configurations for any Parameter that uses a DataSource to received the options
64
56
 
65
- Returns:
66
- A collection of descendent parameters as a ParameterSetBase
57
+ Parameters:
58
+ name: The name of the parameter
59
+ label: The display label for the parameter
60
+ data_source: The lookup table to use for this parameter
61
+ is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
62
+ user_attribute: The user attribute that may cascade the options for this parameter. Default is None
63
+ parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
67
64
  """
68
- dependent_params = ParameterSetBase()
69
- self._accum_all_dependent_params(dependent_params)
70
- return dependent_params
71
-
72
- def _set_default_as_selection_mutate(self) -> None:
73
- raise u.AbstractMethodCallError(self.__class__, "_set_default_as_selection_mutate")
74
-
75
- def _refresh_mutate(self) -> None:
76
- if self.parent is not None and hasattr(self, 'curr_option'):
77
- self.curr_option = next(self._get_valid_options_iterator())
78
- self._set_default_as_selection_mutate()
79
-
80
- def _get_valid_options_iterator(self) -> Iterator[po.ParameterOption]:
81
- selected_parent_option_ids = self.parent._get_selected_ids_as_list()
82
- return (x for x in self.all_options if x.is_valid(selected_parent_option_ids))
83
-
84
- def _raise_invalid_input_error(self, selection: str, more_details: str = '', e: Exception = None) -> None:
85
- raise u.InvalidInputError(f'Selected value "{selection}" is not valid for parameter "{self.name}". ' + more_details) from e
86
-
87
- def _verify_parent_is_single_select(self) -> None:
88
- if not isinstance(self.parent, SingleSelectParameter):
89
- raise u.ConfigurationError(f'For "{self.name}", it''s not a selection parameter, so its parent must be a SingleSelectParameter')
90
-
91
- def _verify_parent_options_have_one_child_each(self) -> None:
92
- accum_set = set()
93
- for option in self.all_options:
94
- if not accum_set.isdisjoint(option.parent_option_ids):
95
- raise u.ConfigurationError(f'For "{self.name}", it''s not a selection parameter, so no two options can share the same parent option')
96
- accum_set = accum_set.union(option.parent_option_ids)
97
- if len(accum_set) != len(self.parent.options):
98
- raise u.ConfigurationError(f'For "{self.name}", all parent option ids must exist across all options')
99
-
100
- def _set_parent_and_options(self, parent: SingleSelectParameter, all_options: Sequence[po.ParameterOption]) -> None:
101
- self.parent = parent
102
- self.all_options = all_options
103
- self._verify_parent_is_single_select()
104
- self._verify_parent_options_have_one_child_each()
105
-
106
- def _accum_all_dependent_params(self, param_set: ParameterSetBase) -> None:
107
- param_set.add_parameter(self)
65
+ param_config_type = cls._ParameterConfigType()
66
+ param_config = pc.DataSourceParameterConfig(param_config_type, name, label, data_source, is_hidden=is_hidden,
67
+ user_attribute=user_attribute, parent_name=parent_name)
68
+ ps.ParameterConfigsSetIO.obj.add(param_config)
108
69
 
109
70
  def _enquote(self, value: str) -> str:
110
71
  return "'" + value.replace("'", "''") + "'"
111
-
112
- def to_json_dict(self) -> Dict:
72
+
73
+ def _validate_date(self, input_date: str) -> date:
74
+ try:
75
+ return datetime.strptime(input_date.strip(), "%Y-%m-%d").date() if isinstance(input_date, str) else input_date
76
+ except ValueError as e:
77
+ self._config._raise_invalid_input_error(input_date, 'Invalid selection for date.', e)
78
+
79
+ def _validate_number(self, input_number: po.Number, curr_option: po._NumericParameterOption) -> Decimal:
80
+ try:
81
+ return curr_option._validate_value(input_number)
82
+ except u.ConfigurationError as e:
83
+ self._config._raise_invalid_input_error(input_number, 'Invalid selection for number.', e)
84
+
85
+ @abstractmethod
86
+ def to_json_dict0(self) -> dict:
113
87
  """
114
88
  Helper method to convert the derived Parameter class into a JSON dictionary
115
89
  """
116
- return {
117
- 'widget_type': self.widget_type,
118
- 'name': self.name,
119
- 'label': self.label
120
- }
90
+ return self._config.to_json_dict0()
121
91
 
122
92
 
123
93
  @dataclass
124
94
  class _SelectionParameter(Parameter):
125
- def __post_init__(self) -> None:
126
- self.trigger_refresh: bool = False
127
- self.options: Sequence[po.SelectParameterOption] = tuple(self.all_options)
128
- self.children: List[_SelectionParameter] = list()
129
- if self.parent is not None:
130
- self.parent._add_child_mutate(self)
131
- self._refresh_mutate()
132
-
133
- def _add_child_mutate(self, child: Parameter) -> None:
134
- self.children.append(child)
135
- self.trigger_refresh = True
136
-
137
- def _refresh_mutate(self) -> None:
138
- if self.parent is not None:
139
- self.options = tuple(self._get_valid_options_iterator())
140
- self._set_default_as_selection_mutate()
141
- self.children = [child.refresh(self) for child in self.children]
95
+ _config: pc.SelectionParameterConfig
96
+ _options: Sequence[po.SelectParameterOption]
97
+
98
+ def __post_init__(self):
99
+ self._options = tuple(self._options)
142
100
 
101
+ @abstractmethod
143
102
  def _get_selected_ids_as_list(self) -> Sequence[str]:
144
- raise u.AbstractMethodCallError(self.__class__, "_get_selected_ids_as_list")
103
+ pass
145
104
 
146
- def _get_default_iterator(self) -> Iterator[po.ParameterOption]:
147
- return (x.identifier for x in self.options if x.is_default)
105
+ def _validate_selected_id_in_options(self, selected_id):
106
+ if selected_id not in (x._identifier for x in self._options):
107
+ self._config._raise_invalid_input_error(selected_id)
148
108
 
149
- def _validate_selected_id_in_options(self, selected_id: str) -> str:
150
- if selected_id in (x.identifier for x in self.options):
151
- return selected_id
152
- else:
153
- self._raise_invalid_input_error(selected_id)
154
-
155
- def _accum_all_dependent_params(self, param_set: ParameterSetBase) -> None:
156
- super()._accum_all_dependent_params(param_set)
157
- for child in self.children:
158
- child._accum_all_dependent_params(param_set)
159
-
160
- def to_json_dict(self):
109
+ @abstractmethod
110
+ def to_json_dict0(self):
161
111
  """
162
112
  Helper method to convert the derived selection parameter class into a JSON object
163
113
  """
164
- output = super().to_json_dict()
165
- output['options'] = [x.to_dict() for x in self.options]
166
- output['trigger_refresh'] = self.trigger_refresh
114
+ output = super().to_json_dict0()
115
+ output['options'] = [x._to_json_dict() for x in self._options]
167
116
  return output
168
117
 
169
118
 
170
119
  @dataclass
171
120
  class SingleSelectParameter(_SelectionParameter):
172
121
  """
173
- Class to define attributes for single-select parameter widgets.
174
- """
175
- selected_id: Optional[str]
122
+ Class for single-select parameter widgets.
176
123
 
177
- def __init__(self, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *,
178
- is_hidden: bool = False, parent: Optional[_SelectionParameter] = None) -> None:
124
+ Attributes:
125
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
126
+ options: The parameter options that are currently selectable
127
+ selected_id: The ID of the selected option
128
+ """
129
+ _config: pc.SingleSelectParameterConfig
130
+ _selected_id: Optional[str]
131
+
132
+ def __post_init__(self):
133
+ super().__post_init__()
134
+ if len(self._options) > 0:
135
+ assert self._selected_id != None
136
+ self._validate_selected_id_in_options(self._selected_id)
137
+ else:
138
+ self._selected_id = None
139
+
140
+ @staticmethod
141
+ def _ParameterConfigType():
142
+ return pc.SingleSelectParameterConfig
143
+
144
+ @classmethod
145
+ def CreateSimple(
146
+ cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, is_hidden: bool = False, **kwargs
147
+ ) -> None:
179
148
  """
180
- Constructor for SingleSelectParameter class
149
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
181
150
 
182
151
  Parameters:
183
152
  name: The name of the parameter
184
153
  label: The display label for the parameter
185
- all_options: A sequence of SelectParameterOption which defines the attribute for each dropdown option
186
- is_hidden: Whether the parameter is hidden in the parameters API response. Default is False.
187
- parent: The parent parameter that may cascade the options for this parameter. Default is no parent
188
- """
189
- super().__init__("SingleSelectParameter", name, label, all_options, is_hidden, parent)
190
-
191
- def with_selection(self, selection: str) -> SingleSelectParameter:
154
+ all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
155
+ is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
192
156
  """
193
- Applies the selected value to this widget parameter
157
+ cls.Create(name, label, all_options, is_hidden=is_hidden)
194
158
 
195
- Parameters:
196
- selection: The selected value as an ID of one of the dropdown options
197
-
198
- Returns:
199
- A new copy of SingleSelectParameter with the selection applied
200
- """
201
- param_copy = copy.copy(self)
202
- param_copy.selected_id = self._validate_selected_id_in_options(selection)
203
- param_copy.children = [child.refresh(param_copy) for child in param_copy.children]
204
- return param_copy
205
-
206
- def get_selected(self, field: Optional[str] = None, *, default_field: Optional[str] = None,
207
- default: Any = None) -> Union[po.SelectParameterOption, str]:
159
+ def get_selected(
160
+ self, field: Optional[str] = None, *, default_field: Optional[str] = None, default: Any = None, **kwargs
161
+ ) -> Union[po.SelectParameterOption, Any, None]:
208
162
  """
209
163
  Gets the selected single-select option or selected custom field
210
164
 
@@ -219,115 +173,133 @@ class SingleSelectParameter(_SelectionParameter):
219
173
  Returns:
220
174
  A SelectParameterOption class object if no field is provided, or the type of the custom field
221
175
  """
222
- selected = next(x for x in self.options if x.identifier == self.selected_id)
223
- if field is not None:
224
- selected = selected.get_custom_field(field, default_field, default)
225
- return selected
176
+ def get_selected_from_id(identifier: str):
177
+ selected = next(x for x in self._options if x._identifier == identifier)
178
+ if field is not None:
179
+ selected = selected.get_custom_field(field, default_field=default_field, default=default)
180
+ return selected
181
+ return u.process_if_not_none(self._selected_id, get_selected_from_id)
226
182
 
227
- def get_selected_id(self) -> str:
183
+ def get_selected_id(self, **kwargs) -> Optional[str]:
228
184
  """
229
185
  Gets the ID of the selected option
230
186
 
231
187
  Returns:
232
- A string ID
188
+ A string ID or None if there are no selectable options
233
189
  """
234
- return self.get_selected().identifier
190
+ def get_id(x: po.SelectParameterOption): return x._identifier
191
+ return u.process_if_not_none(self.get_selected(), get_id)
235
192
 
236
- def get_selected_id_quoted(self) -> str:
193
+ def get_selected_id_quoted(self, **kwargs) -> Optional[str]:
237
194
  """
238
195
  Gets the ID of the selected option surrounded by single quotes
239
196
 
240
197
  Returns:
241
- A string
198
+ A string or None if there are no selectable options
242
199
  """
243
- return self._enquote(self.get_selected_id())
200
+ return u.process_if_not_none(self.get_selected_id(), self._enquote)
244
201
 
245
- def get_selected_label(self) -> str:
202
+ def get_selected_label(self, **kwargs) -> Optional[str]:
246
203
  """
247
204
  Gets the label of the selected option
248
205
 
249
206
  Returns:
250
- A string
207
+ A string or None if there are no selectable options
251
208
  """
252
- return self.get_selected().label
209
+ def get_label(x: po.SelectParameterOption): return x._label
210
+ return u.process_if_not_none(self.get_selected(), get_label)
253
211
 
254
- def get_selected_label_quoted(self) -> str:
212
+ def get_selected_label_quoted(self, **kwargs) -> Optional[str]:
255
213
  """
256
214
  Gets the label of the selected option surrounded by single quotes
257
215
 
258
216
  Returns:
259
- A string
217
+ A string or None if there are no selectable options
260
218
  """
261
- return self._enquote(self.get_selected_label())
262
-
263
- # Overriding for refresh method
219
+ return u.process_if_not_none(self.get_selected_label(), self._enquote)
220
+
264
221
  def _get_selected_ids_as_list(self) -> Sequence[str]:
265
- return (self.get_selected_id(),)
266
-
267
- def _get_default(self) -> str:
268
- default_id = next(self._get_default_iterator(), None)
269
- if default_id is None:
270
- default_id = self.options[0].identifier if len(self.options) > 0 else None
271
- return default_id
222
+ selected_id = self.get_selected_id()
223
+ if selected_id is not None:
224
+ return (self.get_selected_id(),)
225
+ else:
226
+ return tuple()
272
227
 
273
- def _set_default_as_selection_mutate(self) -> None:
274
- self.selected_id = self._get_default()
275
-
276
- def to_json_dict(self) -> Dict:
228
+ def to_json_dict0(self) -> dict:
277
229
  """
278
230
  Converts this parameter as a JSON object for the parameters API response
279
231
 
280
232
  Returns:
281
233
  A dictionary for the JSON object
282
234
  """
283
- output = super().to_json_dict()
284
- output['selected_id'] = self.selected_id
235
+ output = super().to_json_dict0()
236
+ output['selected_id'] = self._selected_id
285
237
  return output
286
238
 
287
239
 
288
240
  @dataclass
289
241
  class MultiSelectParameter(_SelectionParameter):
290
242
  """
291
- Class to define attributes for multi-select parameter widgets.
243
+ Class for multi-select parameter widgets.
244
+
245
+ Attributes:
246
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
247
+ options: The parameter options that are currently selectable
248
+ selected_ids: A sequence of IDs of the selected options
292
249
  """
293
- selected_ids: Sequence[str]
294
- include_all: bool
295
- order_matters: bool
250
+ _config: pc.MultiSelectParameterConfig
251
+ _selected_ids: Sequence[str]
296
252
 
297
- def __init__(self, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, is_hidden = False,
298
- parent: Optional[_SelectionParameter] = None, include_all: bool = True, order_matters: bool = False) -> None:
253
+ def __post_init__(self):
254
+ super().__post_init__()
255
+ self._selected_ids = tuple(self._selected_ids)
256
+ for selected_id in self._selected_ids:
257
+ self._validate_selected_id_in_options(selected_id)
258
+
259
+ @staticmethod
260
+ def _ParameterConfigType():
261
+ return pc.MultiSelectParameterConfig
262
+
263
+ @classmethod
264
+ def Create(
265
+ cls, name: str, label: str, all_options: Sequence[Union[po.SelectParameterOption, dict]], *, include_all: bool = True,
266
+ order_matters: bool = False, is_hidden: bool = False, user_attribute: Optional[str] = None, parent_name: Optional[str] = None,
267
+ **kwargs
268
+ ) -> None:
299
269
  """
300
- Constructor for MultiSelectParameter class
270
+ Method for creating the configurations for a Parameter that may include user attribute or parent
301
271
 
302
272
  Parameters:
303
273
  name: The name of the parameter
304
274
  label: The display label for the parameter
305
- all_options: A sequence of SelectParameterOption which defines the attribute for each dropdown option
306
- is_hidden: Whether the parameter is hidden in the parameters API response. Default is False.
307
- parent: The parent parameter that may cascade the options for this parameter. Default is no parent
308
- include_all: Whether applying no selection is equivalent to selecting all. Default is True
309
- order_matters: Whether the ordering of the selection matters. Default is False
275
+ all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
276
+ include_all: Whether having no options selected is equivalent to all selectable options selected
277
+ order_matters: Whether the order of the selections made matter
278
+ is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
279
+ user_attribute: The user attribute that may cascade the options for this parameter. Default is None
280
+ parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
310
281
  """
311
- super().__init__("MultiSelectParameter", name, label, all_options, is_hidden, parent)
312
- self.include_all = include_all
313
- self.order_matters = order_matters
282
+ super(cls, cls).Create(name, label, all_options, include_all=include_all, order_matters=order_matters, is_hidden=is_hidden,
283
+ user_attribute=user_attribute, parent_name=parent_name)
314
284
 
315
- def with_selection(self, selection: str) -> MultiSelectParameter:
285
+ @classmethod
286
+ def CreateSimple(
287
+ cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, include_all: bool = True,
288
+ order_matters: bool = False, is_hidden: bool = False, **kwargs
289
+ ) -> None:
316
290
  """
317
- Applies the selected value(s) to this widget parameter
291
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
318
292
 
319
293
  Parameters:
320
- selection: A JSON string of list of strings representing IDs of selected values
321
-
322
- Returns:
323
- A new copy of MultiSelectParameter with the selection applied
294
+ name: The name of the parameter
295
+ label: The display label for the parameter
296
+ all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
297
+ include_all: Whether having no options selected is equivalent to all selectable options selected
298
+ order_matters: Whether the order of the selections made matter
299
+ is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
324
300
  """
325
- param_copy = copy.copy(self)
326
- selection_split = u.load_json_or_comma_delimited_str_as_list(selection)
327
- param_copy.selected_ids = tuple(self._validate_selected_id_in_options(x) for x in selection_split)
328
- param_copy.children = [child.refresh(param_copy) for child in self.children]
329
- return param_copy
330
-
301
+ cls.Create(name, label, all_options, include_all=include_all, order_matters=order_matters, is_hidden=is_hidden)
302
+
331
303
  def has_non_empty_selection(self) -> bool:
332
304
  """
333
305
  Returns True if more than zero options were selected. False otherwise.
@@ -338,10 +310,11 @@ class MultiSelectParameter(_SelectionParameter):
338
310
  Returns:
339
311
  A boolean
340
312
  """
341
- return len(self.selected_ids) > 0
313
+ return len(self._selected_ids) > 0
342
314
 
343
- def get_selected_list(self, field: Optional[str] = None, *, default_field: Optional[str] = None,
344
- default: Any = None) -> Sequence[Union[po.SelectParameterOption, Any]]:
315
+ def get_selected_list(
316
+ self, field: Optional[str] = None, *, default_field: Optional[str] = None, default: Any = None, **kwargs
317
+ ) -> Sequence[Union[po.SelectParameterOption, Any]]:
345
318
  """
346
319
  Gets the sequence of the selected option(s) or a sequence of selected custom fields
347
320
 
@@ -356,35 +329,35 @@ class MultiSelectParameter(_SelectionParameter):
356
329
  Returns:
357
330
  A sequence of SelectParameterOption class objects or sequence of type of custom field
358
331
  """
359
- if not self.has_non_empty_selection() and self.include_all:
360
- selected_list = self.options
332
+ if not self.has_non_empty_selection() and self._config.include_all:
333
+ selected_list = self._options
361
334
  else:
362
- selected_list = (x for x in self.options if x.identifier in self.selected_ids)
335
+ selected_list = (x for x in self._options if x._identifier in self._selected_ids)
363
336
 
364
337
  if field is not None:
365
- selected_list = [selected.get_custom_field(field, default_field, default) for selected in selected_list]
338
+ selected_list = [selected.get_custom_field(field, default_field=default_field, default=default) for selected in selected_list]
366
339
 
367
340
  return tuple(selected_list)
368
341
 
369
- def get_selected_ids_as_list(self) -> Sequence[str]:
342
+ def get_selected_ids_as_list(self, **kwargs) -> Sequence[str]:
370
343
  """
371
344
  Gets the sequence of ID(s) of the selected option(s)
372
345
 
373
346
  Returns:
374
347
  A sequence of strings
375
348
  """
376
- return tuple(x.identifier for x in self.get_selected_list())
349
+ return tuple(x._identifier for x in self.get_selected_list())
377
350
 
378
- def get_selected_ids_joined(self) -> str:
351
+ def get_selected_ids_joined(self, **kwargs) -> str:
379
352
  """
380
353
  Gets the ID(s) of the selected option(s) joined by comma
381
354
 
382
355
  Returns:
383
356
  A string
384
357
  """
385
- return ', '.join(self.get_selected_ids_as_list())
358
+ return ','.join(self.get_selected_ids_as_list())
386
359
 
387
- def get_selected_ids_quoted_as_list(self) -> Sequence[str]:
360
+ def get_selected_ids_quoted_as_list(self, **kwargs) -> Sequence[str]:
388
361
  """
389
362
  Gets the sequence of ID(s) of the selected option(s) surrounded by single quotes
390
363
 
@@ -393,34 +366,34 @@ class MultiSelectParameter(_SelectionParameter):
393
366
  """
394
367
  return tuple(self._enquote(x) for x in self.get_selected_ids_as_list())
395
368
 
396
- def get_selected_ids_quoted_joined(self) -> str:
369
+ def get_selected_ids_quoted_joined(self, **kwargs) -> str:
397
370
  """
398
371
  Gets the ID(s) of the selected option(s) surrounded by single quotes and joined by comma
399
372
 
400
373
  Returns:
401
374
  A string
402
375
  """
403
- return ', '.join(self.get_selected_ids_quoted_as_list())
376
+ return ','.join(self.get_selected_ids_quoted_as_list())
404
377
 
405
- def get_selected_labels_as_list(self) -> Sequence[str]:
378
+ def get_selected_labels_as_list(self, **kwargs) -> Sequence[str]:
406
379
  """
407
380
  Gets the sequence of label(s) of the selected option(s)
408
381
 
409
382
  Returns:
410
383
  A sequence of strings
411
384
  """
412
- return tuple(x.label for x in self.get_selected_list())
385
+ return tuple(x._label for x in self.get_selected_list())
413
386
 
414
- def get_selected_labels_joined(self) -> str:
387
+ def get_selected_labels_joined(self, **kwargs) -> str:
415
388
  """
416
389
  Gets the label(s) of the selected option(s) joined by comma
417
390
 
418
391
  Returns:
419
392
  A string
420
393
  """
421
- return ', '.join(self.get_selected_labels_as_list())
394
+ return ','.join(self.get_selected_labels_as_list())
422
395
 
423
- def get_selected_labels_quoted_as_list(self) -> Sequence[str]:
396
+ def get_selected_labels_quoted_as_list(self, **kwargs) -> Sequence[str]:
424
397
  """
425
398
  Gets the sequence of label(s) of the selected option(s) surrounded by single quotes
426
399
 
@@ -429,97 +402,68 @@ class MultiSelectParameter(_SelectionParameter):
429
402
  """
430
403
  return tuple(self._enquote(x) for x in self.get_selected_labels_as_list())
431
404
 
432
- def get_selected_labels_quoted_joined(self) -> str:
405
+ def get_selected_labels_quoted_joined(self, **kwargs) -> str:
433
406
  """
434
407
  Gets the label(s) of the selected option(s) surrounded by single quotes and joined by comma
435
408
 
436
409
  Returns:
437
410
  A string
438
411
  """
439
- return ', '.join(self.get_selected_labels_quoted_as_list())
440
-
441
- def _get_selected_ids_as_list(self) -> Sequence[str]:
412
+ return ','.join(self.get_selected_labels_quoted_as_list())
413
+
414
+ def _get_selected_ids_as_list(self, **kwargs) -> Sequence[str]:
442
415
  return self.get_selected_ids_as_list()
443
416
 
444
- def _get_default(self) -> Sequence[str]:
445
- return tuple(self._get_default_iterator())
446
-
447
- def _set_default_as_selection_mutate(self):
448
- self.selected_ids = self._get_default()
449
-
450
- def to_json_dict(self):
417
+ def to_json_dict0(self):
451
418
  """
452
419
  Converts this parameter as a JSON object for the parameters API response
453
420
 
454
421
  Returns:
455
422
  A dictionary for the JSON object
456
423
  """
457
- output = super().to_json_dict()
458
- output['selected_ids'] = list(self.selected_ids)
459
- output['include_all'] = self.include_all
460
- output['order_matters'] = self.order_matters
424
+ output = super().to_json_dict0()
425
+ output['selected_ids'] = list(self._selected_ids)
461
426
  return output
462
427
 
463
428
 
464
429
  @dataclass
465
430
  class DateParameter(Parameter):
466
431
  """
467
- Class to define attributes for date parameter widgets.
468
- """
469
- curr_option: po.DateParameterOption
470
- selected_date: datetime
432
+ Class for date parameter widgets.
471
433
 
472
- def __init__(self, name: str, label: str, default_date: Union[str, datetime], date_format: str = '%Y-%m-%d',
473
- *, is_hidden: bool = False) -> None:
474
- """
475
- Constructor for DateParameter class
434
+ Attributes:
435
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
436
+ curr_option: The current option showing for defaults based on user attribute and selection of parent
437
+ selected_date: The selected date
438
+ """
439
+ _curr_option: po.DateParameterOption
440
+ _selected_date: Union[date, str]
476
441
 
477
- Parameters:
478
- name: The name of the parameter
479
- label: The display label for the parameter
480
- default_date: The default selected date
481
- date_format: The format of the default_date. Default is '%Y-%m-%d'
482
- is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
483
- """
484
- self.curr_option = po.DateParameterOption(default_date, date_format)
485
- all_options = (self.curr_option,)
486
- super().__init__("DateParameter", name, label, all_options, is_hidden, None)
487
- self._set_default_as_selection_mutate()
442
+ def __post_init__(self):
443
+ self._selected_date: date = self._validate_date(self._selected_date)
488
444
 
489
445
  @staticmethod
490
- def WithParent(name: str, label: str, all_options: Sequence[po.DateParameterOption], parent: SingleSelectParameter, *,
491
- is_hidden: bool = False) -> DateParameter:
446
+ def _ParameterConfigType():
447
+ return pc.DateParameterConfig
448
+
449
+ @classmethod
450
+ def CreateSimple(
451
+ cls, name: str, label: str, default_date: Union[str, date], *, date_format: str = '%Y-%m-%d', is_hidden: bool = False, **kwargs
452
+ ) -> None:
492
453
  """
493
- A factory method to construct a DateParameter with a parent parameter
454
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
494
455
 
495
456
  Parameters:
496
457
  name: The name of the parameter
497
458
  label: The display label for the parameter
498
- all_options: A sequence of DateParameterOption which contains various default dates linked to specific parent options
499
- parent: The parent parameter, which must be a SingleSelectParameter
459
+ default_date: Default date for this option
460
+ date_format: Format of the default date, default is '%Y-%m-%d'
500
461
  is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
501
462
  """
502
- new_param = DateParameter(name, label, '2020-01-01', is_hidden=is_hidden) # dummy date in valid format
503
- return Parameter.WithParent(all_options, parent, new_param)
463
+ single_param_option = po.DateParameterOption(default_date, date_format=date_format)
464
+ cls.Create(name, label, (single_param_option,), is_hidden=is_hidden)
504
465
 
505
- def with_selection(self, selection: str):
506
- """
507
- Applies the selected date to this widget parameter
508
-
509
- Parameters:
510
- selection: The date string which must be in yyyy-mm-dd format (regardless of self.date_format value)
511
-
512
- Returns:
513
- A new copy of DateParameter with the selection applied
514
- """
515
- param_copy = copy.copy(self)
516
- try:
517
- param_copy.selected_date = datetime.strptime(selection, "%Y-%m-%d")
518
- except ValueError as e:
519
- self._raise_invalid_input_error(selection, 'Invalid selection for date.', e)
520
- return param_copy
521
-
522
- def get_selected_date(self, date_format: str = None) -> str:
466
+ def get_selected_date(self, *, date_format: str = None, **kwargs) -> str:
523
467
  """
524
468
  Gets selected date as string
525
469
 
@@ -529,10 +473,10 @@ class DateParameter(Parameter):
529
473
  Returns:
530
474
  A string
531
475
  """
532
- date_format = self.curr_option.date_format if date_format is None else date_format
533
- return self.selected_date.strftime(date_format)
476
+ date_format = self._curr_option._date_format if date_format is None else date_format
477
+ return self._selected_date.strftime(date_format)
534
478
 
535
- def get_selected_date_quoted(self, date_format: str = None) -> str:
479
+ def get_selected_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
536
480
  """
537
481
  Gets selected date as string surrounded by single quotes
538
482
 
@@ -542,12 +486,9 @@ class DateParameter(Parameter):
542
486
  Returns:
543
487
  A string
544
488
  """
545
- return self._enquote(self.get_selected_date(date_format))
546
-
547
- def _set_default_as_selection_mutate(self) -> None:
548
- self.selected_date = self.curr_option.default_date
489
+ return self._enquote(self.get_selected_date(date_format=date_format))
549
490
 
550
- def to_json_dict(self):
491
+ def to_json_dict0(self):
551
492
  """
552
493
  Converts this parameter as a JSON object for the parameters API response
553
494
 
@@ -556,271 +497,259 @@ class DateParameter(Parameter):
556
497
  Returns:
557
498
  A dictionary for the JSON object
558
499
  """
559
- output = super().to_json_dict()
560
- output['selected_date'] = self.get_selected_date("%Y-%m-%d")
561
- return output
562
-
563
-
564
- @dataclass
565
- class _NumericParameter(Parameter):
566
- curr_option: po.NumericParameterOption
567
-
568
- def to_json_dict(self):
569
- """
570
- Helper method to converts numeric parameters into JSON objects for the parameters API response
571
-
572
- Returns:
573
- A dictionary for the JSON object
574
- """
575
- output = super().to_json_dict()
576
- output['min_value'] = str(self.curr_option.min_value)
577
- output['max_value'] = str(self.curr_option.max_value)
578
- output['increment'] = str(self.curr_option.increment)
500
+ output = super().to_json_dict0()
501
+ output.update(self._curr_option._to_json_dict())
502
+ output['selected_date'] = self.get_selected_date(date_format="%Y-%m-%d")
579
503
  return output
580
504
 
581
505
 
582
506
  @dataclass
583
- class NumberParameter(_NumericParameter):
507
+ class DateRangeParameter(Parameter):
584
508
  """
585
- Class to define attributes for number slider parameter widgets.
509
+ Class for date range parameter widgets.
510
+
511
+ Attributes:
512
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
513
+ curr_option: The current option showing for defaults based on user attribute and selection of parent
514
+ selected_start_date: The selected start date
515
+ selected_end_date: The selected end date
586
516
  """
587
- selected_value: Decimal
517
+ _curr_option: po.DateRangeParameterOption
518
+ _selected_start_date: Union[date, str]
519
+ _selected_end_date: Union[date, str]
520
+
521
+ def __post_init__(self):
522
+ self._selected_start_date: date = self._validate_date(self._selected_start_date)
523
+ self._selected_end_date: date = self._validate_date(self._selected_end_date)
524
+
525
+ @staticmethod
526
+ def _ParameterConfigType():
527
+ return pc.DateRangeParameterConfig
588
528
 
589
- def __init__(self, name: str, label: str, min_value: po.Number, max_value: po.Number, increment: po.Number = 1,
590
- default_value: po.Number = None, *, is_hidden: bool = False) -> None:
529
+ @classmethod
530
+ def CreateSimple(
531
+ cls, name: str, label: str, default_start_date: Union[str, date], default_end_date: Union[str, date],
532
+ *, date_format: str = '%Y-%m-%d', is_hidden: bool = False, **kwargs
533
+ ) -> None:
591
534
  """
592
- Constructor for NumberParameter class
535
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
593
536
 
594
537
  Parameters:
595
538
  name: The name of the parameter
596
539
  label: The display label for the parameter
597
- min_value: The minimum bound for selection. Can be of type Decimal, integer, or number parsable string
598
- max_value: The maxixmum bound for selection. Can be of type Decimal, integer, or number parsable string
599
- increment: The increment for allowable selections. Can be of type Decimal, integer, or number parsable string. Default is 1
600
- default_value: The default selection. Can be of type Decimal, integer, or number parsable string. Default is min_value
540
+ default_start_date: Default start date for this option
541
+ default_end_date: Default end date for this option
542
+ date_format: Format of the default date, default is '%Y-%m-%d'
601
543
  is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
602
544
  """
603
- default_value = default_value if default_value is not None else min_value
604
- curr_option = po.NumberParameterOption(min_value, max_value, increment, default_value)
605
- all_options = (curr_option,)
606
- super().__init__("NumberParameter", name, label, all_options, is_hidden, None, curr_option)
607
- self._set_default_as_selection_mutate()
545
+ single_param_option = po.DateRangeParameterOption(default_start_date, default_end_date, date_format=date_format)
546
+ cls.Create(name, label, (single_param_option,), is_hidden=is_hidden)
608
547
 
609
- @staticmethod
610
- def WithParent(name: str, label: str, all_options: Sequence[po.NumberParameterOption], parent: SingleSelectParameter, *,
611
- is_hidden: bool = False) -> DateParameter:
548
+ def get_selected_start_date(self, *, date_format: str = None, **kwargs) -> str:
612
549
  """
613
- A factory method to construct a NumberParameter with a parent parameter
550
+ Gets selected start date as string
614
551
 
615
552
  Parameters:
616
- name: The name of the parameter
617
- label: The display label for the parameter
618
- all_options: A sequence of NumberParameterOption which contains various bounds and default values linked to specific parent options
619
- parent: The parent parameter, which must be a SingleSelectParameter
620
- is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
553
+ date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
554
+
555
+ Returns:
556
+ A string
557
+ """
558
+ date_format = self._curr_option._date_format if date_format is None else date_format
559
+ return self._selected_start_date.strftime(date_format)
560
+
561
+ def get_selected_start_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
562
+ """
563
+ Gets selected start date as string surrounded by single quotes
564
+
565
+ Parameters:
566
+ date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
567
+
568
+ Returns:
569
+ A string
621
570
  """
622
- new_param = NumberParameter(name, label, 0, 1, is_hidden=is_hidden) # dummy values
623
- return Parameter.WithParent(all_options, parent, new_param)
571
+ return self._enquote(self.get_selected_start_date(date_format=date_format))
624
572
 
625
- def with_selection(self, selection: str):
573
+ def get_selected_end_date(self, *, date_format: str = None, **kwargs) -> str:
626
574
  """
627
- Applies the selected number to this widget parameter
575
+ Gets selected end date as string
628
576
 
629
577
  Parameters:
630
- selection: The selected number (must be a string parsable as a number)
631
-
578
+ date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
579
+
632
580
  Returns:
633
- A new copy of NumberParameter with the selection applied
581
+ A string
634
582
  """
635
- param_copy = copy.copy(self)
636
- try:
637
- param_copy.selected_value = param_copy.curr_option._validate_value(selection)
638
- except u.ConfigurationError as e:
639
- self._raise_invalid_input_error(selection, 'Invalid selection for number parameter.', e)
640
- return param_copy
583
+ date_format = self._curr_option._date_format if date_format is None else date_format
584
+ return self._selected_end_date.strftime(date_format)
641
585
 
642
- def get_selected_value(self) -> str:
586
+ def get_selected_end_date_quoted(self, *, date_format: str = None, **kwargs) -> str:
643
587
  """
644
- Get the selected number
588
+ Gets selected end date as string surrounded by single quotes
589
+
590
+ Parameters:
591
+ date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
645
592
 
646
593
  Returns:
647
- A number parsable string of the selected number
594
+ A string
648
595
  """
649
- return str(self.selected_value)
596
+ return self._enquote(self.get_selected_end_date(date_format=date_format))
650
597
 
651
- def _set_default_as_selection_mutate(self) -> None:
652
- self.curr_option: po.NumberParameterOption
653
- self.selected_value = self.curr_option.default_value
654
-
655
- def to_json_dict(self):
598
+ def to_json_dict0(self):
656
599
  """
657
600
  Converts this parameter as a JSON object for the parameters API response
658
601
 
602
+ The "selected_date" field will always be in yyyy-mm-dd format
603
+
659
604
  Returns:
660
605
  A dictionary for the JSON object
661
606
  """
662
- output = super().to_json_dict()
663
- output['selected_value'] = self.get_selected_value()
607
+ output = super().to_json_dict0()
608
+ output.update(self._curr_option._to_json_dict())
609
+ output['selected_start_date'] = self.get_selected_start_date(date_format="%Y-%m-%d")
610
+ output['selected_end_date'] = self.get_selected_end_date(date_format="%Y-%m-%d")
664
611
  return output
665
612
 
666
613
 
667
614
  @dataclass
668
- class NumRangeParameter(_NumericParameter):
615
+ class NumberParameter(Parameter):
669
616
  """
670
- Class to define attributes for number range slider (double-ended) parameter widgets.
671
- """
672
- selected_lower_value: Decimal
673
- selected_upper_value: Decimal
617
+ Class for number parameter widgets.
674
618
 
675
- def __init__(self, name: str, label: str, min_value: po.Number, max_value: po.Number, increment: po.Number = 1,
676
- default_lower_value: po.Number = None, default_upper_value: po.Number = None, *, is_hidden: bool = False) -> None:
677
- """
678
- Constructor for NumberParameter class
619
+ Attributes:
620
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
621
+ curr_option: The current option showing for defaults based on user attribute and selection of parent
622
+ selected_value: The selected integer or decimal number
623
+ """
624
+ _curr_option: po.NumberParameterOption
625
+ _selected_value: po.Number
679
626
 
680
- Parameters:
681
- name: The name of the parameter
682
- label: The display label for the parameter
683
- min_value: The minimum bound for selection. Can be of type Decimal, integer, or number parsable string
684
- max_value: The maxixmum bound for selection. Can be of type Decimal, integer, or number parsable string
685
- increment: The increment for allowable selections. Can be of type Decimal, integer, or number parsable string. Default is 1
686
- default_lower_value: The default lower selection. Can be of type Decimal, integer, or number parsable string. Default is min_value
687
- default_upper_value: The default upper selection. Can be of type Decimal, integer, or number parsable string. Default is max_value
688
- is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
689
- """
690
- default_lower_value = default_lower_value if default_lower_value is not None else min_value
691
- default_upper_value = default_upper_value if default_upper_value is not None else max_value
692
- curr_option = po.NumRangeParameterOption(min_value, max_value, increment, default_lower_value, default_upper_value)
693
- all_options = (curr_option,)
694
- super().__init__("NumRangeParameter", name, label, all_options, is_hidden, None, curr_option)
695
- self._set_default_as_selection_mutate()
627
+ def __post_init__(self):
628
+ self._selected_value: Decimal = self._validate_number(self._selected_value, self._curr_option)
696
629
 
697
630
  @staticmethod
698
- def WithParent(name: str, label: str, all_options: Sequence[po.NumRangeParameterOption], parent: SingleSelectParameter, *,
699
- is_hidden: bool = False) -> DateParameter:
700
- """
701
- A factory method to construct a NumRangeParameter with a parent parameter
631
+ def _ParameterConfigType():
632
+ return pc.NumberParameterConfig
702
633
 
634
+ @classmethod
635
+ def CreateSimple(
636
+ cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, increment: po.Number = 1,
637
+ default_value: Optional[po.Number] = None, is_hidden: bool = False, **kwargs
638
+ ) -> None:
639
+ """
640
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
641
+
642
+ * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
643
+
703
644
  Parameters:
704
645
  name: The name of the parameter
705
646
  label: The display label for the parameter
706
- all_options: A sequence of NumRangeParameterOption which contains various bounds and default values linked to specific parent options
707
- parent: The parent parameter, which must be a SingleSelectParameter
647
+ min_value: Minimum selectable value
648
+ max_value: Maximum selectable value
649
+ increment: Increment of selectable values, and must fit evenly between min_value and max_value
650
+ default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
708
651
  is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
709
652
  """
710
- new_param = NumRangeParameter(name, label, 0, 1, is_hidden=is_hidden) # dummy values
711
- return Parameter.WithParent(all_options, parent, new_param)
653
+ single_param_option = po.NumberParameterOption(min_value, max_value, increment=increment, default_value=default_value)
654
+ cls.Create(name, label, (single_param_option,), is_hidden=is_hidden)
712
655
 
713
- def with_selection(self, selection: str):
656
+ def get_selected_value(self, **kwargs) -> str:
714
657
  """
715
- Applies the selected numbers to this widget parameter
716
-
717
- Parameters:
718
- selection: The lower and upper selected numbers joined by comma (with no spaces)
719
-
720
- Returns:
721
- A new copy of NumRangeParameter with the selection applied
722
- """
723
- try:
724
- lower, upper = selection.split(',')
725
- except ValueError as e:
726
- self._raise_invalid_input_error(selection, "Range parameter selection must be two numbers joined by comma.", e)
727
-
728
- param_copy = copy.copy(self)
729
- try:
730
- param_copy.selected_lower_value = param_copy.curr_option._validate_value(lower)
731
- param_copy.selected_upper_value = param_copy.curr_option._validate_value(upper, param_copy.selected_lower_value)
732
- except u.ConfigurationError as e:
733
- self._raise_invalid_input_error(selection, 'Invalid selection for range parameter.', e)
734
- return param_copy
735
-
736
- def get_selected_lower_value(self) -> str:
737
- """
738
- Get the selected lower number
739
-
740
- Returns:
741
- A number parsable string of the selected number
742
- """
743
- return str(self.selected_lower_value)
744
-
745
- def get_selected_upper_value(self) -> str:
746
- """
747
- Get the selected upper number
658
+ Get the selected number
748
659
 
749
660
  Returns:
750
661
  A number parsable string of the selected number
751
662
  """
752
- return str(self.selected_upper_value)
753
-
754
- def _set_default_as_selection_mutate(self) -> None:
755
- self.curr_option: po.NumRangeParameterOption
756
- self.selected_lower_value = self.curr_option.default_lower_value
757
- self.selected_upper_value = self.curr_option.default_upper_value
758
-
759
- def to_json_dict(self):
663
+ return str(self._selected_value)
664
+
665
+ def to_json_dict0(self):
760
666
  """
761
667
  Converts this parameter as a JSON object for the parameters API response
762
668
 
763
669
  Returns:
764
670
  A dictionary for the JSON object
765
671
  """
766
- output = super().to_json_dict()
767
- output['selected_lower_value'] = self.get_selected_lower_value()
768
- output['selected_upper_value'] = self.get_selected_upper_value()
672
+ output = super().to_json_dict0()
673
+ output.update(self._curr_option._to_json_dict())
674
+ output['selected_value'] = self.get_selected_value()
769
675
  return output
770
676
 
771
677
 
772
678
  @dataclass
773
- class DataSourceParameter(Parameter):
679
+ class NumberRangeParameter(Parameter):
774
680
  """
775
- Class for parameters that can use a lookup table to convert itself into another parameter
681
+ Class for number range parameter widgets.
682
+
683
+ Attributes:
684
+ config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
685
+ curr_option: The current option showing for defaults based on user attribute and selection of parent
686
+ selected_lower_value: The selected lower integer or decimal number
687
+ selected_upper_value: The selected upper integer or decimal number
776
688
  """
777
- parameter_class: Type[Parameter]
778
- data_source: DataSource
779
- parent: Optional[Parameter]
689
+ _curr_option: po.NumberRangeParameterOption
690
+ _selected_lower_value: po.Number
691
+ _selected_upper_value: po.Number
780
692
 
781
- def __init__(self, parameter_class: Type[Parameter], name: str, label: str, data_source: DataSource, *,
782
- is_hidden: bool = False, parent: Optional[Parameter] = None) -> None:
693
+ def __post_init__(self):
694
+ self._selected_lower_value: Decimal = self._validate_number(self._selected_lower_value, self._curr_option)
695
+ self._selected_upper_value: Decimal = self._validate_number(self._selected_upper_value, self._curr_option)
696
+
697
+ @staticmethod
698
+ def _ParameterConfigType():
699
+ return pc.NumberRangeParameterConfig
700
+
701
+ @classmethod
702
+ def CreateSimple(
703
+ cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, increment: po.Number = 1,
704
+ default_lower_value: Optional[po.Number] = None, default_upper_value: Optional[po.Number] = None, is_hidden: bool = False, **kwargs
705
+ ) -> None:
783
706
  """
784
- Constructor for DataSourceParameter, a Parameter that uses a DataSource to convert itself to another Parameter
707
+ Method for creating the configurations for a Parameter that doesn't involve user attributes or parent parameters
708
+
709
+ * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
785
710
 
786
711
  Parameters:
787
- parameter_class: The class of widget parameter to convert to
788
712
  name: The name of the parameter
789
713
  label: The display label for the parameter
790
- data_source: The lookup table to use for this parameter
714
+ min_value: Minimum selectable value
715
+ max_value: Maximum selectable value
716
+ increment: Increment of selectable values, and must fit evenly between min_value and max_value
717
+ default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
718
+ default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
719
+ Must also be greater than default_lower_value
791
720
  is_hidden: Whether the parameter is hidden in the parameters API response. Default is False
792
- parent: The parent parameter that may cascade the options for this parameter. Default is no parent
793
721
  """
794
- super().__init__("DataSourceParameter", name, label, None, is_hidden, None)
795
- self.parameter_class = parameter_class
796
- self.data_source = data_source
797
- self.parent = parent
722
+ single_param_option = po.NumberRangeParameterOption(min_value, max_value, increment=increment, default_lower_value=default_lower_value,
723
+ default_upper_value=default_upper_value)
724
+ cls.Create(name, label, (single_param_option,), is_hidden=is_hidden)
725
+
726
+ def get_selected_lower_value(self, **kwargs) -> str:
727
+ """
728
+ Get the selected lower value number
798
729
 
799
- def convert(self, df: pd.DataFrame) -> Parameter:
730
+ Returns:
731
+ A number parsable string of the selected number
800
732
  """
801
- Method to convert this DataSourceParameter into another parameter
733
+ return str(self._selected_lower_value)
802
734
 
803
- Parameters:
804
- df: The dataframe containing the parameter options data
735
+ def get_selected_upper_value(self, **kwargs) -> str:
736
+ """
737
+ Get the selected upper value number
805
738
 
806
739
  Returns:
807
- The converted parameter
740
+ A number parsable string of the selected number
808
741
  """
809
- return self.data_source.convert(self, df)
810
-
811
- def to_json_dict(self) -> Dict:
742
+ return str(self._selected_upper_value)
743
+
744
+ def to_json_dict0(self):
812
745
  """
813
746
  Converts this parameter as a JSON object for the parameters API response
814
747
 
815
748
  Returns:
816
749
  A dictionary for the JSON object
817
750
  """
818
- output = super().to_json_dict()
819
- output['widget_type'] = self.parameter_class.__name__
820
- output['data_source'] = self.data_source.__dict__
751
+ output = super().to_json_dict0()
752
+ output.update(self._curr_option._to_json_dict())
753
+ output['selected_lower_value'] = self.get_selected_lower_value()
754
+ output['selected_upper_value'] = self.get_selected_upper_value()
821
755
  return output
822
-
823
-
824
- # Types:
825
- SelectionParameter = Union[SingleSelectParameter, MultiSelectParameter]
826
- NumericParameter = Union[NumberParameter, NumRangeParameter]