squirrels 0.1.0__py3-none-any.whl → 0.6.0.post0__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.
- dateutils/__init__.py +6 -0
- dateutils/_enums.py +25 -0
- squirrels/dateutils.py → dateutils/_implementation.py +409 -380
- dateutils/types.py +6 -0
- squirrels/__init__.py +21 -18
- squirrels/_api_routes/__init__.py +5 -0
- squirrels/_api_routes/auth.py +337 -0
- squirrels/_api_routes/base.py +196 -0
- squirrels/_api_routes/dashboards.py +156 -0
- squirrels/_api_routes/data_management.py +148 -0
- squirrels/_api_routes/datasets.py +220 -0
- squirrels/_api_routes/project.py +289 -0
- squirrels/_api_server.py +552 -134
- squirrels/_arguments/__init__.py +0 -0
- squirrels/_arguments/init_time_args.py +83 -0
- squirrels/_arguments/run_time_args.py +111 -0
- squirrels/_auth.py +777 -0
- squirrels/_command_line.py +239 -107
- squirrels/_compile_prompts.py +147 -0
- squirrels/_connection_set.py +94 -0
- squirrels/_constants.py +141 -64
- squirrels/_dashboards.py +179 -0
- squirrels/_data_sources.py +570 -0
- squirrels/_dataset_types.py +91 -0
- squirrels/_env_vars.py +209 -0
- squirrels/_exceptions.py +29 -0
- squirrels/_http_error_responses.py +52 -0
- squirrels/_initializer.py +319 -110
- squirrels/_logging.py +121 -0
- squirrels/_manifest.py +357 -187
- squirrels/_mcp_server.py +578 -0
- squirrels/_model_builder.py +69 -0
- squirrels/_model_configs.py +74 -0
- squirrels/_model_queries.py +52 -0
- squirrels/_models.py +1201 -0
- squirrels/_package_data/base_project/.env +7 -0
- squirrels/_package_data/base_project/.env.example +44 -0
- squirrels/_package_data/base_project/connections.yml +16 -0
- squirrels/_package_data/base_project/dashboards/dashboard_example.py +40 -0
- squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
- squirrels/_package_data/base_project/docker/.dockerignore +16 -0
- squirrels/_package_data/base_project/docker/Dockerfile +16 -0
- squirrels/_package_data/base_project/docker/compose.yml +7 -0
- squirrels/_package_data/base_project/duckdb_init.sql +10 -0
- squirrels/_package_data/base_project/gitignore +13 -0
- squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
- squirrels/_package_data/base_project/models/builds/build_example.py +26 -0
- squirrels/_package_data/base_project/models/builds/build_example.sql +16 -0
- squirrels/_package_data/base_project/models/builds/build_example.yml +57 -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 +51 -0
- squirrels/_package_data/base_project/models/federates/federate_example.sql +21 -0
- squirrels/_package_data/base_project/models/federates/federate_example.yml +65 -0
- squirrels/_package_data/base_project/models/sources.yml +38 -0
- squirrels/_package_data/base_project/parameters.yml +142 -0
- squirrels/_package_data/base_project/pyconfigs/connections.py +19 -0
- squirrels/_package_data/base_project/pyconfigs/context.py +96 -0
- squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
- squirrels/_package_data/base_project/pyconfigs/user.py +56 -0
- squirrels/_package_data/base_project/resources/expenses.db +0 -0
- squirrels/_package_data/base_project/resources/public/.gitkeep +0 -0
- squirrels/_package_data/base_project/resources/weather.db +0 -0
- squirrels/_package_data/base_project/seeds/seed_categories.csv +6 -0
- squirrels/_package_data/base_project/seeds/seed_categories.yml +15 -0
- squirrels/_package_data/base_project/seeds/seed_subcategories.csv +15 -0
- squirrels/_package_data/base_project/seeds/seed_subcategories.yml +21 -0
- squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
- squirrels/_package_data/base_project/tmp/.gitignore +2 -0
- squirrels/_package_data/templates/login_successful.html +53 -0
- squirrels/_package_data/templates/squirrels_studio.html +22 -0
- squirrels/_package_loader.py +29 -0
- squirrels/_parameter_configs.py +592 -0
- squirrels/_parameter_options.py +348 -0
- squirrels/_parameter_sets.py +207 -0
- squirrels/_parameters.py +1703 -0
- squirrels/_project.py +796 -0
- squirrels/_py_module.py +122 -0
- squirrels/_request_context.py +33 -0
- squirrels/_schemas/__init__.py +0 -0
- squirrels/_schemas/auth_models.py +83 -0
- squirrels/_schemas/query_param_models.py +70 -0
- squirrels/_schemas/request_models.py +26 -0
- squirrels/_schemas/response_models.py +286 -0
- squirrels/_seeds.py +97 -0
- squirrels/_sources.py +112 -0
- squirrels/_utils.py +540 -149
- squirrels/_version.py +1 -3
- squirrels/arguments.py +7 -0
- squirrels/auth.py +4 -0
- squirrels/connections.py +3 -0
- squirrels/dashboards.py +3 -0
- squirrels/data_sources.py +14 -282
- squirrels/parameter_options.py +13 -189
- squirrels/parameters.py +14 -801
- squirrels/types.py +18 -0
- squirrels-0.6.0.post0.dist-info/METADATA +148 -0
- squirrels-0.6.0.post0.dist-info/RECORD +101 -0
- {squirrels-0.1.0.dist-info → squirrels-0.6.0.post0.dist-info}/WHEEL +1 -2
- {squirrels-0.1.0.dist-info → squirrels-0.6.0.post0.dist-info}/entry_points.txt +1 -0
- squirrels-0.6.0.post0.dist-info/licenses/LICENSE +201 -0
- squirrels/_credentials_manager.py +0 -87
- squirrels/_module_loader.py +0 -37
- squirrels/_parameter_set.py +0 -151
- squirrels/_renderer.py +0 -286
- squirrels/_timed_imports.py +0 -37
- squirrels/connection_set.py +0 -126
- squirrels/package_data/base_project/.gitignore +0 -4
- squirrels/package_data/base_project/connections.py +0 -21
- squirrels/package_data/base_project/database/sample_database.db +0 -0
- squirrels/package_data/base_project/database/seattle_weather.db +0 -0
- squirrels/package_data/base_project/datasets/sample_dataset/context.py +0 -8
- squirrels/package_data/base_project/datasets/sample_dataset/database_view1.py +0 -23
- squirrels/package_data/base_project/datasets/sample_dataset/database_view1.sql.j2 +0 -7
- squirrels/package_data/base_project/datasets/sample_dataset/final_view.py +0 -10
- squirrels/package_data/base_project/datasets/sample_dataset/final_view.sql.j2 +0 -2
- squirrels/package_data/base_project/datasets/sample_dataset/parameters.py +0 -30
- squirrels/package_data/base_project/datasets/sample_dataset/selections.cfg +0 -6
- squirrels/package_data/base_project/squirrels.yaml +0 -26
- squirrels/package_data/static/favicon.ico +0 -0
- squirrels/package_data/static/script.js +0 -234
- squirrels/package_data/static/style.css +0 -110
- squirrels/package_data/templates/index.html +0 -32
- squirrels-0.1.0.dist-info/LICENSE +0 -22
- squirrels-0.1.0.dist-info/METADATA +0 -67
- squirrels-0.1.0.dist-info/RECORD +0 -40
- squirrels-0.1.0.dist-info/top_level.txt +0 -1
squirrels/_version.py
CHANGED
squirrels/arguments.py
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from ._arguments.init_time_args import ConnectionsArgs, AuthProviderArgs, ParametersArgs, BuildModelArgs
|
|
2
|
+
from ._arguments.run_time_args import ContextArgs, ModelArgs, DashboardArgs
|
|
3
|
+
|
|
4
|
+
__all__ = [
|
|
5
|
+
"ConnectionsArgs", "AuthProviderArgs", "ParametersArgs", "BuildModelArgs",
|
|
6
|
+
"ContextArgs", "ModelArgs", "DashboardArgs"
|
|
7
|
+
]
|
squirrels/auth.py
ADDED
squirrels/connections.py
ADDED
squirrels/dashboards.py
ADDED
squirrels/data_sources.py
CHANGED
|
@@ -1,282 +1,14 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"""
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
table_or_query: str
|
|
16
|
-
|
|
17
|
-
def __post_init__(self) -> None:
|
|
18
|
-
if not hasattr(self, 'parent_id_col'):
|
|
19
|
-
self.parent_id_col = None
|
|
20
|
-
if not hasattr(self, 'connection_name'):
|
|
21
|
-
self.connection_name = c.DEFAULT_DB_CONN
|
|
22
|
-
|
|
23
|
-
def get_query(self) -> str:
|
|
24
|
-
"""
|
|
25
|
-
Get the "table_or_query" attribute as a select query
|
|
26
|
-
|
|
27
|
-
Returns:
|
|
28
|
-
str: The converted select query
|
|
29
|
-
"""
|
|
30
|
-
if self.table_or_query.lower().startswith('select '):
|
|
31
|
-
query = self.table_or_query
|
|
32
|
-
else:
|
|
33
|
-
query = f'SELECT * FROM {self.table_or_query}'
|
|
34
|
-
return query
|
|
35
|
-
|
|
36
|
-
def convert(self, ds_param: p.DataSourceParameter, df: pd.DataFrame) -> p.Parameter:
|
|
37
|
-
"""
|
|
38
|
-
An abstract method for converting itself into a parameter
|
|
39
|
-
|
|
40
|
-
Args:
|
|
41
|
-
ds_param: The parameter to convert
|
|
42
|
-
df: The dataframe containing the parameter options data
|
|
43
|
-
|
|
44
|
-
Returns:
|
|
45
|
-
The converted parameter
|
|
46
|
-
"""
|
|
47
|
-
raise _utils.AbstractMethodCallError(self.__class__, "convert")
|
|
48
|
-
|
|
49
|
-
def _get_parent(self, row):
|
|
50
|
-
return str(_utils.get_row_value(row, self.parent_id_col)) if self.parent_id_col is not None else None
|
|
51
|
-
|
|
52
|
-
def _validate_parameter_class(self, ds_param: p.DataSourceParameter, parameter_classes: List[Type[p.Parameter]]) -> None:
|
|
53
|
-
if ds_param.parameter_class not in parameter_classes:
|
|
54
|
-
parameter_class_name = ds_param.parameter_class.__name__
|
|
55
|
-
datasource_class_name = self.__class__.__name__
|
|
56
|
-
raise _utils.ConfigurationError(f'Invalid widget type "{parameter_class_name}" for {datasource_class_name}')
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
@dataclass
|
|
60
|
-
class SelectionDataSource(DataSource):
|
|
61
|
-
"""
|
|
62
|
-
Lookup table for selection parameters (single and multi)
|
|
63
|
-
|
|
64
|
-
Attributes:
|
|
65
|
-
connection_name: Name of the connection to use defined in connections.py
|
|
66
|
-
table_or_query: Either the name of the table to use, or a query to run
|
|
67
|
-
id_col: The column name of the id
|
|
68
|
-
options_col: The column name of the options
|
|
69
|
-
order_by_col: The column name to order the options by. Orders by the id_col instead if this is None
|
|
70
|
-
is_default_col: The column name that indicates which options are the default
|
|
71
|
-
parent_id_col: The column name of the parent option id that this option belongs to
|
|
72
|
-
"""
|
|
73
|
-
id_col: str
|
|
74
|
-
options_col: str
|
|
75
|
-
order_by_col: Optional[str] = None
|
|
76
|
-
is_default_col: Optional[str] = None
|
|
77
|
-
parent_id_col: Optional[str] = None
|
|
78
|
-
connection_name: str = c.DEFAULT_DB_CONN
|
|
79
|
-
|
|
80
|
-
def __post_init__(self):
|
|
81
|
-
self.order_by_col = self.order_by_col if self.order_by_col is not None else self.id_col
|
|
82
|
-
|
|
83
|
-
def convert(self, ds_param: p.DataSourceParameter, df: pd.DataFrame) -> p.Parameter:
|
|
84
|
-
"""
|
|
85
|
-
Method to convert the associated DataSourceParameter into a SingleSelect or MultiSelect Parameter
|
|
86
|
-
|
|
87
|
-
Parameters:
|
|
88
|
-
ds_param: The parameter to convert
|
|
89
|
-
df: The dataframe containing the parameter options data
|
|
90
|
-
|
|
91
|
-
Returns:
|
|
92
|
-
The converted parameter
|
|
93
|
-
"""
|
|
94
|
-
self._validate_parameter_class(ds_param, [p.SingleSelectParameter, p.MultiSelectParameter])
|
|
95
|
-
|
|
96
|
-
def is_default(row):
|
|
97
|
-
return int(_utils.get_row_value(row, self.is_default_col)) == 1 if self.is_default_col is not None else False
|
|
98
|
-
|
|
99
|
-
try:
|
|
100
|
-
df.sort_values(self.order_by_col, inplace=True)
|
|
101
|
-
except KeyError as e:
|
|
102
|
-
raise _utils.ConfigurationError(f'Could not sort on column name "{self.order_by_col}" as it does not exist')
|
|
103
|
-
|
|
104
|
-
options = tuple(
|
|
105
|
-
po.SelectParameterOption(str(_utils.get_row_value(row, self.id_col)), str(_utils.get_row_value(row, self.options_col)), is_default(row),
|
|
106
|
-
parent_option_id=self._get_parent(row))
|
|
107
|
-
for _, row in df.iterrows()
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
return ds_param.parameter_class(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden, parent=ds_param.parent)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
@dataclass
|
|
114
|
-
class DateDataSource(DataSource):
|
|
115
|
-
"""
|
|
116
|
-
Lookup table for date parameter default options
|
|
117
|
-
|
|
118
|
-
Attributes:
|
|
119
|
-
connection_name: Name of the connection to use defined in connections.py
|
|
120
|
-
table_or_query: Either the name of the table to use, or a query to run
|
|
121
|
-
default_date_col: The column name of the default date
|
|
122
|
-
date_format: The format of the default date(s). Defaults to '%Y-%m-%d'
|
|
123
|
-
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
124
|
-
"""
|
|
125
|
-
default_date_col: str
|
|
126
|
-
parent_id_col: Optional[str] = None
|
|
127
|
-
date_format: Optional[str] = '%Y-%m-%d'
|
|
128
|
-
connection_name: str = c.DEFAULT_DB_CONN
|
|
129
|
-
|
|
130
|
-
def convert(self, ds_param: p.DataSourceParameter, df: pd.DataFrame) -> p.DateParameter:
|
|
131
|
-
"""
|
|
132
|
-
Method to convert the associated DataSourceParameter into a DateParameter
|
|
133
|
-
|
|
134
|
-
Parameters:
|
|
135
|
-
ds_param: The parameter to convert
|
|
136
|
-
df: The dataframe containing the parameter options data
|
|
137
|
-
|
|
138
|
-
Returns:
|
|
139
|
-
The converted parameter
|
|
140
|
-
"""
|
|
141
|
-
self._validate_parameter_class(ds_param, [p.DateParameter])
|
|
142
|
-
|
|
143
|
-
def get_date(row: pd.Series) -> str:
|
|
144
|
-
return str(_utils.get_row_value(row, self.default_date_col))
|
|
145
|
-
|
|
146
|
-
def create_date_param_option(row: pd.Series) -> po.DateParameterOption:
|
|
147
|
-
return po.DateParameterOption(get_date(row), self.date_format, self._get_parent(row))
|
|
148
|
-
|
|
149
|
-
if ds_param.parent is None:
|
|
150
|
-
row = df.iloc[0]
|
|
151
|
-
return p.DateParameter(ds_param.name, ds_param.label, get_date(row), self.date_format,
|
|
152
|
-
is_hidden=ds_param.is_hidden)
|
|
153
|
-
else:
|
|
154
|
-
all_options = tuple(create_date_param_option(row) for _, row in df.iterrows())
|
|
155
|
-
return p.DateParameter.WithParent(ds_param.name, ds_param.label, all_options, ds_param.parent,
|
|
156
|
-
is_hidden=ds_param.is_hidden)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
@dataclass
|
|
160
|
-
class _NumericDataSource(DataSource):
|
|
161
|
-
"""
|
|
162
|
-
Abstract class for number or number range data sources
|
|
163
|
-
"""
|
|
164
|
-
min_value_col: str
|
|
165
|
-
max_value_col: str
|
|
166
|
-
increment_col: Optional[str] = None
|
|
167
|
-
|
|
168
|
-
def _convert_helper(self, row: pd.Series) -> Tuple[str, str, str]:
|
|
169
|
-
min_val = str(_utils.get_row_value(row, self.min_value_col))
|
|
170
|
-
max_val = str(_utils.get_row_value(row, self.max_value_col))
|
|
171
|
-
incr_val = str(_utils.get_row_value(row, self.increment_col)) if self.increment_col is not None else '1'
|
|
172
|
-
return min_val, max_val, incr_val
|
|
173
|
-
|
|
174
|
-
@dataclass
|
|
175
|
-
class NumberDataSource(_NumericDataSource):
|
|
176
|
-
"""
|
|
177
|
-
Lookup table for number parameter default options
|
|
178
|
-
|
|
179
|
-
Attributes:
|
|
180
|
-
connection_name: Name of the connection to use defined in connections.py
|
|
181
|
-
table_or_query: Either the name of the table to use, or a query to run
|
|
182
|
-
min_value_col: The column name of the minimum value
|
|
183
|
-
max_value_col: The column name of the maximum value
|
|
184
|
-
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
185
|
-
default_value_col: The column name of the default value. Defaults to min_value_col if None
|
|
186
|
-
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
187
|
-
"""
|
|
188
|
-
default_value_col: Optional[str] = None
|
|
189
|
-
parent_id_col: Optional[str] = None
|
|
190
|
-
connection_name: str = c.DEFAULT_DB_CONN
|
|
191
|
-
|
|
192
|
-
def convert(self, ds_param: p.DataSourceParameter, df: pd.DataFrame) -> p.NumberParameter:
|
|
193
|
-
"""
|
|
194
|
-
Method to convert the associated DataSourceParameter into a NumberParameter
|
|
195
|
-
|
|
196
|
-
Parameters:
|
|
197
|
-
ds_param: The parameter to convert
|
|
198
|
-
df: The dataframe containing the parameter options data
|
|
199
|
-
|
|
200
|
-
Returns:
|
|
201
|
-
The converted parameter
|
|
202
|
-
"""
|
|
203
|
-
self._validate_parameter_class(ds_param, [p.NumberParameter])
|
|
204
|
-
|
|
205
|
-
def _get_default_value(row: pd.Series) -> str:
|
|
206
|
-
return str(_utils.get_row_value(row, self.default_value_col)) if self.default_value_col is not None \
|
|
207
|
-
else str(_utils.get_row_value(row, self.min_value_col))
|
|
208
|
-
|
|
209
|
-
def _create_num_param_option(row: pd.Series) -> po.NumberParameterOption:
|
|
210
|
-
min_value, max_value, increment = self._convert_helper(row)
|
|
211
|
-
return po.NumberParameterOption(min_value, max_value, increment, _get_default_value(row),
|
|
212
|
-
self._get_parent(row))
|
|
213
|
-
|
|
214
|
-
if ds_param.parent is None:
|
|
215
|
-
row = df.iloc[0]
|
|
216
|
-
min_value, max_value, increment = self._convert_helper(row)
|
|
217
|
-
return p.NumberParameter(ds_param.name, ds_param.label, min_value, max_value, increment,
|
|
218
|
-
_get_default_value(row), is_hidden=ds_param.is_hidden)
|
|
219
|
-
else:
|
|
220
|
-
all_options = tuple(_create_num_param_option(row) for _, row in df.iterrows())
|
|
221
|
-
return p.NumberParameter.WithParent(ds_param.name, ds_param.label, all_options, ds_param.parent,
|
|
222
|
-
is_hidden=ds_param.is_hidden)
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
@dataclass
|
|
226
|
-
class NumRangeDataSource(_NumericDataSource):
|
|
227
|
-
"""
|
|
228
|
-
Lookup table for number range parameter default options
|
|
229
|
-
|
|
230
|
-
Attributes:
|
|
231
|
-
connection_name: Name of the connection to use defined in connections.py
|
|
232
|
-
table_or_query: Either the name of the table to use, or a query to run
|
|
233
|
-
min_value_col: The column name of the minimum value
|
|
234
|
-
max_value_col: The column name of the maximum value
|
|
235
|
-
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
236
|
-
default_lower_value_col: The column name of the default lower value. Defaults to min_value_col if None
|
|
237
|
-
default_upper_value_col: The column name of the default upper value. Defaults to max_value_col if None
|
|
238
|
-
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
239
|
-
"""
|
|
240
|
-
default_lower_value_col: Optional[str] = None
|
|
241
|
-
default_upper_value_col: Optional[str] = None
|
|
242
|
-
parent_id_col: Optional[str] = None
|
|
243
|
-
connection_name: str = c.DEFAULT_DB_CONN
|
|
244
|
-
|
|
245
|
-
def convert(self, ds_param: p.DataSourceParameter, df: pd.DataFrame) -> p.NumRangeParameter:
|
|
246
|
-
"""
|
|
247
|
-
Method to convert the associated DataSourceParameter into a NumRangeParameter
|
|
248
|
-
|
|
249
|
-
Parameters:
|
|
250
|
-
ds_param: The parameter to convert
|
|
251
|
-
df: The dataframe containing the parameter options data
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
The converted parameter
|
|
255
|
-
"""
|
|
256
|
-
self._validate_parameter_class(ds_param, [p.NumRangeParameter])
|
|
257
|
-
|
|
258
|
-
def _get_default_lower_upper_values(row: pd.Series) -> Tuple[str, str]:
|
|
259
|
-
lower_value_col = self.default_lower_value_col if self.default_lower_value_col is not None \
|
|
260
|
-
else self.min_value_col
|
|
261
|
-
upper_value_col = self.default_upper_value_col if self.default_upper_value_col is not None \
|
|
262
|
-
else self.max_value_col
|
|
263
|
-
lower_value = str(_utils.get_row_value(row, lower_value_col))
|
|
264
|
-
upper_value = str(_utils.get_row_value(row, upper_value_col))
|
|
265
|
-
return lower_value, upper_value
|
|
266
|
-
|
|
267
|
-
def _create_range_param_option(row: pd.Series) -> po.NumRangeParameterOption:
|
|
268
|
-
min_value, max_value, increment = self._convert_helper(row)
|
|
269
|
-
lower_value, upper_value = _get_default_lower_upper_values(row)
|
|
270
|
-
return po.NumRangeParameterOption(min_value, max_value, increment, lower_value, upper_value,
|
|
271
|
-
self._get_parent(row))
|
|
272
|
-
|
|
273
|
-
if ds_param.parent is None:
|
|
274
|
-
row = df.iloc[0]
|
|
275
|
-
min_value, max_value, increment = self._convert_helper(row)
|
|
276
|
-
lower_value, upper_value = _get_default_lower_upper_values(row)
|
|
277
|
-
return p.NumRangeParameter(ds_param.name, ds_param.label, min_value, max_value, increment,
|
|
278
|
-
lower_value, upper_value, is_hidden=ds_param.is_hidden)
|
|
279
|
-
else:
|
|
280
|
-
all_options = tuple(_create_range_param_option(row) for _, row in df.iterrows())
|
|
281
|
-
return p.NumRangeParameter.WithParent(ds_param.name, ds_param.label, all_options, ds_param.parent,
|
|
282
|
-
is_hidden=ds_param.is_hidden)
|
|
1
|
+
from ._data_sources import (
|
|
2
|
+
SourceEnum,
|
|
3
|
+
SelectDataSource,
|
|
4
|
+
DateDataSource,
|
|
5
|
+
DateRangeDataSource,
|
|
6
|
+
NumberDataSource,
|
|
7
|
+
NumberRangeDataSource,
|
|
8
|
+
TextDataSource
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
"SourceEnum", "SelectDataSource", "DateDataSource", "DateRangeDataSource",
|
|
13
|
+
"NumberDataSource", "NumberRangeDataSource", "TextDataSource"
|
|
14
|
+
]
|
squirrels/parameter_options.py
CHANGED
|
@@ -1,189 +1,13 @@
|
|
|
1
|
-
from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Abstract class (or type) for parameter options
|
|
15
|
-
"""
|
|
16
|
-
def __post_init__(self) -> None:
|
|
17
|
-
if not hasattr(self, "parent_option_ids"):
|
|
18
|
-
self.parent_option_ids = frozenset()
|
|
19
|
-
|
|
20
|
-
self.parent_option_ids = frozenset(
|
|
21
|
-
{self.parent_option_id} \
|
|
22
|
-
if hasattr(self, "parent_option_id") and self.parent_option_id is not None \
|
|
23
|
-
else self.parent_option_ids
|
|
24
|
-
)
|
|
25
|
-
|
|
26
|
-
def is_valid(self, selected_parent_option_ids: Optional[Iterable[str]] = None):
|
|
27
|
-
"""
|
|
28
|
-
Checks if this option is valid given the selected parent options.
|
|
29
|
-
|
|
30
|
-
Parameters:
|
|
31
|
-
selected_parent_option_ids: List of selected option ids from the parent parameter
|
|
32
|
-
|
|
33
|
-
Returns:
|
|
34
|
-
True if valid, False otherwise
|
|
35
|
-
"""
|
|
36
|
-
if selected_parent_option_ids is not None:
|
|
37
|
-
return not self.parent_option_ids.isdisjoint(selected_parent_option_ids)
|
|
38
|
-
else:
|
|
39
|
-
return True
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
@dataclass
|
|
43
|
-
class SelectParameterOption(ParameterOption):
|
|
44
|
-
"""
|
|
45
|
-
Parameter option for a select parameter
|
|
46
|
-
|
|
47
|
-
Attributes:
|
|
48
|
-
identifier: Unique identifier for this option that never changes over time
|
|
49
|
-
label: Human readable label that gets shown as a dropdown option
|
|
50
|
-
is_default: True if this is a default option, False otherwise
|
|
51
|
-
parent_option_id: Identifier of the parent option, or None if this is a top-level option
|
|
52
|
-
parent_option_ids: Set of parent option ids (only used if parent_option_id is None), or an empty set if this is a top-level option
|
|
53
|
-
"""
|
|
54
|
-
identifier: str
|
|
55
|
-
label: str
|
|
56
|
-
is_default: bool = False
|
|
57
|
-
parent_option_id: Optional[str] = field(default=None, repr=False)
|
|
58
|
-
parent_option_ids: Iterable[str] = frozenset()
|
|
59
|
-
|
|
60
|
-
def to_dict(self):
|
|
61
|
-
return {'id': self.identifier, 'label': self.label}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
@dataclass
|
|
65
|
-
class DateParameterOption(ParameterOption):
|
|
66
|
-
"""
|
|
67
|
-
Parameter option for default dates if it varies based on selection of another parameter
|
|
68
|
-
|
|
69
|
-
Attributes:
|
|
70
|
-
default_date: Default date for this option
|
|
71
|
-
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
72
|
-
parent_option_id: Identifier of the parent option, or None if this is a top-level option
|
|
73
|
-
parent_option_ids: Set of parent option ids (only used if parent_option_id is None), or an empty set if this is a top-level option
|
|
74
|
-
"""
|
|
75
|
-
default_date: Union[str, datetime]
|
|
76
|
-
date_format: str = '%Y-%m-%d'
|
|
77
|
-
parent_option_id: Optional[str] = field(default=None, repr=False)
|
|
78
|
-
parent_option_ids: Iterable[str] = frozenset()
|
|
79
|
-
|
|
80
|
-
def __post_init__(self) -> None:
|
|
81
|
-
super().__post_init__()
|
|
82
|
-
self.default_date = self._validate_date(self.default_date) \
|
|
83
|
-
if isinstance(self.default_date, str) else self.default_date
|
|
84
|
-
|
|
85
|
-
def _validate_date(self, date_str: str) -> datetime:
|
|
86
|
-
try:
|
|
87
|
-
return datetime.strptime(date_str, self.date_format)
|
|
88
|
-
except ValueError as e:
|
|
89
|
-
raise ConfigurationError(f'Invalid format for date "{date_str}".') from e
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
@dataclass
|
|
93
|
-
class _NumericParameterOption(ParameterOption):
|
|
94
|
-
"""
|
|
95
|
-
Abstract class (or type) for numeric parameter options
|
|
96
|
-
"""
|
|
97
|
-
min_value: Decimal
|
|
98
|
-
max_value: Decimal
|
|
99
|
-
increment: Decimal
|
|
100
|
-
|
|
101
|
-
def __post_init__(self) -> None:
|
|
102
|
-
super().__post_init__()
|
|
103
|
-
try:
|
|
104
|
-
self.min_value = Decimal(self.min_value)
|
|
105
|
-
self.max_value = Decimal(self.max_value)
|
|
106
|
-
self.increment = Decimal(self.increment)
|
|
107
|
-
except InvalidDecimalConversion as e:
|
|
108
|
-
raise ConfigurationError(f'Could not convert either min, max, or increment to number') from e
|
|
109
|
-
|
|
110
|
-
if self.min_value > self.max_value:
|
|
111
|
-
raise ConfigurationError(f'The min_value "{self.min_value}" must be less than or equal to ' +
|
|
112
|
-
'the max_value "{self.max_value}"')
|
|
113
|
-
if (self.max_value - self.min_value) % self.increment != 0:
|
|
114
|
-
raise ConfigurationError(f'The increment "{self.increment}" must fit evenly between ' +
|
|
115
|
-
'the min_value "{self.min_value}" and max_value "{self.max_value}"')
|
|
116
|
-
|
|
117
|
-
def _value_in_range(self, value: Decimal, min_value: Decimal) -> bool:
|
|
118
|
-
return min_value <= value <= self.max_value
|
|
119
|
-
|
|
120
|
-
def _value_on_increment(self, value: Decimal, min_value: Decimal) -> bool:
|
|
121
|
-
diff = (value - min_value)
|
|
122
|
-
return diff >= 0 and diff % self.increment == 0
|
|
123
|
-
|
|
124
|
-
def _validate_value(self, value: Number, min_value: Optional[Decimal] = None) -> Decimal:
|
|
125
|
-
min_value = self.min_value if min_value is None else min_value
|
|
126
|
-
try:
|
|
127
|
-
value = Decimal(value)
|
|
128
|
-
except InvalidDecimalConversion as e:
|
|
129
|
-
raise ConfigurationError(f'Could not convert "{value}" to number', e)
|
|
130
|
-
|
|
131
|
-
if not self._value_in_range(value, min_value):
|
|
132
|
-
raise ConfigurationError(f'The selected value "{value}" is outside of bounds ' +
|
|
133
|
-
'"{min_value}" and "{self.max_value}"')
|
|
134
|
-
if not self._value_on_increment(value, min_value):
|
|
135
|
-
raise ConfigurationError(f'The difference between selected value "{value}" and lower value ' +
|
|
136
|
-
'"{min_value}" must be a multiple of increment "{self.increment}"')
|
|
137
|
-
return value
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
@dataclass
|
|
141
|
-
class NumberParameterOption(_NumericParameterOption):
|
|
142
|
-
"""
|
|
143
|
-
Parameter option for default numbers if it varies based on selection of another parameter
|
|
144
|
-
|
|
145
|
-
Attributes:
|
|
146
|
-
min_value: Minimum selectable value
|
|
147
|
-
max_value: Maximum selectable value
|
|
148
|
-
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
149
|
-
default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
|
|
150
|
-
parent_option_id: Identifier of the parent option, or None if this is a top-level option
|
|
151
|
-
parent_option_ids: Set of parent option ids (only used if parent_option_id is None), or an empty set if this is a top-level option
|
|
152
|
-
"""
|
|
153
|
-
default_value: Decimal
|
|
154
|
-
parent_option_id: Optional[str] = field(default=None, repr=False)
|
|
155
|
-
parent_option_ids: Iterable[str] = frozenset()
|
|
156
|
-
|
|
157
|
-
def __post_init__(self) -> None:
|
|
158
|
-
super().__post_init__()
|
|
159
|
-
self.default_value = self._validate_value(self.default_value)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
@dataclass
|
|
163
|
-
class NumRangeParameterOption(_NumericParameterOption):
|
|
164
|
-
"""
|
|
165
|
-
Parameter option for default numeric ranges if it varies based on selection of another parameter
|
|
166
|
-
|
|
167
|
-
Attributes:
|
|
168
|
-
min_value: Minimum selectable value
|
|
169
|
-
max_value: Maximum selectable value
|
|
170
|
-
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
171
|
-
default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
|
|
172
|
-
default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
|
|
173
|
-
Must also be greater than default_lower_value
|
|
174
|
-
parent_option_id: Identifier of the parent option, or None if this is a top-level option
|
|
175
|
-
parent_option_ids: Set of parent option ids (only used if parent_option_id is None), or an empty set if this is a top-level option
|
|
176
|
-
"""
|
|
177
|
-
default_lower_value: Decimal
|
|
178
|
-
default_upper_value: Decimal
|
|
179
|
-
parent_option_id: Optional[str] = field(default=None, repr=False)
|
|
180
|
-
parent_option_ids: Iterable[str] = frozenset()
|
|
181
|
-
|
|
182
|
-
def __post_init__(self) -> None:
|
|
183
|
-
super().__post_init__()
|
|
184
|
-
self.default_lower_value = self._validate_value(self.default_lower_value)
|
|
185
|
-
self.default_upper_value = self._validate_value(self.default_upper_value, self.default_lower_value)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# Types:
|
|
189
|
-
NumericParameterOption = Union[NumberParameterOption, NumRangeParameterOption]
|
|
1
|
+
from ._parameter_options import (
|
|
2
|
+
SelectParameterOption,
|
|
3
|
+
DateParameterOption,
|
|
4
|
+
DateRangeParameterOption,
|
|
5
|
+
NumberParameterOption,
|
|
6
|
+
NumberRangeParameterOption,
|
|
7
|
+
TextParameterOption
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"SelectParameterOption", "DateParameterOption", "DateRangeParameterOption",
|
|
12
|
+
"NumberParameterOption", "NumberRangeParameterOption", "TextParameterOption"
|
|
13
|
+
]
|