squirrels 0.5.0rc0__py3-none-any.whl → 0.5.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.
- dateutils/__init__.py +6 -0
- dateutils/_enums.py +25 -0
- squirrels/dateutils.py → dateutils/_implementation.py +58 -111
- dateutils/types.py +6 -0
- squirrels/__init__.py +10 -12
- squirrels/_api_routes/__init__.py +5 -0
- squirrels/_api_routes/auth.py +271 -0
- squirrels/_api_routes/base.py +171 -0
- squirrels/_api_routes/dashboards.py +158 -0
- squirrels/_api_routes/data_management.py +148 -0
- squirrels/_api_routes/datasets.py +265 -0
- squirrels/_api_routes/oauth2.py +298 -0
- squirrels/_api_routes/project.py +252 -0
- squirrels/_api_server.py +245 -781
- squirrels/_arguments/__init__.py +0 -0
- squirrels/{arguments → _arguments}/init_time_args.py +7 -2
- squirrels/{arguments → _arguments}/run_time_args.py +13 -35
- squirrels/_auth.py +720 -212
- squirrels/_command_line.py +81 -41
- squirrels/_compile_prompts.py +147 -0
- squirrels/_connection_set.py +16 -7
- squirrels/_constants.py +29 -9
- squirrels/{_dashboards_io.py → _dashboards.py} +87 -6
- squirrels/_data_sources.py +570 -0
- squirrels/{dataset_result.py → _dataset_types.py} +2 -4
- squirrels/_exceptions.py +9 -37
- squirrels/_initializer.py +83 -59
- squirrels/_logging.py +117 -0
- squirrels/_manifest.py +129 -62
- squirrels/_model_builder.py +10 -52
- squirrels/_model_configs.py +3 -3
- squirrels/_model_queries.py +1 -1
- squirrels/_models.py +249 -118
- squirrels/{package_data → _package_data}/base_project/.env +16 -4
- squirrels/{package_data → _package_data}/base_project/.env.example +15 -3
- squirrels/{package_data → _package_data}/base_project/connections.yml +4 -3
- squirrels/{package_data → _package_data}/base_project/dashboards/dashboard_example.py +4 -4
- squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
- squirrels/{package_data → _package_data}/base_project/duckdb_init.sql +1 -0
- squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
- squirrels/{package_data → _package_data}/base_project/models/builds/build_example.py +2 -2
- squirrels/{package_data → _package_data}/base_project/models/builds/build_example.sql +1 -1
- squirrels/{package_data → _package_data}/base_project/models/builds/build_example.yml +2 -0
- squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +17 -0
- squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +32 -0
- squirrels/_package_data/base_project/models/federates/federate_example.py +48 -0
- squirrels/_package_data/base_project/models/federates/federate_example.sql +21 -0
- squirrels/{package_data → _package_data}/base_project/models/federates/federate_example.yml +7 -7
- squirrels/{package_data → _package_data}/base_project/models/sources.yml +5 -6
- squirrels/{package_data → _package_data}/base_project/parameters.yml +32 -45
- squirrels/_package_data/base_project/pyconfigs/connections.py +18 -0
- squirrels/{package_data → _package_data}/base_project/pyconfigs/context.py +31 -22
- squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
- squirrels/_package_data/base_project/pyconfigs/user.py +44 -0
- squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.yml +1 -1
- squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.yml +1 -1
- squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
- squirrels/_package_data/templates/dataset_results.html +112 -0
- squirrels/_package_data/templates/oauth_login.html +271 -0
- squirrels/_package_data/templates/squirrels_studio.html +20 -0
- squirrels/_parameter_configs.py +76 -55
- squirrels/_parameter_options.py +348 -0
- squirrels/_parameter_sets.py +53 -45
- squirrels/_parameters.py +1664 -0
- squirrels/_project.py +403 -242
- squirrels/_py_module.py +3 -2
- squirrels/_request_context.py +33 -0
- squirrels/_schemas/__init__.py +0 -0
- squirrels/_schemas/auth_models.py +167 -0
- squirrels/_schemas/query_param_models.py +75 -0
- squirrels/{_api_response_models.py → _schemas/response_models.py} +48 -18
- squirrels/_seeds.py +1 -1
- squirrels/_sources.py +23 -19
- squirrels/_utils.py +121 -39
- squirrels/_version.py +1 -1
- squirrels/arguments.py +7 -0
- squirrels/auth.py +4 -0
- squirrels/connections.py +3 -0
- squirrels/dashboards.py +2 -81
- squirrels/data_sources.py +14 -563
- squirrels/parameter_options.py +13 -348
- squirrels/parameters.py +14 -1266
- squirrels/types.py +16 -0
- {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/METADATA +42 -30
- squirrels-0.5.1.dist-info/RECORD +98 -0
- squirrels/package_data/base_project/dashboards/dashboard_example.yml +0 -22
- squirrels/package_data/base_project/macros/macros_example.sql +0 -15
- squirrels/package_data/base_project/models/dbviews/dbview_example.sql +0 -12
- squirrels/package_data/base_project/models/dbviews/dbview_example.yml +0 -26
- squirrels/package_data/base_project/models/federates/federate_example.py +0 -44
- squirrels/package_data/base_project/models/federates/federate_example.sql +0 -17
- squirrels/package_data/base_project/pyconfigs/connections.py +0 -14
- squirrels/package_data/base_project/pyconfigs/parameters.py +0 -93
- squirrels/package_data/base_project/pyconfigs/user.py +0 -23
- squirrels/package_data/base_project/squirrels.yml.j2 +0 -71
- squirrels-0.5.0rc0.dist-info/RECORD +0 -70
- /squirrels/{package_data → _package_data}/base_project/assets/expenses.db +0 -0
- /squirrels/{package_data → _package_data}/base_project/assets/weather.db +0 -0
- /squirrels/{package_data → _package_data}/base_project/docker/.dockerignore +0 -0
- /squirrels/{package_data → _package_data}/base_project/docker/Dockerfile +0 -0
- /squirrels/{package_data → _package_data}/base_project/docker/compose.yml +0 -0
- /squirrels/{package_data/base_project/.gitignore → _package_data/base_project/gitignore} +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.csv +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.csv +0 -0
- /squirrels/{package_data → _package_data}/base_project/tmp/.gitignore +0 -0
- {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/WHEEL +0 -0
- {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/entry_points.txt +0 -0
- {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/licenses/LICENSE +0 -0
squirrels/_parameters.py
ADDED
|
@@ -0,0 +1,1664 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Callable, Type, TypeVar, Sequence, Generic, Any
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from datetime import datetime, date
|
|
5
|
+
from decimal import Decimal
|
|
6
|
+
from abc import ABCMeta, abstractmethod
|
|
7
|
+
|
|
8
|
+
from ._arguments.init_time_args import ParametersArgs
|
|
9
|
+
from ._schemas import response_models as rm
|
|
10
|
+
from . import _data_sources as d, _parameter_configs as pc, _parameter_options as po, _parameter_sets as ps
|
|
11
|
+
from . import _utils as u
|
|
12
|
+
|
|
13
|
+
IntOrFloat = TypeVar("IntOrFloat", int, float)
|
|
14
|
+
|
|
15
|
+
PC = TypeVar("PC", bound=pc.ParameterConfig)
|
|
16
|
+
PO = TypeVar("PO", bound=po.ParameterOption)
|
|
17
|
+
DS = TypeVar("DS", bound=d.DataSource)
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class Parameter(Generic[PC, PO, DS], metaclass=ABCMeta):
|
|
21
|
+
"""
|
|
22
|
+
Abstract class for all parameter widgets
|
|
23
|
+
"""
|
|
24
|
+
_config: PC
|
|
25
|
+
|
|
26
|
+
@abstractmethod
|
|
27
|
+
def is_enabled(self) -> bool:
|
|
28
|
+
return True
|
|
29
|
+
|
|
30
|
+
@staticmethod
|
|
31
|
+
@abstractmethod
|
|
32
|
+
def _ParameterConfigType() -> Type[PC]: # Gets the actual type of the ParameterConfig TypeVar at runtime
|
|
33
|
+
pass
|
|
34
|
+
|
|
35
|
+
@staticmethod
|
|
36
|
+
@abstractmethod
|
|
37
|
+
def _ParameterOptionType() -> Type[PO]: # Gets the actual type of the ParameterOption TypeVar at runtime
|
|
38
|
+
pass
|
|
39
|
+
|
|
40
|
+
@staticmethod
|
|
41
|
+
@abstractmethod
|
|
42
|
+
def _DataSourceType() -> Type[DS]: # Gets the actual type of the DataSource TypeVar at runtime
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
@classmethod
|
|
46
|
+
def CreateWithOptions(
|
|
47
|
+
cls, name: str, label: str, all_options: Sequence[PO | dict], *, description: str = "",
|
|
48
|
+
user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
49
|
+
) -> PC:
|
|
50
|
+
"""
|
|
51
|
+
Method for creating the configurations for a Parameter that may include user attribute or parent
|
|
52
|
+
|
|
53
|
+
Arguments:
|
|
54
|
+
name: The name of the parameter
|
|
55
|
+
label: The display label for the parameter
|
|
56
|
+
all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
|
|
57
|
+
description: Explains the meaning of the parameter
|
|
58
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
59
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
60
|
+
"""
|
|
61
|
+
param_option_type = cls._ParameterOptionType()
|
|
62
|
+
if not isinstance(all_options, Sequence) or not all(isinstance(x, (param_option_type, dict)) for x in all_options):
|
|
63
|
+
raise u.ConfigurationError(f"The parameter must take a sequence of {param_option_type.__name__} objects")
|
|
64
|
+
|
|
65
|
+
param_config_type = cls._ParameterConfigType()
|
|
66
|
+
param_config = param_config_type(
|
|
67
|
+
name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name, **kwargs
|
|
68
|
+
)
|
|
69
|
+
return param_config
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def create_with_options(
|
|
73
|
+
cls, name: str, label: str, *, description: str = "", user_attribute: str | None = None, parent_name: str | None = None
|
|
74
|
+
):
|
|
75
|
+
"""
|
|
76
|
+
Python decorator for creating the configurations for a Parameter that may include user attribute or parent.
|
|
77
|
+
|
|
78
|
+
The decorated function must return a list of ParameterOption objects.
|
|
79
|
+
|
|
80
|
+
Arguments:
|
|
81
|
+
name: The name of the parameter
|
|
82
|
+
label: The display label for the parameter
|
|
83
|
+
description: Explains the meaning of the parameter
|
|
84
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
85
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
86
|
+
"""
|
|
87
|
+
def decorator(func: Callable[..., Sequence[PO]]):
|
|
88
|
+
def wrapper(sqrl: ParametersArgs):
|
|
89
|
+
options = u.call_func(func, sqrl=sqrl)
|
|
90
|
+
return cls.CreateWithOptions(
|
|
91
|
+
name, label, options, description=description,
|
|
92
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
93
|
+
)
|
|
94
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
95
|
+
return wrapper
|
|
96
|
+
return decorator
|
|
97
|
+
|
|
98
|
+
@classmethod
|
|
99
|
+
@abstractmethod
|
|
100
|
+
def CreateSimple(cls, name: str, label: str, *args, description: str = "", **kwargs) -> None:
|
|
101
|
+
pass
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def create_simple(cls, name: str, label: str, *args, description: str = "", **kwargs) -> None:
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
@classmethod
|
|
109
|
+
def _CreateFromSourceHelper(
|
|
110
|
+
cls, name: str, label: str, data_source: DS | dict, *, extra_args: dict = {}, description: str = "",
|
|
111
|
+
user_attribute: str | None = None, parent_name: str | None = None
|
|
112
|
+
):
|
|
113
|
+
data_source_type = cls._DataSourceType()
|
|
114
|
+
if not isinstance(data_source, (data_source_type, dict)):
|
|
115
|
+
raise u.ConfigurationError(f"The data source must be a {data_source_type.__name__} object")
|
|
116
|
+
|
|
117
|
+
param_config = pc.DataSourceParameterConfig(
|
|
118
|
+
cls._ParameterConfigType(), name, label, data_source, description=description, user_attribute=user_attribute,
|
|
119
|
+
parent_name=parent_name, extra_args=extra_args
|
|
120
|
+
)
|
|
121
|
+
return param_config
|
|
122
|
+
|
|
123
|
+
@classmethod
|
|
124
|
+
def CreateFromSource(
|
|
125
|
+
cls, name: str, label: str, data_source: DS | dict, *, description: str = "",
|
|
126
|
+
user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
127
|
+
):
|
|
128
|
+
"""
|
|
129
|
+
Method for creating the configurations for any Parameter that uses a DataSource to receive the options
|
|
130
|
+
|
|
131
|
+
Arguments:
|
|
132
|
+
name: The name of the parameter
|
|
133
|
+
label: The display label for the parameter
|
|
134
|
+
data_source: The lookup table to use for this parameter
|
|
135
|
+
description: Explains the meaning of the parameter
|
|
136
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
137
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
138
|
+
"""
|
|
139
|
+
return cls._CreateFromSourceHelper(name, label, data_source, description=description, user_attribute=user_attribute, parent_name=parent_name)
|
|
140
|
+
|
|
141
|
+
@classmethod
|
|
142
|
+
def create_from_source(
|
|
143
|
+
cls, name: str, label: str, *, description: str = "", user_attribute: str | None = None, parent_name: str | None = None
|
|
144
|
+
):
|
|
145
|
+
"""
|
|
146
|
+
Python decorator for creating the configurations for a Parameter that uses a DataSource to receive the options from a lookup table
|
|
147
|
+
|
|
148
|
+
The decorated function must return a DataSource object.
|
|
149
|
+
|
|
150
|
+
Arguments:
|
|
151
|
+
name: The name of the parameter
|
|
152
|
+
label: The display label for the parameter
|
|
153
|
+
description: Explains the meaning of the parameter
|
|
154
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
155
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
156
|
+
"""
|
|
157
|
+
def decorator(func: Callable[..., DS]):
|
|
158
|
+
def wrapper(sqrl: ParametersArgs):
|
|
159
|
+
data_source = u.call_func(func, sqrl=sqrl)
|
|
160
|
+
return cls.CreateFromSource(
|
|
161
|
+
name, label, data_source, description=description,
|
|
162
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
163
|
+
)
|
|
164
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
165
|
+
return wrapper
|
|
166
|
+
return decorator
|
|
167
|
+
|
|
168
|
+
def _enquote(self, value: str) -> str:
|
|
169
|
+
return "'" + value.replace("'", "''") + "'"
|
|
170
|
+
|
|
171
|
+
def _validate_input_date(self, input_date: date | str, curr_option: po._DateTypeParameterOption) -> date:
|
|
172
|
+
if isinstance(input_date, str):
|
|
173
|
+
try:
|
|
174
|
+
input_date = datetime.strptime(input_date.strip(), "%Y-%m-%d").date()
|
|
175
|
+
except ValueError:
|
|
176
|
+
raise self._config._invalid_input_error(str(input_date), "Must be a date in YYYY-MM-DD format.")
|
|
177
|
+
|
|
178
|
+
try:
|
|
179
|
+
return curr_option._validate_date(input_date)
|
|
180
|
+
except u.ConfigurationError as e:
|
|
181
|
+
raise self._config._invalid_input_error(str(input_date), str(e))
|
|
182
|
+
|
|
183
|
+
def _validate_number(self, input_number: po.Number, curr_option: po._NumericParameterOption) -> Decimal:
|
|
184
|
+
try:
|
|
185
|
+
return curr_option._validate_value(input_number)
|
|
186
|
+
except u.ConfigurationError as e:
|
|
187
|
+
raise self._config._invalid_input_error(str(input_number), str(e))
|
|
188
|
+
|
|
189
|
+
@abstractmethod
|
|
190
|
+
def _to_json_dict0(self) -> dict:
|
|
191
|
+
"""
|
|
192
|
+
Helper method to convert the derived Parameter class into a JSON dictionary
|
|
193
|
+
"""
|
|
194
|
+
output = {
|
|
195
|
+
"widget_type": self._config.widget_type(), "name": self._config.name,
|
|
196
|
+
"label": self._config.label, "description": self._config.description
|
|
197
|
+
}
|
|
198
|
+
if not self.is_enabled():
|
|
199
|
+
output["widget_type"] = "disabled"
|
|
200
|
+
return output
|
|
201
|
+
|
|
202
|
+
@abstractmethod
|
|
203
|
+
def _get_response_model0(self) -> type[rm.ParameterModelBase]:
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
def _to_api_response_model0(self) -> rm.ParameterModelBase:
|
|
207
|
+
return self._get_response_model0().model_validate(self._to_json_dict0())
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
SelectionPC = TypeVar("SelectionPC", bound=pc.SelectionParameterConfig)
|
|
211
|
+
|
|
212
|
+
@dataclass
|
|
213
|
+
class _SelectionParameter(Parameter[SelectionPC, po.SelectParameterOption, d.SelectDataSource], Generic[SelectionPC]):
|
|
214
|
+
_options: Sequence[po.SelectParameterOption]
|
|
215
|
+
|
|
216
|
+
def __post_init__(self):
|
|
217
|
+
self._options = tuple(self._options)
|
|
218
|
+
|
|
219
|
+
def is_enabled(self) -> bool:
|
|
220
|
+
return len(self._options) > 0
|
|
221
|
+
|
|
222
|
+
@abstractmethod
|
|
223
|
+
def _get_selected_ids_as_list(self) -> Sequence[str]:
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
def _validate_selected_id_in_options(self, selected_id):
|
|
227
|
+
if selected_id not in (x._identifier for x in self._options):
|
|
228
|
+
raise self._config._invalid_input_error(selected_id, f"The selected id {selected_id} does not exist in available options.")
|
|
229
|
+
|
|
230
|
+
@abstractmethod
|
|
231
|
+
def _to_json_dict0(self) -> dict:
|
|
232
|
+
"""
|
|
233
|
+
Helper method to convert the derived selection parameter class into a JSON object
|
|
234
|
+
"""
|
|
235
|
+
output = super()._to_json_dict0()
|
|
236
|
+
output['trigger_refresh'] = self._config.trigger_refresh
|
|
237
|
+
output['options'] = [x._to_json_dict() for x in self._options]
|
|
238
|
+
return output
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
@dataclass
|
|
242
|
+
class SingleSelectParameter(_SelectionParameter[pc.SingleSelectParameterConfig]):
|
|
243
|
+
"""
|
|
244
|
+
Class for single-select parameter widgets.
|
|
245
|
+
|
|
246
|
+
Attributes:
|
|
247
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
248
|
+
options: The parameter options that are currently selectable
|
|
249
|
+
selected_id: The ID of the selected option
|
|
250
|
+
"""
|
|
251
|
+
_selected_id: str | None
|
|
252
|
+
|
|
253
|
+
def __post_init__(self):
|
|
254
|
+
super().__post_init__()
|
|
255
|
+
if len(self._options) > 0:
|
|
256
|
+
assert self._selected_id != None
|
|
257
|
+
self._validate_selected_id_in_options(self._selected_id)
|
|
258
|
+
else:
|
|
259
|
+
self._selected_id = None
|
|
260
|
+
|
|
261
|
+
@staticmethod
|
|
262
|
+
def _ParameterConfigType():
|
|
263
|
+
return pc.SingleSelectParameterConfig
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def _ParameterOptionType():
|
|
267
|
+
return po.SelectParameterOption
|
|
268
|
+
|
|
269
|
+
@staticmethod
|
|
270
|
+
def _DataSourceType():
|
|
271
|
+
return d.SelectDataSource
|
|
272
|
+
|
|
273
|
+
@classmethod
|
|
274
|
+
def CreateSimple(
|
|
275
|
+
cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption | dict], *, description: str = "", **kwargs
|
|
276
|
+
):
|
|
277
|
+
"""
|
|
278
|
+
Method for creating the configurations for a SingleSelectParameter that doesn't involve user attributes or parent parameters
|
|
279
|
+
|
|
280
|
+
Arguments:
|
|
281
|
+
name: The name of the parameter
|
|
282
|
+
label: The display label for the parameter
|
|
283
|
+
all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
|
|
284
|
+
description: Explains the meaning of the parameter
|
|
285
|
+
"""
|
|
286
|
+
return cls.CreateWithOptions(name, label, all_options, description=description)
|
|
287
|
+
|
|
288
|
+
@classmethod
|
|
289
|
+
def create_simple(cls, name: str, label: str, *, description: str = ""):
|
|
290
|
+
"""
|
|
291
|
+
Python decorator for creating the configurations for a SingleSelectParameter that doesn't involve user attributes or parent parameters
|
|
292
|
+
|
|
293
|
+
The decorated function must return a list of SelectParameterOption objects.
|
|
294
|
+
|
|
295
|
+
Arguments:
|
|
296
|
+
name: The name of the parameter
|
|
297
|
+
label: The display label for the parameter
|
|
298
|
+
description: Explains the meaning of the parameter
|
|
299
|
+
"""
|
|
300
|
+
def decorator(func: Callable[..., Sequence[po.SelectParameterOption]]):
|
|
301
|
+
def wrapper(sqrl: ParametersArgs):
|
|
302
|
+
options = u.call_func(func, sqrl=sqrl)
|
|
303
|
+
return cls.CreateSimple(name, label, options, description=description)
|
|
304
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
305
|
+
return wrapper
|
|
306
|
+
return decorator
|
|
307
|
+
|
|
308
|
+
def get_selected(
|
|
309
|
+
self, field: str | None = None, *, default_field: str | None = None, default: Any = None, **kwargs
|
|
310
|
+
) -> po.SelectParameterOption | Any | None:
|
|
311
|
+
"""
|
|
312
|
+
Gets the selected single-select option or selected custom field
|
|
313
|
+
|
|
314
|
+
Arguments:
|
|
315
|
+
field: If field is not None, the method gets this field from the "custom_fields" attribute of the selected option.
|
|
316
|
+
Otherwise, returns the class object of the selected option
|
|
317
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
318
|
+
as the "field" instead. Does nothing if field is None
|
|
319
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, then the default
|
|
320
|
+
is returned as the selected field. Does nothing if field is None or default_field is not None
|
|
321
|
+
|
|
322
|
+
Returns:
|
|
323
|
+
A SelectParameterOption class object if no field is provided, or the type of the custom field
|
|
324
|
+
"""
|
|
325
|
+
def get_selected_from_id(identifier: str):
|
|
326
|
+
selected = next(x for x in self._options if x._identifier == identifier)
|
|
327
|
+
if field is not None:
|
|
328
|
+
selected = selected.get_custom_field(field, default_field=default_field, default=default)
|
|
329
|
+
return selected
|
|
330
|
+
return u.process_if_not_none(self._selected_id, get_selected_from_id)
|
|
331
|
+
|
|
332
|
+
def get_selected_quoted(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str | None:
|
|
333
|
+
"""
|
|
334
|
+
Gets the selected single-select option surrounded by single quotes
|
|
335
|
+
|
|
336
|
+
Arguments:
|
|
337
|
+
field: The "custom_fields" attribute of the selected option.
|
|
338
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
339
|
+
as the "field" instead.
|
|
340
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, then the default
|
|
341
|
+
is returned as the selected field. Does nothing if default_field is not None
|
|
342
|
+
|
|
343
|
+
Returns:
|
|
344
|
+
A string surrounded by single quotes
|
|
345
|
+
"""
|
|
346
|
+
selected_value = self.get_selected(field, default_field=default_field, default=default)
|
|
347
|
+
|
|
348
|
+
def _enquote(x: Any) -> str:
|
|
349
|
+
if not isinstance(selected_value, str):
|
|
350
|
+
raise u.ConfigurationError(
|
|
351
|
+
f"Method 'get_selected_quoted' can only be used on fields with only string values"
|
|
352
|
+
)
|
|
353
|
+
return self._enquote(x)
|
|
354
|
+
|
|
355
|
+
return u.process_if_not_none(selected_value, _enquote)
|
|
356
|
+
|
|
357
|
+
def get_selected_id(self, **kwargs) -> str | None:
|
|
358
|
+
"""
|
|
359
|
+
Gets the ID of the selected option
|
|
360
|
+
|
|
361
|
+
Returns:
|
|
362
|
+
A string ID or None if there are no selectable options
|
|
363
|
+
"""
|
|
364
|
+
def get_id(x: po.SelectParameterOption):
|
|
365
|
+
return x._identifier
|
|
366
|
+
return u.process_if_not_none(self.get_selected(), get_id)
|
|
367
|
+
|
|
368
|
+
def get_selected_id_quoted(self, **kwargs) -> str | None:
|
|
369
|
+
"""
|
|
370
|
+
Gets the ID of the selected option surrounded by single quotes
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
A string or None if there are no selectable options
|
|
374
|
+
"""
|
|
375
|
+
return u.process_if_not_none(self.get_selected_id(), self._enquote)
|
|
376
|
+
|
|
377
|
+
def get_selected_label(self, **kwargs) -> str | None:
|
|
378
|
+
"""
|
|
379
|
+
Gets the label of the selected option
|
|
380
|
+
|
|
381
|
+
Returns:
|
|
382
|
+
A string or None if there are no selectable options
|
|
383
|
+
"""
|
|
384
|
+
def get_label(x: po.SelectParameterOption): return x._label
|
|
385
|
+
return u.process_if_not_none(self.get_selected(), get_label)
|
|
386
|
+
|
|
387
|
+
def get_selected_label_quoted(self, **kwargs) -> str | None:
|
|
388
|
+
"""
|
|
389
|
+
Gets the label of the selected option surrounded by single quotes
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
A string or None if there are no selectable options
|
|
393
|
+
"""
|
|
394
|
+
return u.process_if_not_none(self.get_selected_label(), self._enquote)
|
|
395
|
+
|
|
396
|
+
def _get_selected_ids_as_list(self) -> Sequence[str]:
|
|
397
|
+
selected_id = self.get_selected_id()
|
|
398
|
+
if selected_id is not None:
|
|
399
|
+
return (selected_id,)
|
|
400
|
+
else:
|
|
401
|
+
return tuple()
|
|
402
|
+
|
|
403
|
+
def _to_json_dict0(self) -> dict:
|
|
404
|
+
"""
|
|
405
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
406
|
+
|
|
407
|
+
Returns:
|
|
408
|
+
A dictionary for the JSON object
|
|
409
|
+
"""
|
|
410
|
+
output = super()._to_json_dict0()
|
|
411
|
+
output['selected_id'] = self._selected_id
|
|
412
|
+
return output
|
|
413
|
+
|
|
414
|
+
def _get_response_model0(self):
|
|
415
|
+
return rm.SingleSelectParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
@dataclass
|
|
419
|
+
class MultiSelectParameter(_SelectionParameter[pc.MultiSelectParameterConfig]):
|
|
420
|
+
"""
|
|
421
|
+
Class for multi-select parameter widgets.
|
|
422
|
+
|
|
423
|
+
Attributes:
|
|
424
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
425
|
+
options: The parameter options that are currently selectable
|
|
426
|
+
selected_ids: A sequence of IDs of the selected options
|
|
427
|
+
"""
|
|
428
|
+
_selected_ids: Sequence[str]
|
|
429
|
+
|
|
430
|
+
def __post_init__(self):
|
|
431
|
+
super().__post_init__()
|
|
432
|
+
self._selected_ids = tuple(self._selected_ids)
|
|
433
|
+
for selected_id in self._selected_ids:
|
|
434
|
+
self._validate_selected_id_in_options(selected_id)
|
|
435
|
+
|
|
436
|
+
@staticmethod
|
|
437
|
+
def _ParameterConfigType():
|
|
438
|
+
return pc.MultiSelectParameterConfig
|
|
439
|
+
|
|
440
|
+
@staticmethod
|
|
441
|
+
def _ParameterOptionType():
|
|
442
|
+
return po.SelectParameterOption
|
|
443
|
+
|
|
444
|
+
@staticmethod
|
|
445
|
+
def _DataSourceType():
|
|
446
|
+
return d.SelectDataSource
|
|
447
|
+
|
|
448
|
+
@classmethod
|
|
449
|
+
def CreateWithOptions(
|
|
450
|
+
cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption | dict], *, description: str = "",
|
|
451
|
+
show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
|
|
452
|
+
user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
453
|
+
):
|
|
454
|
+
"""
|
|
455
|
+
Method for creating the configurations for a MultiSelectParameter that may include user attribute or parent
|
|
456
|
+
|
|
457
|
+
Arguments:
|
|
458
|
+
name: The name of the parameter
|
|
459
|
+
label: The display label for the parameter
|
|
460
|
+
all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
|
|
461
|
+
description: Explains the meaning of the parameter
|
|
462
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
463
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
464
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
465
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
466
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
467
|
+
"""
|
|
468
|
+
return super().CreateWithOptions(
|
|
469
|
+
name, label, all_options, description=description, user_attribute=user_attribute, parent_name=parent_name,
|
|
470
|
+
show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
|
|
471
|
+
)
|
|
472
|
+
|
|
473
|
+
@classmethod
|
|
474
|
+
def create_with_options(
|
|
475
|
+
cls, name: str, label: str, *, description: str = "", show_select_all: bool = True, order_matters: bool = False,
|
|
476
|
+
none_is_all: bool = True, user_attribute: str | None = None, parent_name: str | None = None
|
|
477
|
+
):
|
|
478
|
+
"""
|
|
479
|
+
Python decorator for creating the configurations for a MultiSelectParameter that may include user attribute or parent
|
|
480
|
+
|
|
481
|
+
The decorated function must return a list of SelectParameterOption objects.
|
|
482
|
+
|
|
483
|
+
Arguments:
|
|
484
|
+
name: The name of the parameter
|
|
485
|
+
label: The display label for the parameter
|
|
486
|
+
description: Explains the meaning of the parameter
|
|
487
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
488
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
489
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
490
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
491
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
492
|
+
"""
|
|
493
|
+
def decorator(func: Callable[..., Sequence[po.SelectParameterOption]]):
|
|
494
|
+
def wrapper(sqrl: ParametersArgs):
|
|
495
|
+
options = u.call_func(func, sqrl=sqrl)
|
|
496
|
+
return cls.CreateWithOptions(
|
|
497
|
+
name, label, options, description=description, user_attribute=user_attribute, parent_name=parent_name,
|
|
498
|
+
show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
|
|
499
|
+
)
|
|
500
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
501
|
+
return wrapper
|
|
502
|
+
return decorator
|
|
503
|
+
|
|
504
|
+
@classmethod
|
|
505
|
+
def CreateSimple(
|
|
506
|
+
cls, name: str, label: str, all_options: Sequence[po.SelectParameterOption], *, description: str = "",
|
|
507
|
+
show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True, **kwargs
|
|
508
|
+
):
|
|
509
|
+
"""
|
|
510
|
+
Method for creating the configurations for a MultiSelectParameter that doesn't involve user attributes or parent parameters
|
|
511
|
+
|
|
512
|
+
Arguments:
|
|
513
|
+
name: The name of the parameter
|
|
514
|
+
label: The display label for the parameter
|
|
515
|
+
all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
|
|
516
|
+
description: Explains the meaning of the parameter
|
|
517
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
518
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
519
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
520
|
+
"""
|
|
521
|
+
return cls.CreateWithOptions(
|
|
522
|
+
name, label, all_options, description=description,
|
|
523
|
+
show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
@classmethod
|
|
527
|
+
def create_simple(
|
|
528
|
+
cls, name: str, label: str, *, description: str = "",
|
|
529
|
+
show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True
|
|
530
|
+
):
|
|
531
|
+
"""
|
|
532
|
+
Python decorator for creating the configurations for a MultiSelectParameter that doesn't involve user attributes or parent parameters
|
|
533
|
+
|
|
534
|
+
The decorated function must return a list of SelectParameterOption objects.
|
|
535
|
+
|
|
536
|
+
Arguments:
|
|
537
|
+
name: The name of the parameter
|
|
538
|
+
label: The display label for the parameter
|
|
539
|
+
description: Explains the meaning of the parameter
|
|
540
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
541
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
542
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
543
|
+
"""
|
|
544
|
+
def decorator(func: Callable[..., Sequence[po.SelectParameterOption]]):
|
|
545
|
+
def wrapper(sqrl: ParametersArgs):
|
|
546
|
+
options = u.call_func(func, sqrl=sqrl)
|
|
547
|
+
return cls.CreateSimple(
|
|
548
|
+
name, label, options, description=description,
|
|
549
|
+
show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all
|
|
550
|
+
)
|
|
551
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
552
|
+
return wrapper
|
|
553
|
+
return decorator
|
|
554
|
+
|
|
555
|
+
@classmethod
|
|
556
|
+
def CreateFromSource(
|
|
557
|
+
cls, name: str, label: str, data_source: d.SelectDataSource | dict, *, description: str = "",
|
|
558
|
+
show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
|
|
559
|
+
user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
560
|
+
):
|
|
561
|
+
"""
|
|
562
|
+
Method for creating the configurations for a MultiSelectParameter that uses a SelectDataSource to receive the options
|
|
563
|
+
|
|
564
|
+
Arguments:
|
|
565
|
+
name: The name of the parameter
|
|
566
|
+
label: The display label for the parameter
|
|
567
|
+
data_source: The lookup table to use for this parameter
|
|
568
|
+
description: Explains the meaning of the parameter
|
|
569
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
570
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
571
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
572
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
573
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
574
|
+
"""
|
|
575
|
+
extra_args = {
|
|
576
|
+
"show_select_all": show_select_all, "order_matters": order_matters, "none_is_all": none_is_all
|
|
577
|
+
}
|
|
578
|
+
return cls._CreateFromSourceHelper(
|
|
579
|
+
name, label, data_source, extra_args=extra_args, description=description,
|
|
580
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
581
|
+
)
|
|
582
|
+
|
|
583
|
+
@classmethod
|
|
584
|
+
def create_from_source(
|
|
585
|
+
cls, name: str, label: str, *, description: str = "",
|
|
586
|
+
show_select_all: bool = True, order_matters: bool = False, none_is_all: bool = True,
|
|
587
|
+
user_attribute: str | None = None, parent_name: str | None = None
|
|
588
|
+
):
|
|
589
|
+
"""
|
|
590
|
+
Python decorator for creating the configurations for a MultiSelectParameter that uses a SelectDataSource to receive the options from a lookup table
|
|
591
|
+
|
|
592
|
+
The decorated function must return a SelectDataSource object.
|
|
593
|
+
|
|
594
|
+
Arguments:
|
|
595
|
+
name: The name of the parameter
|
|
596
|
+
label: The display label for the parameter
|
|
597
|
+
data_source: The lookup table to use for this parameter
|
|
598
|
+
description: Explains the meaning of the parameter
|
|
599
|
+
show_select_all: Communicate to front-end whether to include a "select all" option
|
|
600
|
+
order_matters: Communicate to front-end whether the order of the selections made matter
|
|
601
|
+
none_is_all: Whether having no options selected is equivalent to all selectable options selected
|
|
602
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
603
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
604
|
+
"""
|
|
605
|
+
def decorator(func: Callable[..., d.SelectDataSource]):
|
|
606
|
+
def wrapper(sqrl: ParametersArgs):
|
|
607
|
+
data_source = u.call_func(func, sqrl=sqrl)
|
|
608
|
+
return cls.CreateFromSource(
|
|
609
|
+
name, label, data_source, description=description,
|
|
610
|
+
show_select_all=show_select_all, order_matters=order_matters, none_is_all=none_is_all,
|
|
611
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
612
|
+
)
|
|
613
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
614
|
+
return wrapper
|
|
615
|
+
return decorator
|
|
616
|
+
|
|
617
|
+
def has_non_empty_selection(self) -> bool:
|
|
618
|
+
"""
|
|
619
|
+
Returns True if more than zero options were selected. False otherwise.
|
|
620
|
+
|
|
621
|
+
Note that even when this returns False, all "get_selected" functions would
|
|
622
|
+
return the full list of options if "include_all" is set to True
|
|
623
|
+
|
|
624
|
+
Returns:
|
|
625
|
+
A boolean
|
|
626
|
+
"""
|
|
627
|
+
return len(self._selected_ids) > 0
|
|
628
|
+
|
|
629
|
+
def get_selected_list(
|
|
630
|
+
self, field: str | None = None, *, default_field: str | None = None, default: Any = None, **kwargs
|
|
631
|
+
) -> Sequence[po.SelectParameterOption | Any]:
|
|
632
|
+
"""
|
|
633
|
+
Gets the sequence of the selected option(s) or a sequence of selected custom fields
|
|
634
|
+
|
|
635
|
+
Arguments:
|
|
636
|
+
field: If field is not None, the method gets this field from the "custom_fields" attribute of the selected options.
|
|
637
|
+
Otherwise, returns the class objects of the selected options
|
|
638
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
639
|
+
as the "field" instead. Does nothing if field is None
|
|
640
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
|
|
641
|
+
is returned as the selected field. Does nothing if field is None or default_field is not None
|
|
642
|
+
|
|
643
|
+
Returns:
|
|
644
|
+
A sequence of SelectParameterOption class objects or sequence of type of custom field
|
|
645
|
+
"""
|
|
646
|
+
if not self.has_non_empty_selection() and self._config.none_is_all:
|
|
647
|
+
selected_list = self._options
|
|
648
|
+
else:
|
|
649
|
+
selected_list = (x for x in self._options if x._identifier in self._selected_ids)
|
|
650
|
+
|
|
651
|
+
if field is not None:
|
|
652
|
+
selected_list = [selected.get_custom_field(field, default_field=default_field, default=default) for selected in selected_list]
|
|
653
|
+
|
|
654
|
+
return tuple(selected_list)
|
|
655
|
+
|
|
656
|
+
def _get_selected_list_of_strings(
|
|
657
|
+
self, method: str, field: str, default_field: str | None, default: str | None, **kwargs
|
|
658
|
+
) -> list[str]:
|
|
659
|
+
selected_list = self.get_selected_list(field, default_field=default_field, default=default)
|
|
660
|
+
list_of_strings: list[str] = []
|
|
661
|
+
for selected in selected_list:
|
|
662
|
+
if not isinstance(selected, str):
|
|
663
|
+
raise u.ConfigurationError(
|
|
664
|
+
f"Method '{method}' can only be used on fields with only string values"
|
|
665
|
+
)
|
|
666
|
+
list_of_strings.append(selected)
|
|
667
|
+
return list_of_strings
|
|
668
|
+
|
|
669
|
+
def get_selected_list_joined(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str:
|
|
670
|
+
"""
|
|
671
|
+
Gets the selected custom fields joined by comma
|
|
672
|
+
|
|
673
|
+
Arguments:
|
|
674
|
+
field: The "custom_fields" attribute of the selected options.
|
|
675
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
676
|
+
as the "field" instead.
|
|
677
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
|
|
678
|
+
is returned as the selected field. Does nothing if default_field is not None
|
|
679
|
+
|
|
680
|
+
Returns:
|
|
681
|
+
A string
|
|
682
|
+
"""
|
|
683
|
+
list_of_strings = self._get_selected_list_of_strings("get_selected_list_joined", field, default_field, default)
|
|
684
|
+
return ','.join(list_of_strings)
|
|
685
|
+
|
|
686
|
+
def get_selected_list_quoted(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> tuple[str, ...]:
|
|
687
|
+
"""
|
|
688
|
+
Gets the selected custom fields surrounded by single quotes
|
|
689
|
+
|
|
690
|
+
Arguments:
|
|
691
|
+
field: The "custom_fields" attribute of the selected options.
|
|
692
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
693
|
+
as the "field" instead.
|
|
694
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
|
|
695
|
+
is returned as the selected field. Does nothing if default_field is not None
|
|
696
|
+
|
|
697
|
+
Returns:
|
|
698
|
+
A tuple of strings
|
|
699
|
+
"""
|
|
700
|
+
list_of_strings = self._get_selected_list_of_strings("get_selected_list_quoted", field, default_field, default)
|
|
701
|
+
return tuple(self._enquote(x) for x in list_of_strings)
|
|
702
|
+
|
|
703
|
+
def get_selected_list_quoted_joined(self, field: str, *, default_field: str | None = None, default: str | None = None, **kwargs) -> str:
|
|
704
|
+
"""
|
|
705
|
+
Gets the selected custom fields surrounded by single quotes and joined by comma
|
|
706
|
+
|
|
707
|
+
Arguments:
|
|
708
|
+
field: The "custom_fields" attribute of the selected options.
|
|
709
|
+
default_field: If field does not exist for a parameter option and default_field is not None, the default_field is used
|
|
710
|
+
as the "field" instead.
|
|
711
|
+
default: If field does not exist for a parameter option, default_field is None, but default is not None, the default
|
|
712
|
+
is returned as the selected field. Does nothing if default_field is not None
|
|
713
|
+
|
|
714
|
+
Returns:
|
|
715
|
+
A string
|
|
716
|
+
"""
|
|
717
|
+
list_of_strings = self._get_selected_list_of_strings("get_selected_list_quoted_joined", field, default_field, default)
|
|
718
|
+
return ','.join(self._enquote(x) for x in list_of_strings)
|
|
719
|
+
|
|
720
|
+
def get_selected_ids_as_list(self, **kwargs) -> Sequence[str]:
|
|
721
|
+
"""
|
|
722
|
+
Gets the sequence of ID(s) of the selected option(s)
|
|
723
|
+
|
|
724
|
+
Returns:
|
|
725
|
+
A sequence of strings
|
|
726
|
+
"""
|
|
727
|
+
return tuple(x._identifier for x in self.get_selected_list())
|
|
728
|
+
|
|
729
|
+
def get_selected_ids_joined(self, **kwargs) -> str:
|
|
730
|
+
"""
|
|
731
|
+
Gets the ID(s) of the selected option(s) joined by comma
|
|
732
|
+
|
|
733
|
+
Returns:
|
|
734
|
+
A string
|
|
735
|
+
"""
|
|
736
|
+
return ','.join(self.get_selected_ids_as_list())
|
|
737
|
+
|
|
738
|
+
def get_selected_ids_quoted_as_list(self, **kwargs) -> Sequence[str]:
|
|
739
|
+
"""
|
|
740
|
+
Gets the sequence of ID(s) of the selected option(s) surrounded by single quotes
|
|
741
|
+
|
|
742
|
+
Returns:
|
|
743
|
+
A sequence of strings
|
|
744
|
+
"""
|
|
745
|
+
return tuple(self._enquote(x) for x in self.get_selected_ids_as_list())
|
|
746
|
+
|
|
747
|
+
def get_selected_ids_quoted_joined(self, **kwargs) -> str:
|
|
748
|
+
"""
|
|
749
|
+
Gets the ID(s) of the selected option(s) surrounded by single quotes and joined by comma
|
|
750
|
+
|
|
751
|
+
Returns:
|
|
752
|
+
A string
|
|
753
|
+
"""
|
|
754
|
+
return ','.join(self.get_selected_ids_quoted_as_list())
|
|
755
|
+
|
|
756
|
+
def get_selected_labels_as_list(self, **kwargs) -> Sequence[str]:
|
|
757
|
+
"""
|
|
758
|
+
Gets the sequence of label(s) of the selected option(s)
|
|
759
|
+
|
|
760
|
+
Returns:
|
|
761
|
+
A sequence of strings
|
|
762
|
+
"""
|
|
763
|
+
return tuple(x._label for x in self.get_selected_list())
|
|
764
|
+
|
|
765
|
+
def get_selected_labels_joined(self, **kwargs) -> str:
|
|
766
|
+
"""
|
|
767
|
+
Gets the label(s) of the selected option(s) joined by comma
|
|
768
|
+
|
|
769
|
+
Returns:
|
|
770
|
+
A string
|
|
771
|
+
"""
|
|
772
|
+
return ','.join(self.get_selected_labels_as_list())
|
|
773
|
+
|
|
774
|
+
def get_selected_labels_quoted_as_list(self, **kwargs) -> Sequence[str]:
|
|
775
|
+
"""
|
|
776
|
+
Gets the sequence of label(s) of the selected option(s) surrounded by single quotes
|
|
777
|
+
|
|
778
|
+
Returns:
|
|
779
|
+
A sequence of strings
|
|
780
|
+
"""
|
|
781
|
+
return tuple(self._enquote(x) for x in self.get_selected_labels_as_list())
|
|
782
|
+
|
|
783
|
+
def get_selected_labels_quoted_joined(self, **kwargs) -> str:
|
|
784
|
+
"""
|
|
785
|
+
Gets the label(s) of the selected option(s) surrounded by single quotes and joined by comma
|
|
786
|
+
|
|
787
|
+
Returns:
|
|
788
|
+
A string
|
|
789
|
+
"""
|
|
790
|
+
return ','.join(self.get_selected_labels_quoted_as_list())
|
|
791
|
+
|
|
792
|
+
def _get_selected_ids_as_list(self, **kwargs) -> Sequence[str]:
|
|
793
|
+
return self.get_selected_ids_as_list()
|
|
794
|
+
|
|
795
|
+
def _to_json_dict0(self):
|
|
796
|
+
"""
|
|
797
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
798
|
+
|
|
799
|
+
Returns:
|
|
800
|
+
A dictionary for the JSON object
|
|
801
|
+
"""
|
|
802
|
+
output = super()._to_json_dict0()
|
|
803
|
+
output['show_select_all'] = self._config.show_select_all
|
|
804
|
+
output['order_matters'] = self._config.order_matters
|
|
805
|
+
output['selected_ids'] = list(self._selected_ids)
|
|
806
|
+
return output
|
|
807
|
+
|
|
808
|
+
def _get_response_model0(self):
|
|
809
|
+
return rm.MultiSelectParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
810
|
+
|
|
811
|
+
|
|
812
|
+
DatePO = TypeVar("DatePO", bound=po._DateTypeParameterOption)
|
|
813
|
+
|
|
814
|
+
@dataclass
|
|
815
|
+
class _DateTypeParameter(Parameter[PC, DatePO, DS], Generic[PC, DatePO, DS]):
|
|
816
|
+
_curr_option: DatePO | None
|
|
817
|
+
|
|
818
|
+
def is_enabled(self) -> bool:
|
|
819
|
+
return self._curr_option is not None
|
|
820
|
+
|
|
821
|
+
def _cast_optional_date_to_str(self, date: date | None) -> str | None:
|
|
822
|
+
return None if date is None else date.strftime("%Y-%m-%d")
|
|
823
|
+
|
|
824
|
+
def _to_json_dict0(self):
|
|
825
|
+
output = super()._to_json_dict0()
|
|
826
|
+
if self._curr_option is not None:
|
|
827
|
+
output["min_date"] = self._cast_optional_date_to_str(self._curr_option._min_date)
|
|
828
|
+
output["max_date"] = self._cast_optional_date_to_str(self._curr_option._max_date)
|
|
829
|
+
return output
|
|
830
|
+
|
|
831
|
+
|
|
832
|
+
@dataclass
|
|
833
|
+
class DateParameter(_DateTypeParameter[pc.DateParameterConfig, po.DateParameterOption, d.DateDataSource]):
|
|
834
|
+
"""
|
|
835
|
+
Class for date parameter widgets.
|
|
836
|
+
|
|
837
|
+
Attributes:
|
|
838
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
839
|
+
curr_option: The current option showing for defaults based on user attribute and selection of parent
|
|
840
|
+
selected_date: The selected date
|
|
841
|
+
"""
|
|
842
|
+
_selected_date: date | str | None
|
|
843
|
+
|
|
844
|
+
def __post_init__(self):
|
|
845
|
+
if self._curr_option is not None and self._selected_date is not None:
|
|
846
|
+
self._selected_date = self._validate_input_date(self._selected_date, self._curr_option)
|
|
847
|
+
|
|
848
|
+
def is_enabled(self) -> bool:
|
|
849
|
+
return self._curr_option is not None
|
|
850
|
+
|
|
851
|
+
@staticmethod
|
|
852
|
+
def _ParameterConfigType():
|
|
853
|
+
return pc.DateParameterConfig
|
|
854
|
+
|
|
855
|
+
@staticmethod
|
|
856
|
+
def _ParameterOptionType():
|
|
857
|
+
return po.DateParameterOption
|
|
858
|
+
|
|
859
|
+
@staticmethod
|
|
860
|
+
def _DataSourceType():
|
|
861
|
+
return d.DateDataSource
|
|
862
|
+
|
|
863
|
+
@classmethod
|
|
864
|
+
def CreateSimple(
|
|
865
|
+
cls, name: str, label: str, default_date: str | date, *, description: str = "",
|
|
866
|
+
min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d', **kwargs
|
|
867
|
+
):
|
|
868
|
+
"""
|
|
869
|
+
Method for creating the configurations for a DateParameter that doesn't involve user attributes or parent parameters
|
|
870
|
+
|
|
871
|
+
Arguments:
|
|
872
|
+
name: The name of the parameter
|
|
873
|
+
label: The display label for the parameter
|
|
874
|
+
default_date: Default date for this option
|
|
875
|
+
description: Explains the meaning of the parameter
|
|
876
|
+
min_date: Minimum selectable date
|
|
877
|
+
max_date: Maximum selectable date
|
|
878
|
+
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
879
|
+
"""
|
|
880
|
+
single_param_option = po.DateParameterOption(default_date, min_date=min_date, max_date=max_date, date_format=date_format)
|
|
881
|
+
return cls.CreateWithOptions(name, label, (single_param_option,), description=description)
|
|
882
|
+
|
|
883
|
+
@classmethod
|
|
884
|
+
def create_simple(
|
|
885
|
+
cls, name: str, label: str, default_date: str | date, *, description: str = "",
|
|
886
|
+
min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d'
|
|
887
|
+
):
|
|
888
|
+
"""
|
|
889
|
+
Python decorator for creating the configurations for a DateParameter that doesn't involve user attributes or parent parameters
|
|
890
|
+
|
|
891
|
+
Arguments:
|
|
892
|
+
name: The name of the parameter
|
|
893
|
+
label: The display label for the parameter
|
|
894
|
+
default_date: Default date for this option
|
|
895
|
+
description: Explains the meaning of the parameter
|
|
896
|
+
min_date: Minimum selectable date
|
|
897
|
+
max_date: Maximum selectable date
|
|
898
|
+
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
899
|
+
"""
|
|
900
|
+
def decorator(func: Callable[..., Any]):
|
|
901
|
+
def wrapper(sqrl: ParametersArgs):
|
|
902
|
+
return cls.CreateSimple(
|
|
903
|
+
name, label, default_date, description=description,
|
|
904
|
+
min_date=min_date, max_date=max_date, date_format=date_format
|
|
905
|
+
)
|
|
906
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
907
|
+
return wrapper
|
|
908
|
+
return decorator
|
|
909
|
+
|
|
910
|
+
def get_selected_date(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
911
|
+
"""
|
|
912
|
+
Gets selected date as string
|
|
913
|
+
|
|
914
|
+
Arguments:
|
|
915
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
916
|
+
|
|
917
|
+
Returns:
|
|
918
|
+
A string
|
|
919
|
+
"""
|
|
920
|
+
assert self._curr_option is not None and isinstance(self._selected_date, date), "Parameter is not enabled"
|
|
921
|
+
date_format = self._curr_option._date_format if date_format is None else date_format
|
|
922
|
+
return self._selected_date.strftime(date_format)
|
|
923
|
+
|
|
924
|
+
def get_selected_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
925
|
+
"""
|
|
926
|
+
Gets selected date as string surrounded by single quotes
|
|
927
|
+
|
|
928
|
+
Arguments:
|
|
929
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
930
|
+
|
|
931
|
+
Returns:
|
|
932
|
+
A string
|
|
933
|
+
"""
|
|
934
|
+
return self._enquote(self.get_selected_date(date_format=date_format))
|
|
935
|
+
|
|
936
|
+
def _to_json_dict0(self):
|
|
937
|
+
"""
|
|
938
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
939
|
+
|
|
940
|
+
The "selected_date" field will always be in yyyy-mm-dd format
|
|
941
|
+
|
|
942
|
+
Returns:
|
|
943
|
+
A dictionary for the JSON object
|
|
944
|
+
"""
|
|
945
|
+
output = super()._to_json_dict0()
|
|
946
|
+
if self.is_enabled():
|
|
947
|
+
output["selected_date"] = self.get_selected_date(date_format="%Y-%m-%d")
|
|
948
|
+
else:
|
|
949
|
+
output["selected_date"] = ""
|
|
950
|
+
return output
|
|
951
|
+
|
|
952
|
+
def _get_response_model0(self):
|
|
953
|
+
return rm.DateParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
954
|
+
|
|
955
|
+
|
|
956
|
+
@dataclass
|
|
957
|
+
class DateRangeParameter(_DateTypeParameter[pc.DateRangeParameterConfig, po.DateRangeParameterOption, d.DateRangeDataSource]):
|
|
958
|
+
"""
|
|
959
|
+
Class for date range parameter widgets.
|
|
960
|
+
|
|
961
|
+
Attributes:
|
|
962
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
963
|
+
curr_option: The current option showing for defaults based on user attribute and selection of parent
|
|
964
|
+
selected_start_date: The selected start date
|
|
965
|
+
selected_end_date: The selected end date
|
|
966
|
+
"""
|
|
967
|
+
_selected_start_date: date | str | None
|
|
968
|
+
_selected_end_date: date | str | None
|
|
969
|
+
|
|
970
|
+
def __post_init__(self):
|
|
971
|
+
if self._curr_option is not None:
|
|
972
|
+
if self._selected_start_date is not None:
|
|
973
|
+
self._selected_start_date = self._validate_input_date(self._selected_start_date, self._curr_option)
|
|
974
|
+
if self._selected_end_date is not None:
|
|
975
|
+
self._selected_end_date = self._validate_input_date(self._selected_end_date, self._curr_option)
|
|
976
|
+
|
|
977
|
+
def is_enabled(self) -> bool:
|
|
978
|
+
return self._curr_option is not None
|
|
979
|
+
|
|
980
|
+
@staticmethod
|
|
981
|
+
def _ParameterConfigType():
|
|
982
|
+
return pc.DateRangeParameterConfig
|
|
983
|
+
|
|
984
|
+
@staticmethod
|
|
985
|
+
def _ParameterOptionType():
|
|
986
|
+
return po.DateRangeParameterOption
|
|
987
|
+
|
|
988
|
+
@staticmethod
|
|
989
|
+
def _DataSourceType():
|
|
990
|
+
return d.DateRangeDataSource
|
|
991
|
+
|
|
992
|
+
@classmethod
|
|
993
|
+
def CreateSimple(
|
|
994
|
+
cls, name: str, label: str, default_start_date: str | date, default_end_date: str | date, *, description: str = "",
|
|
995
|
+
min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d', **kwargs
|
|
996
|
+
):
|
|
997
|
+
"""
|
|
998
|
+
Method for creating the configurations for a DateRangeParameter that doesn't involve user attributes or parent parameters
|
|
999
|
+
|
|
1000
|
+
Arguments:
|
|
1001
|
+
name: The name of the parameter
|
|
1002
|
+
label: The display label for the parameter
|
|
1003
|
+
default_start_date: Default start date for this option
|
|
1004
|
+
default_end_date: Default end date for this option
|
|
1005
|
+
description: Explains the meaning of the parameter
|
|
1006
|
+
min_date: Minimum selectable date
|
|
1007
|
+
max_date: Maximum selectable date
|
|
1008
|
+
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
1009
|
+
"""
|
|
1010
|
+
single_param_option = po.DateRangeParameterOption(
|
|
1011
|
+
default_start_date, default_end_date, min_date=min_date, max_date=max_date, date_format=date_format
|
|
1012
|
+
)
|
|
1013
|
+
return cls.CreateWithOptions(name, label, (single_param_option,), description=description)
|
|
1014
|
+
|
|
1015
|
+
@classmethod
|
|
1016
|
+
def create_simple(
|
|
1017
|
+
cls, name: str, label: str, default_start_date: str | date, default_end_date: str | date, *, description: str = "",
|
|
1018
|
+
min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d'
|
|
1019
|
+
):
|
|
1020
|
+
"""
|
|
1021
|
+
Python decorator for creating the configurations for a DateRangeParameter that doesn't involve user attributes or parent parameters
|
|
1022
|
+
|
|
1023
|
+
Arguments:
|
|
1024
|
+
name: The name of the parameter
|
|
1025
|
+
label: The display label for the parameter
|
|
1026
|
+
default_start_date: Default start date for this option
|
|
1027
|
+
default_end_date: Default end date for this option
|
|
1028
|
+
description: Explains the meaning of the parameter
|
|
1029
|
+
min_date: Minimum selectable date
|
|
1030
|
+
max_date: Maximum selectable date
|
|
1031
|
+
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
1032
|
+
"""
|
|
1033
|
+
def decorator(func: Callable[..., Any]):
|
|
1034
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1035
|
+
return cls.CreateSimple(
|
|
1036
|
+
name, label, default_start_date, default_end_date, description=description,
|
|
1037
|
+
min_date=min_date, max_date=max_date, date_format=date_format
|
|
1038
|
+
)
|
|
1039
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1040
|
+
return wrapper
|
|
1041
|
+
return decorator
|
|
1042
|
+
|
|
1043
|
+
def get_selected_start_date(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
1044
|
+
"""
|
|
1045
|
+
Gets selected start date as string
|
|
1046
|
+
|
|
1047
|
+
Arguments:
|
|
1048
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
1049
|
+
|
|
1050
|
+
Returns:
|
|
1051
|
+
A string
|
|
1052
|
+
"""
|
|
1053
|
+
assert self._curr_option is not None and isinstance(self._selected_start_date, date), "Parameter is not enabled"
|
|
1054
|
+
date_format = self._curr_option._date_format if date_format is None else date_format
|
|
1055
|
+
return self._selected_start_date.strftime(date_format)
|
|
1056
|
+
|
|
1057
|
+
def get_selected_start_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
1058
|
+
"""
|
|
1059
|
+
Gets selected start date as string surrounded by single quotes
|
|
1060
|
+
|
|
1061
|
+
Arguments:
|
|
1062
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
1063
|
+
|
|
1064
|
+
Returns:
|
|
1065
|
+
A string
|
|
1066
|
+
"""
|
|
1067
|
+
return self._enquote(self.get_selected_start_date(date_format=date_format))
|
|
1068
|
+
|
|
1069
|
+
def get_selected_end_date(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
1070
|
+
"""
|
|
1071
|
+
Gets selected end date as string
|
|
1072
|
+
|
|
1073
|
+
Arguments:
|
|
1074
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
1075
|
+
|
|
1076
|
+
Returns:
|
|
1077
|
+
A string
|
|
1078
|
+
"""
|
|
1079
|
+
assert self._curr_option is not None and isinstance(self._selected_end_date, date), "Parameter is not enabled"
|
|
1080
|
+
date_format = self._curr_option._date_format if date_format is None else date_format
|
|
1081
|
+
return self._selected_end_date.strftime(date_format)
|
|
1082
|
+
|
|
1083
|
+
def get_selected_end_date_quoted(self, *, date_format: str | None = None, **kwargs) -> str:
|
|
1084
|
+
"""
|
|
1085
|
+
Gets selected end date as string surrounded by single quotes
|
|
1086
|
+
|
|
1087
|
+
Arguments:
|
|
1088
|
+
date_format: The date format (see Python's datetime formats). If not specified, self.date_format is used
|
|
1089
|
+
|
|
1090
|
+
Returns:
|
|
1091
|
+
A string
|
|
1092
|
+
"""
|
|
1093
|
+
return self._enquote(self.get_selected_end_date(date_format=date_format))
|
|
1094
|
+
|
|
1095
|
+
def _to_json_dict0(self):
|
|
1096
|
+
"""
|
|
1097
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
1098
|
+
|
|
1099
|
+
The "selected_date" field will always be in yyyy-mm-dd format
|
|
1100
|
+
|
|
1101
|
+
Returns:
|
|
1102
|
+
A dictionary for the JSON object
|
|
1103
|
+
"""
|
|
1104
|
+
output = super()._to_json_dict0()
|
|
1105
|
+
if self.is_enabled():
|
|
1106
|
+
output["selected_start_date"] = self.get_selected_start_date(date_format="%Y-%m-%d")
|
|
1107
|
+
output["selected_end_date"] = self.get_selected_end_date(date_format="%Y-%m-%d")
|
|
1108
|
+
return output
|
|
1109
|
+
|
|
1110
|
+
def _get_response_model0(self):
|
|
1111
|
+
return rm.DateRangeParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
1112
|
+
|
|
1113
|
+
|
|
1114
|
+
NumericPO = TypeVar("NumericPO", bound=po._NumericParameterOption)
|
|
1115
|
+
|
|
1116
|
+
@dataclass
|
|
1117
|
+
class _NumberTypeParameter(Parameter[PC, NumericPO, DS], Generic[PC, NumericPO, DS]):
|
|
1118
|
+
_curr_option: NumericPO | None
|
|
1119
|
+
|
|
1120
|
+
def is_enabled(self) -> bool:
|
|
1121
|
+
return self._curr_option is not None
|
|
1122
|
+
|
|
1123
|
+
def _to_json_dict0(self):
|
|
1124
|
+
output = super()._to_json_dict0()
|
|
1125
|
+
if self._curr_option is not None:
|
|
1126
|
+
output["min_value"] = float(self._curr_option._min_value)
|
|
1127
|
+
output["max_value"] = float(self._curr_option._max_value)
|
|
1128
|
+
output["increment"] = float(self._curr_option._increment)
|
|
1129
|
+
return output
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
@dataclass
|
|
1133
|
+
class NumberParameter(_NumberTypeParameter[pc.NumberParameterConfig, po.NumberParameterOption, d.NumberDataSource]):
|
|
1134
|
+
"""
|
|
1135
|
+
Class for number parameter widgets.
|
|
1136
|
+
|
|
1137
|
+
Attributes:
|
|
1138
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
1139
|
+
curr_option: The current option showing for defaults based on user attribute and selection of parent
|
|
1140
|
+
selected_value: The selected integer or decimal number
|
|
1141
|
+
"""
|
|
1142
|
+
_selected_value: po.Number | None
|
|
1143
|
+
|
|
1144
|
+
def __post_init__(self):
|
|
1145
|
+
if self._curr_option is not None and self._selected_value is not None:
|
|
1146
|
+
self._selected_value = self._validate_number(self._selected_value, self._curr_option)
|
|
1147
|
+
|
|
1148
|
+
@staticmethod
|
|
1149
|
+
def _ParameterConfigType():
|
|
1150
|
+
return pc.NumberParameterConfig
|
|
1151
|
+
|
|
1152
|
+
@staticmethod
|
|
1153
|
+
def _ParameterOptionType():
|
|
1154
|
+
return po.NumberParameterOption
|
|
1155
|
+
|
|
1156
|
+
@staticmethod
|
|
1157
|
+
def _DataSourceType():
|
|
1158
|
+
return d.NumberDataSource
|
|
1159
|
+
|
|
1160
|
+
@classmethod
|
|
1161
|
+
def CreateSimple(
|
|
1162
|
+
cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
|
|
1163
|
+
increment: po.Number = 1, default_value: po.Number | None = None, **kwargs
|
|
1164
|
+
):
|
|
1165
|
+
"""
|
|
1166
|
+
Method for creating the configurations for a NumberParameter that doesn't involve user attributes or parent parameters
|
|
1167
|
+
|
|
1168
|
+
* Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
|
|
1169
|
+
|
|
1170
|
+
Arguments:
|
|
1171
|
+
name: The name of the parameter
|
|
1172
|
+
label: The display label for the parameter
|
|
1173
|
+
min_value: Minimum selectable value
|
|
1174
|
+
max_value: Maximum selectable value
|
|
1175
|
+
description: Explains the meaning of the parameter
|
|
1176
|
+
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
1177
|
+
default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
|
|
1178
|
+
"""
|
|
1179
|
+
single_param_option = po.NumberParameterOption(min_value, max_value, increment=increment, default_value=default_value)
|
|
1180
|
+
return cls.CreateWithOptions(name, label, (single_param_option,), description=description)
|
|
1181
|
+
|
|
1182
|
+
@classmethod
|
|
1183
|
+
def create_simple(
|
|
1184
|
+
cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
|
|
1185
|
+
increment: po.Number = 1, default_value: po.Number | None = None
|
|
1186
|
+
):
|
|
1187
|
+
"""
|
|
1188
|
+
Python decorator for creating the configurations for a NumberParameter that doesn't involve user attributes or parent parameters
|
|
1189
|
+
|
|
1190
|
+
* Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
|
|
1191
|
+
|
|
1192
|
+
Arguments:
|
|
1193
|
+
name: The name of the parameter
|
|
1194
|
+
label: The display label for the parameter
|
|
1195
|
+
min_value: Minimum selectable value
|
|
1196
|
+
max_value: Maximum selectable value
|
|
1197
|
+
description: Explains the meaning of the parameter
|
|
1198
|
+
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
1199
|
+
default_value: Default value for the parameter
|
|
1200
|
+
"""
|
|
1201
|
+
def decorator(func: Callable[..., Any]):
|
|
1202
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1203
|
+
return cls.CreateSimple(
|
|
1204
|
+
name, label, min_value, max_value, description=description, increment=increment, default_value=default_value
|
|
1205
|
+
)
|
|
1206
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1207
|
+
return wrapper
|
|
1208
|
+
return decorator
|
|
1209
|
+
|
|
1210
|
+
def get_selected_value(self, **kwargs) -> float:
|
|
1211
|
+
"""
|
|
1212
|
+
Get the selected number (converted from Decimal to float)
|
|
1213
|
+
|
|
1214
|
+
Returns:
|
|
1215
|
+
float
|
|
1216
|
+
"""
|
|
1217
|
+
assert self._selected_value is not None, "Parameter is not enabled"
|
|
1218
|
+
return float(self._selected_value)
|
|
1219
|
+
|
|
1220
|
+
def _to_json_dict0(self):
|
|
1221
|
+
"""
|
|
1222
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
1223
|
+
|
|
1224
|
+
Returns:
|
|
1225
|
+
A dictionary for the JSON object
|
|
1226
|
+
"""
|
|
1227
|
+
output = super()._to_json_dict0()
|
|
1228
|
+
if self.is_enabled():
|
|
1229
|
+
output["selected_value"] = self.get_selected_value()
|
|
1230
|
+
return output
|
|
1231
|
+
|
|
1232
|
+
def _get_response_model0(self):
|
|
1233
|
+
return rm.NumberParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
1234
|
+
|
|
1235
|
+
|
|
1236
|
+
@dataclass
|
|
1237
|
+
class NumberRangeParameter(_NumberTypeParameter[pc.NumberRangeParameterConfig, po.NumberRangeParameterOption, d.NumberRangeDataSource]):
|
|
1238
|
+
"""
|
|
1239
|
+
Class for number range parameter widgets.
|
|
1240
|
+
|
|
1241
|
+
Attributes:
|
|
1242
|
+
config: The config for this widget parameter (for immutable attributes like name, label, all possible options, etc)
|
|
1243
|
+
curr_option: The current option showing for defaults based on user attribute and selection of parent
|
|
1244
|
+
selected_lower_value: The selected lower integer or decimal number
|
|
1245
|
+
selected_upper_value: The selected upper integer or decimal number
|
|
1246
|
+
"""
|
|
1247
|
+
_selected_lower_value: po.Number | None
|
|
1248
|
+
_selected_upper_value: po.Number | None
|
|
1249
|
+
|
|
1250
|
+
def __post_init__(self):
|
|
1251
|
+
if self._curr_option is not None:
|
|
1252
|
+
if self._selected_lower_value is not None:
|
|
1253
|
+
self._selected_lower_value = self._validate_number(self._selected_lower_value, self._curr_option)
|
|
1254
|
+
if self._selected_upper_value is not None:
|
|
1255
|
+
self._selected_upper_value = self._validate_number(self._selected_upper_value, self._curr_option)
|
|
1256
|
+
|
|
1257
|
+
@staticmethod
|
|
1258
|
+
def _ParameterConfigType():
|
|
1259
|
+
return pc.NumberRangeParameterConfig
|
|
1260
|
+
|
|
1261
|
+
@staticmethod
|
|
1262
|
+
def _ParameterOptionType():
|
|
1263
|
+
return po.NumberRangeParameterOption
|
|
1264
|
+
|
|
1265
|
+
@staticmethod
|
|
1266
|
+
def _DataSourceType():
|
|
1267
|
+
return d.NumberRangeDataSource
|
|
1268
|
+
|
|
1269
|
+
@classmethod
|
|
1270
|
+
def CreateSimple(
|
|
1271
|
+
cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
|
|
1272
|
+
increment: po.Number = 1, default_lower_value: po.Number | None = None, default_upper_value: po.Number | None = None,**kwargs
|
|
1273
|
+
):
|
|
1274
|
+
"""
|
|
1275
|
+
Method for creating the configurations for a NumberRangeParameter that doesn't involve user attributes or parent parameters
|
|
1276
|
+
|
|
1277
|
+
* Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
|
|
1278
|
+
|
|
1279
|
+
Arguments:
|
|
1280
|
+
name: The name of the parameter
|
|
1281
|
+
label: The display label for the parameter
|
|
1282
|
+
min_value: Minimum selectable value
|
|
1283
|
+
max_value: Maximum selectable value
|
|
1284
|
+
description: Explains the meaning of the parameter
|
|
1285
|
+
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
1286
|
+
default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
|
|
1287
|
+
default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
|
|
1288
|
+
Must also be greater than default_lower_value
|
|
1289
|
+
"""
|
|
1290
|
+
single_param_option = po.NumberRangeParameterOption(
|
|
1291
|
+
min_value, max_value, increment=increment, default_lower_value=default_lower_value, default_upper_value=default_upper_value
|
|
1292
|
+
)
|
|
1293
|
+
return cls.CreateWithOptions(name, label, (single_param_option,), description=description)
|
|
1294
|
+
|
|
1295
|
+
@classmethod
|
|
1296
|
+
def create_simple(
|
|
1297
|
+
cls, name: str, label: str, min_value: po.Number, max_value: po.Number, *, description: str = "",
|
|
1298
|
+
increment: po.Number = 1, default_lower_value: po.Number | None = None, default_upper_value: po.Number | None = None
|
|
1299
|
+
):
|
|
1300
|
+
"""
|
|
1301
|
+
Python decorator for creating the configurations for a NumberRangeParameter that doesn't involve user attributes or parent parameters
|
|
1302
|
+
|
|
1303
|
+
* Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
|
|
1304
|
+
|
|
1305
|
+
Arguments:
|
|
1306
|
+
name: The name of the parameter
|
|
1307
|
+
label: The display label for the parameter
|
|
1308
|
+
min_value: Minimum selectable value
|
|
1309
|
+
max_value: Maximum selectable value
|
|
1310
|
+
description: Explains the meaning of the parameter
|
|
1311
|
+
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
1312
|
+
default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
|
|
1313
|
+
default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
|
|
1314
|
+
Must also be greater than default_lower_value
|
|
1315
|
+
"""
|
|
1316
|
+
def decorator(func: Callable[..., Any]):
|
|
1317
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1318
|
+
return cls.CreateSimple(
|
|
1319
|
+
name, label, min_value, max_value, description=description, increment=increment,
|
|
1320
|
+
default_lower_value=default_lower_value, default_upper_value=default_upper_value
|
|
1321
|
+
)
|
|
1322
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1323
|
+
return wrapper
|
|
1324
|
+
return decorator
|
|
1325
|
+
|
|
1326
|
+
def get_selected_lower_value(self, **kwargs) -> float:
|
|
1327
|
+
"""
|
|
1328
|
+
Get the selected lower value number (converted from Decimal to float)
|
|
1329
|
+
|
|
1330
|
+
Returns:
|
|
1331
|
+
float
|
|
1332
|
+
"""
|
|
1333
|
+
assert self._selected_lower_value is not None, "Parameter is not enabled"
|
|
1334
|
+
return float(self._selected_lower_value)
|
|
1335
|
+
|
|
1336
|
+
def get_selected_upper_value(self, **kwargs) -> float:
|
|
1337
|
+
"""
|
|
1338
|
+
Get the selected upper value number (converted from Decimal to float)
|
|
1339
|
+
|
|
1340
|
+
Returns:
|
|
1341
|
+
float
|
|
1342
|
+
"""
|
|
1343
|
+
assert self._selected_upper_value is not None, "Parameter is not enabled"
|
|
1344
|
+
return float(self._selected_upper_value)
|
|
1345
|
+
|
|
1346
|
+
def _to_json_dict0(self):
|
|
1347
|
+
"""
|
|
1348
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
1349
|
+
|
|
1350
|
+
Returns:
|
|
1351
|
+
A dictionary for the JSON object
|
|
1352
|
+
"""
|
|
1353
|
+
output = super()._to_json_dict0()
|
|
1354
|
+
if self.is_enabled():
|
|
1355
|
+
output['selected_lower_value'] = self.get_selected_lower_value()
|
|
1356
|
+
output['selected_upper_value'] = self.get_selected_upper_value()
|
|
1357
|
+
return output
|
|
1358
|
+
|
|
1359
|
+
def _get_response_model0(self):
|
|
1360
|
+
return rm.NumberRangeParameterModel if self.is_enabled() else rm.NoneParameterModel
|
|
1361
|
+
|
|
1362
|
+
|
|
1363
|
+
@dataclass
|
|
1364
|
+
class TextValue:
|
|
1365
|
+
_value_do_not_touch: str
|
|
1366
|
+
|
|
1367
|
+
def __repr__(self):
|
|
1368
|
+
raise u.ConfigurationError(
|
|
1369
|
+
"Cannot convert TextValue directly to string (to avoid SQL injection). Try using it through placeholders instead"
|
|
1370
|
+
)
|
|
1371
|
+
|
|
1372
|
+
def apply(self, str_to_str_function: Callable[[str], str]) -> TextValue:
|
|
1373
|
+
"""
|
|
1374
|
+
Transforms the entered text with a function that takes a string and returns a string.
|
|
1375
|
+
|
|
1376
|
+
This method returns a new object and leaves the original the same.
|
|
1377
|
+
|
|
1378
|
+
Arguments:
|
|
1379
|
+
str_to_str_function: A function that accepts a string and returns a string
|
|
1380
|
+
|
|
1381
|
+
Returns:
|
|
1382
|
+
A new TextValue with the transformed entered text
|
|
1383
|
+
"""
|
|
1384
|
+
new_value = str_to_str_function(self._value_do_not_touch)
|
|
1385
|
+
if not isinstance(new_value, str):
|
|
1386
|
+
raise u.ConfigurationError("Function provided must return string")
|
|
1387
|
+
return TextValue(new_value)
|
|
1388
|
+
|
|
1389
|
+
def apply_percent_wrap(self) -> TextValue:
|
|
1390
|
+
"""
|
|
1391
|
+
Adds percent signs before and after the entered text, and returns a new object, leaving the original the same.
|
|
1392
|
+
|
|
1393
|
+
Returns:
|
|
1394
|
+
A new TextValue with the transformed entered text
|
|
1395
|
+
"""
|
|
1396
|
+
return self.apply(lambda x: "%"+x+"%")
|
|
1397
|
+
|
|
1398
|
+
def apply_as_bool(self, str_to_bool_function: Callable[[str], bool]) -> bool:
|
|
1399
|
+
"""
|
|
1400
|
+
Transforms the entered text with a function that takes a string and returns a boolean.
|
|
1401
|
+
|
|
1402
|
+
Arguments:
|
|
1403
|
+
str_to_bool_function: A function that accepts a string and returns a boolean.
|
|
1404
|
+
|
|
1405
|
+
Returns:
|
|
1406
|
+
A boolean for the transformed value
|
|
1407
|
+
"""
|
|
1408
|
+
new_value = str_to_bool_function(self._value_do_not_touch)
|
|
1409
|
+
if not isinstance(new_value, bool):
|
|
1410
|
+
raise u.ConfigurationError("Function provided must return bool")
|
|
1411
|
+
return new_value
|
|
1412
|
+
|
|
1413
|
+
def apply_as_number(self, str_to_num_function: Callable[[str], IntOrFloat]) -> IntOrFloat:
|
|
1414
|
+
"""
|
|
1415
|
+
Transforms the entered text with a function that takes a string and returns an int or float.
|
|
1416
|
+
|
|
1417
|
+
Arguments:
|
|
1418
|
+
str_to_num_function: A function that accepts a string and returns an int or float.
|
|
1419
|
+
|
|
1420
|
+
Returns:
|
|
1421
|
+
An int or float for the transformed value
|
|
1422
|
+
"""
|
|
1423
|
+
new_value = str_to_num_function(self._value_do_not_touch)
|
|
1424
|
+
if not isinstance(new_value, (int, float)):
|
|
1425
|
+
raise u.ConfigurationError("Function provided must return a number")
|
|
1426
|
+
return new_value
|
|
1427
|
+
|
|
1428
|
+
def apply_as_datetime(self, str_to_datetime_function: Callable[[str], datetime]) -> datetime:
|
|
1429
|
+
"""
|
|
1430
|
+
Transforms the entered text with a function that takes a string and returns a datetime object.
|
|
1431
|
+
|
|
1432
|
+
Arguments:
|
|
1433
|
+
str_to_datetime_function: A function that accepts a string and returns a datetime object.
|
|
1434
|
+
|
|
1435
|
+
Returns:
|
|
1436
|
+
A datetime object for the transformed value
|
|
1437
|
+
"""
|
|
1438
|
+
new_value = str_to_datetime_function(self._value_do_not_touch)
|
|
1439
|
+
if not isinstance(new_value, datetime):
|
|
1440
|
+
raise u.ConfigurationError("Function provided must return datetime")
|
|
1441
|
+
return new_value
|
|
1442
|
+
|
|
1443
|
+
|
|
1444
|
+
@dataclass
|
|
1445
|
+
class TextParameter(Parameter[pc.TextParameterConfig, po.TextParameterOption, d.TextDataSource]):
|
|
1446
|
+
"""
|
|
1447
|
+
Class for text parameter widgets.
|
|
1448
|
+
"""
|
|
1449
|
+
_curr_option: po.TextParameterOption | None
|
|
1450
|
+
_entered_text: str | None
|
|
1451
|
+
|
|
1452
|
+
def __post_init__(self):
|
|
1453
|
+
if self.is_enabled() and isinstance(self._entered_text, str):
|
|
1454
|
+
try:
|
|
1455
|
+
self._entered_text = self._config.validate_entered_text(self._entered_text)
|
|
1456
|
+
except u.ConfigurationError as e:
|
|
1457
|
+
raise self._config._invalid_input_error(self._entered_text, str(e))
|
|
1458
|
+
|
|
1459
|
+
def is_enabled(self) -> bool:
|
|
1460
|
+
return self._curr_option is not None
|
|
1461
|
+
|
|
1462
|
+
@staticmethod
|
|
1463
|
+
def _ParameterConfigType():
|
|
1464
|
+
return pc.TextParameterConfig
|
|
1465
|
+
|
|
1466
|
+
@staticmethod
|
|
1467
|
+
def _ParameterOptionType():
|
|
1468
|
+
return po.TextParameterOption
|
|
1469
|
+
|
|
1470
|
+
@staticmethod
|
|
1471
|
+
def _DataSourceType():
|
|
1472
|
+
return d.TextDataSource
|
|
1473
|
+
|
|
1474
|
+
@classmethod
|
|
1475
|
+
def CreateWithOptions(
|
|
1476
|
+
cls, name: str, label: str, all_options: Sequence[po.TextParameterOption | dict], *, description: str = "",
|
|
1477
|
+
input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
1478
|
+
):
|
|
1479
|
+
"""
|
|
1480
|
+
Method for creating the configurations for a TextParameter that doesn't involve user attribute or parent
|
|
1481
|
+
|
|
1482
|
+
Arguments:
|
|
1483
|
+
name: The name of the parameter
|
|
1484
|
+
label: The display label for the parameter
|
|
1485
|
+
all_options: All options associated to this parameter regardless of the user group or parent parameter option they depend on
|
|
1486
|
+
description: Explains the meaning of the parameter
|
|
1487
|
+
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
|
|
1488
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
1489
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
1490
|
+
"""
|
|
1491
|
+
return super().CreateWithOptions(
|
|
1492
|
+
name, label, all_options, description=description, input_type=input_type,
|
|
1493
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
1494
|
+
)
|
|
1495
|
+
|
|
1496
|
+
@classmethod
|
|
1497
|
+
def create_with_options(
|
|
1498
|
+
cls, name: str, label: str, *, description: str = "",
|
|
1499
|
+
input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None
|
|
1500
|
+
):
|
|
1501
|
+
"""
|
|
1502
|
+
Python decorator for creating the configurations for a TextParameter that may include user attribute or parent
|
|
1503
|
+
|
|
1504
|
+
The decorated function must return a list of TextParameterOption objects.
|
|
1505
|
+
|
|
1506
|
+
Arguments:
|
|
1507
|
+
name: The name of the parameter
|
|
1508
|
+
label: The display label for the parameter
|
|
1509
|
+
description: Explains the meaning of the parameter
|
|
1510
|
+
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
|
|
1511
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
1512
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
1513
|
+
"""
|
|
1514
|
+
def decorator(func: Callable[..., Sequence[po.TextParameterOption]]):
|
|
1515
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1516
|
+
options = u.call_func(func, sqrl=sqrl)
|
|
1517
|
+
return cls.CreateWithOptions(
|
|
1518
|
+
name, label, options, description=description, input_type=input_type,
|
|
1519
|
+
user_attribute=user_attribute, parent_name=parent_name
|
|
1520
|
+
)
|
|
1521
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1522
|
+
return wrapper
|
|
1523
|
+
return decorator
|
|
1524
|
+
|
|
1525
|
+
@classmethod
|
|
1526
|
+
def CreateSimple(
|
|
1527
|
+
cls, name: str, label: str, *, description: str = "", default_text: str = "", input_type: str = "text", **kwargs
|
|
1528
|
+
):
|
|
1529
|
+
"""
|
|
1530
|
+
Method for creating the configurations for a TextParameter that doesn't involve user attributes or parent parameters
|
|
1531
|
+
|
|
1532
|
+
Arguments:
|
|
1533
|
+
name: The name of the parameter
|
|
1534
|
+
label: The display label for the parameter
|
|
1535
|
+
description: Explains the meaning of the parameter
|
|
1536
|
+
default_text: Default input text for this option. Optional, default is empty string.
|
|
1537
|
+
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
|
|
1538
|
+
"""
|
|
1539
|
+
single_param_option = po.TextParameterOption(default_text=default_text)
|
|
1540
|
+
return cls.CreateWithOptions(name, label, (single_param_option,), description=description, input_type=input_type)
|
|
1541
|
+
|
|
1542
|
+
@classmethod
|
|
1543
|
+
def create_simple(cls, name: str, label: str, *, description: str = "", default_text: str = "", input_type: str = "text"):
|
|
1544
|
+
"""
|
|
1545
|
+
Python decorator for creating the configurations for a TextParameter that doesn't involve user attributes or parent parameters
|
|
1546
|
+
|
|
1547
|
+
Arguments:
|
|
1548
|
+
name: The name of the parameter
|
|
1549
|
+
label: The display label for the parameter
|
|
1550
|
+
description: Explains the meaning of the parameter
|
|
1551
|
+
default_text: Default input text for this option. Optional, default is empty string.
|
|
1552
|
+
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
|
|
1553
|
+
"""
|
|
1554
|
+
def decorator(func: Callable[..., Any]):
|
|
1555
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1556
|
+
return cls.CreateSimple(name, label, description=description, default_text=default_text, input_type=input_type)
|
|
1557
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1558
|
+
return wrapper
|
|
1559
|
+
return decorator
|
|
1560
|
+
|
|
1561
|
+
@classmethod
|
|
1562
|
+
def CreateFromSource(
|
|
1563
|
+
cls, name: str, label: str, data_source: d.TextDataSource | dict, *, description: str = "",
|
|
1564
|
+
input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None, **kwargs
|
|
1565
|
+
):
|
|
1566
|
+
"""
|
|
1567
|
+
Method for creating the configurations for a TextParameter that uses a TextDataSource to receive the options
|
|
1568
|
+
|
|
1569
|
+
Arguments:
|
|
1570
|
+
name: The name of the parameter
|
|
1571
|
+
label: The display label for the parameter
|
|
1572
|
+
data_source: The lookup table to use for this parameter
|
|
1573
|
+
description: Explains the meaning of the parameter
|
|
1574
|
+
input_type: The type of input field to use. Options are 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
|
|
1575
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
1576
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
1577
|
+
"""
|
|
1578
|
+
extra_args = {
|
|
1579
|
+
"input_type": input_type
|
|
1580
|
+
}
|
|
1581
|
+
return cls._CreateFromSourceHelper(
|
|
1582
|
+
name, label, data_source, extra_args=extra_args, description=description, user_attribute=user_attribute, parent_name=parent_name
|
|
1583
|
+
)
|
|
1584
|
+
|
|
1585
|
+
@classmethod
|
|
1586
|
+
def create_from_source(
|
|
1587
|
+
cls, name: str, label: str, data_source: d.TextDataSource | dict, *, description: str = "",
|
|
1588
|
+
input_type: str = "text", user_attribute: str | None = None, parent_name: str | None = None
|
|
1589
|
+
):
|
|
1590
|
+
"""
|
|
1591
|
+
Python decorator for creating the configurations for a TextParameter that uses a TextDataSource to receive the options from a lookup table
|
|
1592
|
+
|
|
1593
|
+
The decorated function must return a TextDataSource object.
|
|
1594
|
+
|
|
1595
|
+
Arguments:
|
|
1596
|
+
name: The name of the parameter
|
|
1597
|
+
label: The display label for the parameter
|
|
1598
|
+
data_source: The lookup table to use for this parameter
|
|
1599
|
+
description: Explains the meaning of the parameter
|
|
1600
|
+
input_type: The type of input field to use. Options are 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
|
|
1601
|
+
user_attribute: The user attribute that may cascade the options for this parameter. Default is None
|
|
1602
|
+
parent_name: Name of parent parameter that may cascade the options for this parameter. Default is None (no parent)
|
|
1603
|
+
"""
|
|
1604
|
+
def decorator(func: Callable[..., d.TextDataSource]):
|
|
1605
|
+
def wrapper(sqrl: ParametersArgs):
|
|
1606
|
+
data_source = u.call_func(func, sqrl=sqrl)
|
|
1607
|
+
return cls.CreateFromSource(
|
|
1608
|
+
name, label, data_source, description=description,
|
|
1609
|
+
input_type=input_type, user_attribute=user_attribute, parent_name=parent_name
|
|
1610
|
+
)
|
|
1611
|
+
ps.ParameterConfigsSetIO.param_factories.append(wrapper)
|
|
1612
|
+
return wrapper
|
|
1613
|
+
return decorator
|
|
1614
|
+
|
|
1615
|
+
def get_entered_text(self, **kwargs) -> TextValue:
|
|
1616
|
+
"""
|
|
1617
|
+
Get the entered text. Returns a TextValue object that cannot be converted to string except through placeholders.
|
|
1618
|
+
|
|
1619
|
+
Returns:
|
|
1620
|
+
A TextValue object
|
|
1621
|
+
"""
|
|
1622
|
+
assert isinstance(self._entered_text, str), "Parameter is not enabled"
|
|
1623
|
+
return TextValue(self._entered_text)
|
|
1624
|
+
|
|
1625
|
+
def get_entered_int(self, **kwargs) -> int:
|
|
1626
|
+
"""
|
|
1627
|
+
Get the entered integer. The TextParameter must be a "number" input type
|
|
1628
|
+
|
|
1629
|
+
Returns: int
|
|
1630
|
+
"""
|
|
1631
|
+
if self._config.input_type != "number":
|
|
1632
|
+
raise u.ConfigurationError("Method 'get_entered_int' requires TextParameter to have input type 'number'")
|
|
1633
|
+
text = self.get_entered_text()
|
|
1634
|
+
return text.apply_as_number(int)
|
|
1635
|
+
|
|
1636
|
+
def get_entered_datetime(self, **kwargs) -> datetime:
|
|
1637
|
+
"""
|
|
1638
|
+
Get the entered datetime. The TextParameter input type must be one of ["date", "datetime-local", "month", "time"]
|
|
1639
|
+
|
|
1640
|
+
Returns: datetime
|
|
1641
|
+
"""
|
|
1642
|
+
applicable_input_types = ["date", "datetime-local", "month", "time"]
|
|
1643
|
+
if self._config.input_type not in applicable_input_types:
|
|
1644
|
+
raise u.ConfigurationError(f"Method 'get_entered_datetime' requires TextParameter to have one of these input types: {applicable_input_types}")
|
|
1645
|
+
text = self.get_entered_text()
|
|
1646
|
+
|
|
1647
|
+
date_formats = { "date": "%Y-%m-%d", "datetime-local": "%Y-%m-%dT%H:%M", "month": "%Y-%m", "time": "%H:%M" }
|
|
1648
|
+
return text.apply_as_datetime(lambda x: datetime.strptime(x, date_formats[self._config.input_type]))
|
|
1649
|
+
|
|
1650
|
+
def _to_json_dict0(self):
|
|
1651
|
+
"""
|
|
1652
|
+
Converts this parameter as a JSON object for the parameters API response
|
|
1653
|
+
|
|
1654
|
+
Returns:
|
|
1655
|
+
A dictionary for the JSON object
|
|
1656
|
+
"""
|
|
1657
|
+
output = super()._to_json_dict0()
|
|
1658
|
+
output['input_type'] = self._config.input_type
|
|
1659
|
+
if self.is_enabled():
|
|
1660
|
+
output['entered_text'] = self._entered_text
|
|
1661
|
+
return output
|
|
1662
|
+
|
|
1663
|
+
def _get_response_model0(self):
|
|
1664
|
+
return rm.TextParameterModel if self.is_enabled() else rm.NoneParameterModel
|