squirrels 0.1.1.post1__py3-none-any.whl → 0.2.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of squirrels might be problematic. Click here for more details.
- squirrels/__init__.py +10 -16
- squirrels/_api_server.py +234 -80
- squirrels/_authenticator.py +84 -0
- squirrels/_command_line.py +60 -72
- squirrels/_connection_set.py +96 -0
- squirrels/_constants.py +114 -33
- squirrels/_environcfg.py +77 -0
- squirrels/_initializer.py +126 -67
- squirrels/_manifest.py +195 -168
- squirrels/_models.py +495 -0
- squirrels/_package_loader.py +26 -0
- squirrels/_parameter_configs.py +401 -0
- squirrels/_parameter_sets.py +188 -0
- squirrels/_py_module.py +60 -0
- squirrels/_timer.py +36 -0
- squirrels/_utils.py +81 -49
- squirrels/_version.py +2 -2
- squirrels/arguments/init_time_args.py +32 -0
- squirrels/arguments/run_time_args.py +82 -0
- squirrels/data_sources.py +380 -155
- squirrels/dateutils.py +86 -57
- squirrels/package_data/base_project/Dockerfile +15 -0
- squirrels/package_data/base_project/connections.yml +7 -0
- squirrels/package_data/base_project/database/{sample_database.db → expenses.db} +0 -0
- squirrels/package_data/base_project/environcfg.yml +29 -0
- squirrels/package_data/base_project/ignores/.dockerignore +8 -0
- squirrels/package_data/base_project/ignores/.gitignore +7 -0
- squirrels/package_data/base_project/models/dbviews/database_view1.py +36 -0
- squirrels/package_data/base_project/models/dbviews/database_view1.sql +15 -0
- squirrels/package_data/base_project/models/federates/dataset_example.py +20 -0
- squirrels/package_data/base_project/models/federates/dataset_example.sql +3 -0
- squirrels/package_data/base_project/parameters.yml +109 -0
- squirrels/package_data/base_project/pyconfigs/auth.py +47 -0
- squirrels/package_data/base_project/pyconfigs/connections.py +28 -0
- squirrels/package_data/base_project/pyconfigs/context.py +45 -0
- squirrels/package_data/base_project/pyconfigs/parameters.py +55 -0
- squirrels/package_data/base_project/seeds/mocks/category.csv +3 -0
- squirrels/package_data/base_project/seeds/mocks/max_filter.csv +2 -0
- squirrels/package_data/base_project/seeds/mocks/subcategory.csv +6 -0
- squirrels/package_data/base_project/squirrels.yml.j2 +57 -0
- squirrels/package_data/base_project/tmp/.gitignore +2 -0
- squirrels/package_data/static/script.js +159 -63
- squirrels/package_data/static/style.css +79 -15
- squirrels/package_data/static/widgets.js +133 -0
- squirrels/package_data/templates/index.html +65 -23
- squirrels/package_data/templates/index2.html +22 -0
- squirrels/parameter_options.py +216 -119
- squirrels/parameters.py +407 -478
- squirrels/user_base.py +58 -0
- squirrels-0.2.0.dev0.dist-info/METADATA +126 -0
- squirrels-0.2.0.dev0.dist-info/RECORD +56 -0
- {squirrels-0.1.1.post1.dist-info → squirrels-0.2.0.dev0.dist-info}/WHEEL +1 -2
- squirrels-0.2.0.dev0.dist-info/entry_points.txt +3 -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 -20
- squirrels/package_data/base_project/datasets/sample_dataset/context.py +0 -22
- squirrels/package_data/base_project/datasets/sample_dataset/database_view1.py +0 -29
- squirrels/package_data/base_project/datasets/sample_dataset/database_view1.sql.j2 +0 -12
- squirrels/package_data/base_project/datasets/sample_dataset/final_view.py +0 -11
- squirrels/package_data/base_project/datasets/sample_dataset/final_view.sql.j2 +0 -3
- squirrels/package_data/base_project/datasets/sample_dataset/parameters.py +0 -47
- squirrels/package_data/base_project/datasets/sample_dataset/selections.cfg +0 -9
- squirrels/package_data/base_project/squirrels.yaml +0 -22
- squirrels-0.1.1.post1.dist-info/METADATA +0 -67
- squirrels-0.1.1.post1.dist-info/RECORD +0 -40
- squirrels-0.1.1.post1.dist-info/entry_points.txt +0 -2
- squirrels-0.1.1.post1.dist-info/top_level.txt +0 -1
- {squirrels-0.1.1.post1.dist-info → squirrels-0.2.0.dev0.dist-info}/LICENSE +0 -0
squirrels/data_sources.py
CHANGED
|
@@ -1,65 +1,196 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
-
from typing import Type,
|
|
2
|
+
from typing import Type, Sequence, Iterable, Optional, Any
|
|
3
3
|
from dataclasses import dataclass, field
|
|
4
|
+
from abc import ABCMeta, abstractmethod
|
|
5
|
+
import pandas as pd
|
|
4
6
|
|
|
5
|
-
from
|
|
6
|
-
from
|
|
7
|
-
from squirrels import _constants as c, _utils
|
|
7
|
+
from . import _parameter_configs as pc, parameter_options as po, _utils as u, _constants as c
|
|
8
|
+
from ._manifest import ManifestIO
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
@dataclass
|
|
11
|
-
class DataSource:
|
|
12
|
+
class DataSource(metaclass=ABCMeta):
|
|
12
13
|
"""
|
|
13
14
|
Abstract class for lookup tables coming from a database
|
|
14
15
|
"""
|
|
15
|
-
|
|
16
|
+
_table_or_query: str
|
|
17
|
+
_id_col: Optional[str]
|
|
18
|
+
_user_group_col: Optional[str] # = field(default=None, kw_only=True)
|
|
19
|
+
_parent_id_col: Optional[str] # = field(default=None, kw_only=True)
|
|
20
|
+
_connection_name: Optional[str] # = field(default=None, kw_only=True)
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
def __init__(
|
|
24
|
+
self, table_or_query: str, *, id_col: Optional[str] = None, user_group_col: Optional[str] = None,
|
|
25
|
+
parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
26
|
+
) -> None:
|
|
27
|
+
self._table_or_query = table_or_query
|
|
28
|
+
self._id_col = id_col
|
|
29
|
+
self._user_group_col = user_group_col
|
|
30
|
+
self._parent_id_col = parent_id_col
|
|
31
|
+
self._connection_name = connection_name
|
|
16
32
|
|
|
17
|
-
def
|
|
18
|
-
if
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
self.connection_name = c.DEFAULT_DB_CONN
|
|
33
|
+
def _get_connection_name(self) -> str:
|
|
34
|
+
if self._connection_name is None:
|
|
35
|
+
return ManifestIO.obj.settings.get(c.DB_CONN_DEFAULT_USED_SETTING, c.DEFAULT_DB_CONN)
|
|
36
|
+
return self._connection_name
|
|
22
37
|
|
|
23
|
-
def
|
|
38
|
+
def _get_query(self) -> str:
|
|
24
39
|
"""
|
|
25
40
|
Get the "table_or_query" attribute as a select query
|
|
26
41
|
|
|
27
42
|
Returns:
|
|
28
43
|
str: The converted select query
|
|
29
44
|
"""
|
|
30
|
-
if self.
|
|
31
|
-
query = self.
|
|
45
|
+
if self._table_or_query.strip().lower().startswith('select '):
|
|
46
|
+
query = self._table_or_query
|
|
32
47
|
else:
|
|
33
|
-
query = f'SELECT * FROM {self.
|
|
48
|
+
query = f'SELECT * FROM {self._table_or_query}'
|
|
34
49
|
return query
|
|
35
50
|
|
|
36
|
-
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.ParameterConfig:
|
|
37
53
|
"""
|
|
38
54
|
An abstract method for converting itself into a parameter
|
|
55
|
+
"""
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def _validate_parameter_type(self, ds_param: pc.DataSourceParameterConfig, target_parameter_type: Type[pc.ParameterConfig]) -> None:
|
|
59
|
+
if ds_param.parameter_type != target_parameter_type:
|
|
60
|
+
parameter_type_name = ds_param.parameter_type.__name__
|
|
61
|
+
datasource_type_name = self.__class__.__name__
|
|
62
|
+
raise u.ConfigurationError(f'Invalid widget type "{parameter_type_name}" for {datasource_type_name}')
|
|
63
|
+
|
|
64
|
+
def _get_aggregated_df(self, df: pd.DataFrame, columns_to_include: Iterable[str]) -> pd.DataFrame:
|
|
65
|
+
agg_rules = {}
|
|
66
|
+
for column in columns_to_include:
|
|
67
|
+
if column is not None:
|
|
68
|
+
agg_rules[column] = "first"
|
|
69
|
+
if self._user_group_col is not None:
|
|
70
|
+
agg_rules[self._user_group_col] = list
|
|
71
|
+
if self._parent_id_col is not None:
|
|
72
|
+
agg_rules[self._parent_id_col] = list
|
|
73
|
+
|
|
74
|
+
groupby_dim = self._id_col if self._id_col is not None else df.index
|
|
75
|
+
try:
|
|
76
|
+
df_agg = df.groupby(groupby_dim).agg(agg_rules)
|
|
77
|
+
except KeyError as e:
|
|
78
|
+
raise u.ConfigurationError(e)
|
|
79
|
+
|
|
80
|
+
return df_agg
|
|
81
|
+
|
|
82
|
+
def _get_key_from_record(self, key: Optional[str], record: dict[str, Any], default: Any) -> Any:
|
|
83
|
+
return record[key] if key is not None else default
|
|
84
|
+
|
|
85
|
+
def _get_key_from_record_as_list(self, key: Optional[str], record: dict[str, Any]) -> Iterable[str]:
|
|
86
|
+
value = self._get_key_from_record(key, record, list())
|
|
87
|
+
return [str(x) for x in value]
|
|
88
|
+
|
|
39
89
|
|
|
40
|
-
|
|
90
|
+
@dataclass
|
|
91
|
+
class _SelectionDataSource(DataSource):
|
|
92
|
+
"""
|
|
93
|
+
Abstract class for selection parameter data sources
|
|
94
|
+
"""
|
|
95
|
+
_options_col: str
|
|
96
|
+
_order_by_col: Optional[str] # = field(default=None, kw_only=True)
|
|
97
|
+
_is_default_col: Optional[str] # = field(default=None, kw_only=True)
|
|
98
|
+
_custom_cols: dict[str, str] # = field(default_factory=dict, kw_only=True)
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def __init__(
|
|
102
|
+
self, table_or_query: str, id_col: str, options_col: str, *, order_by_col: Optional[str] = None,
|
|
103
|
+
is_default_col: Optional[str] = None, custom_cols: dict[str, str] = {}, user_group_col: Optional[str] = None,
|
|
104
|
+
parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
105
|
+
) -> None:
|
|
106
|
+
super().__init__(table_or_query, id_col=id_col, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
107
|
+
connection_name=connection_name)
|
|
108
|
+
self._options_col = options_col
|
|
109
|
+
self._order_by_col = order_by_col
|
|
110
|
+
self._is_default_col = is_default_col
|
|
111
|
+
self._custom_cols = custom_cols
|
|
112
|
+
|
|
113
|
+
def _get_all_options(self, df: pd.DataFrame) -> Sequence[po.SelectParameterOption]:
|
|
114
|
+
columns = [self._options_col, self._order_by_col, self._is_default_col, *self._custom_cols.values()]
|
|
115
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
116
|
+
|
|
117
|
+
if self._order_by_col is None:
|
|
118
|
+
df_agg.sort_index(inplace=True)
|
|
119
|
+
else:
|
|
120
|
+
df_agg.sort_values(self._order_by_col, inplace=True)
|
|
121
|
+
|
|
122
|
+
def get_is_default(record: dict[str, Any]) -> bool:
|
|
123
|
+
return int(record[self._is_default_col]) == 1 if self._is_default_col is not None else False
|
|
124
|
+
|
|
125
|
+
def get_custom_fields(record: dict[str, Any]) -> dict[str, Any]:
|
|
126
|
+
result = {}
|
|
127
|
+
for key, val in self._custom_cols.items():
|
|
128
|
+
result[key] = record[val]
|
|
129
|
+
return result
|
|
130
|
+
|
|
131
|
+
records: dict[str, dict[str, Any]] = df_agg.to_dict("index")
|
|
132
|
+
return tuple(
|
|
133
|
+
po.SelectParameterOption(str(id), str(record[self._options_col]),
|
|
134
|
+
is_default=get_is_default(record), custom_fields=get_custom_fields(record),
|
|
135
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
136
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record))
|
|
137
|
+
for id, record in records.items()
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@dataclass
|
|
142
|
+
class SingleSelectDataSource(_SelectionDataSource):
|
|
143
|
+
"""
|
|
144
|
+
Lookup table for single select parameter options
|
|
145
|
+
|
|
146
|
+
Attributes:
|
|
147
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
148
|
+
id_col: The column name of the id
|
|
149
|
+
options_col: The column name of the options
|
|
150
|
+
order_by_col: The column name to order the options by. Orders by the id_col instead if this is None
|
|
151
|
+
is_default_col: The column name that indicates which options are the default
|
|
152
|
+
custom_cols: Dictionary of attribute to column name for custom fields for the SelectParameterOption
|
|
153
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
154
|
+
parent_id_col: The column name of the parent option id that must be selected for this option to be valid
|
|
155
|
+
connection_name: Name of the connection to use defined in connections.py
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
def __init__(
|
|
159
|
+
self, table_or_query: str, id_col: str, options_col: str, *, order_by_col: Optional[str] = None,
|
|
160
|
+
is_default_col: Optional[str] = None, custom_cols: dict[str, str] = {}, user_group_col: Optional[str] = None,
|
|
161
|
+
parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
162
|
+
) -> None:
|
|
163
|
+
"""
|
|
164
|
+
Constructor for SingleSelectDataSource
|
|
165
|
+
|
|
166
|
+
Parameters:
|
|
167
|
+
...see Attributes of SingleSelectDataSource
|
|
168
|
+
"""
|
|
169
|
+
super().__init__(table_or_query, id_col, options_col, order_by_col=order_by_col, is_default_col=is_default_col,
|
|
170
|
+
custom_cols=custom_cols, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
171
|
+
connection_name=connection_name)
|
|
172
|
+
|
|
173
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.SingleSelectParameterConfig:
|
|
174
|
+
"""
|
|
175
|
+
Method to convert the associated DataSourceParameter into a SingleSelectParameterConfig
|
|
176
|
+
|
|
177
|
+
Parameters:
|
|
41
178
|
ds_param: The parameter to convert
|
|
42
179
|
df: The dataframe containing the parameter options data
|
|
43
180
|
|
|
44
181
|
Returns:
|
|
45
182
|
The converted parameter
|
|
46
183
|
"""
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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}')
|
|
184
|
+
self._validate_parameter_type(ds_param, pc.SingleSelectParameterConfig)
|
|
185
|
+
all_options = self._get_all_options(df)
|
|
186
|
+
return pc.SingleSelectParameterConfig(ds_param.name, ds_param.label, all_options, is_hidden=ds_param.is_hidden,
|
|
187
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|
|
57
188
|
|
|
58
189
|
|
|
59
190
|
@dataclass
|
|
60
|
-
class
|
|
191
|
+
class MultiSelectDataSource(_SelectionDataSource):
|
|
61
192
|
"""
|
|
62
|
-
Lookup table for
|
|
193
|
+
Lookup table for single select parameter options
|
|
63
194
|
|
|
64
195
|
Attributes:
|
|
65
196
|
table_or_query: Either the name of the table to use, or a query to run
|
|
@@ -67,24 +198,36 @@ class SelectionDataSource(DataSource):
|
|
|
67
198
|
options_col: The column name of the options
|
|
68
199
|
order_by_col: The column name to order the options by. Orders by the id_col instead if this is None
|
|
69
200
|
is_default_col: The column name that indicates which options are the default
|
|
70
|
-
parent_id_col: The column name of the parent option id that this option belongs to
|
|
71
201
|
custom_cols: Dictionary of attribute to column name for custom fields for the SelectParameterOption
|
|
202
|
+
include_all: Whether applying no selection is equivalent to selecting all. Default is True
|
|
203
|
+
order_matters: Whether the ordering of the selection matters. Default is False
|
|
204
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
205
|
+
parent_id_col: The column name of the parent option id that must be selected for this option to be valid
|
|
72
206
|
connection_name: Name of the connection to use defined in connections.py
|
|
73
207
|
"""
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
208
|
+
_include_all: bool # = field(default=True, kw_only=True)
|
|
209
|
+
_order_matters: bool # = field(default=False, kw_only=True)
|
|
210
|
+
|
|
211
|
+
def __init__(
|
|
212
|
+
self, table_or_query: str, id_col: str, options_col: str, *, order_by_col: Optional[str] = None,
|
|
213
|
+
is_default_col: Optional[str] = None, custom_cols: dict[str, str] = {}, include_all: bool = True, order_matters: bool = False,
|
|
214
|
+
user_group_col: Optional[str] = None, parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
215
|
+
) -> None:
|
|
216
|
+
"""
|
|
217
|
+
Constructor for SingleSelectDataSource
|
|
218
|
+
|
|
219
|
+
Parameters:
|
|
220
|
+
...see Attributes of SingleSelectDataSource
|
|
221
|
+
"""
|
|
222
|
+
super().__init__(table_or_query, id_col, options_col, order_by_col=order_by_col, is_default_col=is_default_col,
|
|
223
|
+
custom_cols=custom_cols, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
224
|
+
connection_name=connection_name)
|
|
225
|
+
self._include_all = include_all
|
|
226
|
+
self._order_matters = order_matters
|
|
227
|
+
|
|
228
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.MultiSelectParameterConfig:
|
|
86
229
|
"""
|
|
87
|
-
Method to convert the associated DataSourceParameter into a
|
|
230
|
+
Method to convert the associated DataSourceParameter into a MultiSelectParameterConfig
|
|
88
231
|
|
|
89
232
|
Parameters:
|
|
90
233
|
ds_param: The parameter to convert
|
|
@@ -93,29 +236,11 @@ class SelectionDataSource(DataSource):
|
|
|
93
236
|
Returns:
|
|
94
237
|
The converted parameter
|
|
95
238
|
"""
|
|
96
|
-
self.
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
def get_custom_fields(row):
|
|
102
|
-
result = {}
|
|
103
|
-
for key, val in self.custom_cols.items():
|
|
104
|
-
result[key] = _utils.get_row_value(row, val)
|
|
105
|
-
return result
|
|
106
|
-
|
|
107
|
-
try:
|
|
108
|
-
df.sort_values(self.order_by_col, inplace=True)
|
|
109
|
-
except KeyError as e:
|
|
110
|
-
raise _utils.ConfigurationError(f'Could not sort on column name "{self.order_by_col}" as it does not exist')
|
|
111
|
-
|
|
112
|
-
options = tuple(
|
|
113
|
-
po.SelectParameterOption(str(_utils.get_row_value(row, self.id_col)), str(_utils.get_row_value(row, self.options_col)),
|
|
114
|
-
is_default=is_default(row), parent_option_id=self._get_parent(row), custom_fields=get_custom_fields(row))
|
|
115
|
-
for _, row in df.iterrows()
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
return ds_param.parameter_class(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden, parent=ds_param.parent)
|
|
239
|
+
self._validate_parameter_type(ds_param, pc.MultiSelectParameterConfig)
|
|
240
|
+
all_options = self._get_all_options(df)
|
|
241
|
+
return pc.MultiSelectParameterConfig(ds_param.name, ds_param.label, all_options, include_all=self._include_all,
|
|
242
|
+
order_matters=self._order_matters, is_hidden=ds_param.is_hidden,
|
|
243
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|
|
119
244
|
|
|
120
245
|
|
|
121
246
|
@dataclass
|
|
@@ -125,19 +250,97 @@ class DateDataSource(DataSource):
|
|
|
125
250
|
|
|
126
251
|
Attributes:
|
|
127
252
|
table_or_query: Either the name of the table to use, or a query to run
|
|
253
|
+
id_col: The column name of the id
|
|
128
254
|
default_date_col: The column name of the default date
|
|
255
|
+
date_format: The format of the default date(s). Defaults to '%Y-%m-%d'
|
|
256
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
129
257
|
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
258
|
+
connection_name: Name of the connection to use defined in connections.py
|
|
259
|
+
"""
|
|
260
|
+
_default_date_col: str
|
|
261
|
+
_date_format: str # = field(default="%Y-%m-%d", kw_only=True)
|
|
262
|
+
|
|
263
|
+
def __init__(
|
|
264
|
+
self, table_or_query: str, default_date_col: str, *, date_format: str = '%Y-%m-%d', id_col: Optional[str] = None,
|
|
265
|
+
user_group_col: Optional[str] = None, parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
266
|
+
) -> None:
|
|
267
|
+
"""
|
|
268
|
+
Constructor for DateDataSource
|
|
269
|
+
|
|
270
|
+
Parameters:
|
|
271
|
+
...see Attributes of DateDataSource
|
|
272
|
+
"""
|
|
273
|
+
super().__init__(table_or_query, id_col=id_col, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
274
|
+
connection_name=connection_name)
|
|
275
|
+
self._default_date_col = default_date_col
|
|
276
|
+
self._date_format = date_format
|
|
277
|
+
|
|
278
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.DateParameterConfig:
|
|
279
|
+
"""
|
|
280
|
+
Method to convert the associated DataSourceParameter into a DateParameterConfig
|
|
281
|
+
|
|
282
|
+
Parameters:
|
|
283
|
+
ds_param: The parameter to convert
|
|
284
|
+
df: The dataframe containing the parameter options data
|
|
285
|
+
|
|
286
|
+
Returns:
|
|
287
|
+
The converted parameter
|
|
288
|
+
"""
|
|
289
|
+
self._validate_parameter_type(ds_param, pc.DateParameterConfig)
|
|
290
|
+
|
|
291
|
+
columns = [self._default_date_col]
|
|
292
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
293
|
+
|
|
294
|
+
records: dict[str, dict[str, Any]] = df_agg.to_dict("index")
|
|
295
|
+
options = tuple(
|
|
296
|
+
po.DateParameterOption(str(record[self._default_date_col]), date_format=self._date_format,
|
|
297
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
298
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record))
|
|
299
|
+
for _, record in records.items()
|
|
300
|
+
)
|
|
301
|
+
return pc.DateParameterConfig(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden,
|
|
302
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
@dataclass
|
|
306
|
+
class DateRangeDataSource(DataSource):
|
|
307
|
+
"""
|
|
308
|
+
Lookup table for date parameter default options
|
|
309
|
+
|
|
310
|
+
Attributes:
|
|
311
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
312
|
+
id_col: The column name of the id
|
|
313
|
+
default_start_date_col: The column name of the default start date
|
|
314
|
+
default_end_date_col: The column name of the default end date
|
|
130
315
|
date_format: The format of the default date(s). Defaults to '%Y-%m-%d'
|
|
316
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
317
|
+
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
131
318
|
connection_name: Name of the connection to use defined in connections.py
|
|
132
319
|
"""
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
320
|
+
_default_start_date_col: str
|
|
321
|
+
_default_end_date_col: str
|
|
322
|
+
_date_format: str # = field(default="%Y-%m-%d", kw_only=True)
|
|
323
|
+
|
|
324
|
+
def __init__(
|
|
325
|
+
self, table_or_query: str, default_start_date_col: str, default_end_date_col: str, *, date_format: str = '%Y-%m-%d',
|
|
326
|
+
id_col: Optional[str] = None, user_group_col: Optional[str] = None, parent_id_col: Optional[str] = None,
|
|
327
|
+
connection_name: Optional[str] = None, **kwargs
|
|
328
|
+
) -> None:
|
|
329
|
+
"""
|
|
330
|
+
Constructor for DateRangeDataSource
|
|
331
|
+
|
|
332
|
+
Parameters:
|
|
333
|
+
...see Attributes of DateRangeDataSource
|
|
334
|
+
"""
|
|
335
|
+
super().__init__(table_or_query, id_col=id_col, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
336
|
+
connection_name=connection_name)
|
|
337
|
+
self._default_start_date_col = default_start_date_col
|
|
338
|
+
self._default_end_date_col = default_end_date_col
|
|
339
|
+
self._date_format = date_format
|
|
137
340
|
|
|
138
|
-
def
|
|
341
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.DateRangeParameterConfig:
|
|
139
342
|
"""
|
|
140
|
-
Method to convert the associated DataSourceParameter into a
|
|
343
|
+
Method to convert the associated DataSourceParameter into a DateRangeParameterConfig
|
|
141
344
|
|
|
142
345
|
Parameters:
|
|
143
346
|
ds_param: The parameter to convert
|
|
@@ -146,22 +349,21 @@ class DateDataSource(DataSource):
|
|
|
146
349
|
Returns:
|
|
147
350
|
The converted parameter
|
|
148
351
|
"""
|
|
149
|
-
self.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
is_hidden=ds_param.is_hidden)
|
|
352
|
+
self._validate_parameter_type(ds_param, pc.DateRangeParameterConfig)
|
|
353
|
+
|
|
354
|
+
columns = [self._default_start_date_col, self._default_end_date_col]
|
|
355
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
356
|
+
|
|
357
|
+
records: dict[str, dict[str, Any]] = df_agg.to_dict("index")
|
|
358
|
+
options = tuple(
|
|
359
|
+
po.DateRangeParameterOption(str(record[self._default_start_date_col]), str(record[self._default_end_date_col]),
|
|
360
|
+
date_format=self._date_format,
|
|
361
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
362
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record))
|
|
363
|
+
for _, record in records.items()
|
|
364
|
+
)
|
|
365
|
+
return pc.DateRangeParameterConfig(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden,
|
|
366
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|
|
165
367
|
|
|
166
368
|
|
|
167
369
|
@dataclass
|
|
@@ -169,15 +371,21 @@ class _NumericDataSource(DataSource):
|
|
|
169
371
|
"""
|
|
170
372
|
Abstract class for number or number range data sources
|
|
171
373
|
"""
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
374
|
+
_min_value_col: str
|
|
375
|
+
_max_value_col: str
|
|
376
|
+
_increment_col: Optional[str] # = field(default=None, kw_only=True)
|
|
377
|
+
|
|
378
|
+
@abstractmethod
|
|
379
|
+
def __init__(
|
|
380
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: Optional[str] = None,
|
|
381
|
+
id_col: Optional[str] = None, user_group_col: Optional[str] = None, parent_id_col: Optional[str] = None,
|
|
382
|
+
connection_name: Optional[str] = None, **kwargs
|
|
383
|
+
) -> None:
|
|
384
|
+
super().__init__(table_or_query, id_col=id_col, user_group_col=user_group_col, parent_id_col=parent_id_col, connection_name=connection_name)
|
|
385
|
+
self._min_value_col = min_value_col
|
|
386
|
+
self._max_value_col = max_value_col
|
|
387
|
+
self._increment_col = increment_col
|
|
175
388
|
|
|
176
|
-
def _convert_helper(self, row: pd.Series) -> Tuple[str, str, str]:
|
|
177
|
-
min_val = str(_utils.get_row_value(row, self.min_value_col))
|
|
178
|
-
max_val = str(_utils.get_row_value(row, self.max_value_col))
|
|
179
|
-
incr_val = str(_utils.get_row_value(row, self.increment_col)) if self.increment_col is not None else '1'
|
|
180
|
-
return min_val, max_val, incr_val
|
|
181
389
|
|
|
182
390
|
@dataclass
|
|
183
391
|
class NumberDataSource(_NumericDataSource):
|
|
@@ -186,20 +394,35 @@ class NumberDataSource(_NumericDataSource):
|
|
|
186
394
|
|
|
187
395
|
Attributes:
|
|
188
396
|
table_or_query: Either the name of the table to use, or a query to run
|
|
397
|
+
id_col: The column name of the id
|
|
189
398
|
min_value_col: The column name of the minimum value
|
|
190
399
|
max_value_col: The column name of the maximum value
|
|
191
400
|
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
192
401
|
default_value_col: The column name of the default value. Defaults to min_value_col if None
|
|
402
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
193
403
|
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
194
404
|
connection_name: Name of the connection to use defined in connections.py
|
|
195
405
|
"""
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
406
|
+
_default_value_col: Optional[str] # = field(default=None, kw_only=True)
|
|
407
|
+
|
|
408
|
+
def __init__(
|
|
409
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: Optional[str] = None,
|
|
410
|
+
default_value_col: Optional[str] = None, id_col: Optional[str] = None, user_group_col: Optional[str] = None,
|
|
411
|
+
parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
412
|
+
) -> None:
|
|
413
|
+
"""
|
|
414
|
+
Constructor for NumberDataSource
|
|
199
415
|
|
|
200
|
-
|
|
416
|
+
Parameters:
|
|
417
|
+
...see Attributes of NumberDataSource
|
|
418
|
+
"""
|
|
419
|
+
super().__init__(table_or_query, min_value_col, max_value_col, increment_col=increment_col, id_col=id_col,
|
|
420
|
+
user_group_col=user_group_col, parent_id_col=parent_id_col, connection_name=connection_name)
|
|
421
|
+
self._default_value_col = default_value_col
|
|
422
|
+
|
|
423
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.NumberParameterConfig:
|
|
201
424
|
"""
|
|
202
|
-
Method to convert the associated DataSourceParameter into a
|
|
425
|
+
Method to convert the associated DataSourceParameter into a NumberParameterConfig
|
|
203
426
|
|
|
204
427
|
Parameters:
|
|
205
428
|
ds_param: The parameter to convert
|
|
@@ -208,51 +431,63 @@ class NumberDataSource(_NumericDataSource):
|
|
|
208
431
|
Returns:
|
|
209
432
|
The converted parameter
|
|
210
433
|
"""
|
|
211
|
-
self.
|
|
434
|
+
self._validate_parameter_type(ds_param, pc.NumberParameterConfig)
|
|
212
435
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
else:
|
|
228
|
-
all_options = tuple(_create_num_param_option(row) for _, row in df.iterrows())
|
|
229
|
-
return p.NumberParameter.WithParent(ds_param.name, ds_param.label, all_options, ds_param.parent,
|
|
230
|
-
is_hidden=ds_param.is_hidden)
|
|
436
|
+
columns = [self._min_value_col, self._max_value_col, self._increment_col, self._default_value_col]
|
|
437
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
438
|
+
|
|
439
|
+
records: dict[str, dict[str, Any]] = df_agg.to_dict("index")
|
|
440
|
+
options = tuple(
|
|
441
|
+
po.NumberParameterOption(record[self._min_value_col], record[self._max_value_col],
|
|
442
|
+
increment=self._get_key_from_record(self._increment_col, record, 1),
|
|
443
|
+
default_value=self._get_key_from_record(self._default_value_col, record, None),
|
|
444
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
445
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record))
|
|
446
|
+
for _, record in records.items()
|
|
447
|
+
)
|
|
448
|
+
return pc.NumberParameterConfig(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden,
|
|
449
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|
|
231
450
|
|
|
232
451
|
|
|
233
452
|
@dataclass
|
|
234
|
-
class
|
|
453
|
+
class NumberRangeDataSource(_NumericDataSource):
|
|
235
454
|
"""
|
|
236
455
|
Lookup table for number range parameter default options
|
|
237
456
|
|
|
238
457
|
Attributes:
|
|
239
|
-
table_or_query: Either the name of the table to use, or a query to
|
|
458
|
+
table_or_query: Either the name of the table to use, or a query to
|
|
459
|
+
id_col: The column name of the id
|
|
240
460
|
min_value_col: The column name of the minimum value
|
|
241
461
|
max_value_col: The column name of the maximum value
|
|
242
462
|
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
243
463
|
default_lower_value_col: The column name of the default lower value. Defaults to min_value_col if None
|
|
244
464
|
default_upper_value_col: The column name of the default upper value. Defaults to max_value_col if None
|
|
465
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
245
466
|
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
246
467
|
connection_name: Name of the connection to use defined in connections.py
|
|
247
468
|
"""
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
469
|
+
_default_lower_value_col: Optional[str] # = field(default=None, kw_only=True)
|
|
470
|
+
_default_upper_value_col: Optional[str] # = field(default=None, kw_only=True)
|
|
471
|
+
|
|
472
|
+
def __init__(
|
|
473
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: Optional[str] = None,
|
|
474
|
+
default_lower_value_col: Optional[str] = None, default_upper_value_col: Optional[str] = None, id_col: Optional[str] = None,
|
|
475
|
+
user_group_col: Optional[str] = None, parent_id_col: Optional[str] = None, connection_name: Optional[str] = None, **kwargs
|
|
476
|
+
) -> None:
|
|
477
|
+
"""
|
|
478
|
+
Constructor for NumRangeDataSource
|
|
479
|
+
|
|
480
|
+
Parameters:
|
|
481
|
+
...see Attributes of NumRangeDataSource
|
|
482
|
+
"""
|
|
483
|
+
super().__init__(table_or_query, min_value_col, max_value_col, increment_col=increment_col, id_col=id_col,
|
|
484
|
+
user_group_col=user_group_col, parent_id_col=parent_id_col, connection_name=connection_name)
|
|
485
|
+
self._default_lower_value_col = default_lower_value_col
|
|
486
|
+
self._default_upper_value_col = default_upper_value_col
|
|
252
487
|
|
|
253
|
-
def
|
|
488
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pd.DataFrame) -> pc.NumberRangeParameterConfig:
|
|
254
489
|
"""
|
|
255
|
-
Method to convert the associated DataSourceParameter into a
|
|
490
|
+
Method to convert the associated DataSourceParameter into a NumberRangeParameterConfig
|
|
256
491
|
|
|
257
492
|
Parameters:
|
|
258
493
|
ds_param: The parameter to convert
|
|
@@ -261,30 +496,20 @@ class NumRangeDataSource(_NumericDataSource):
|
|
|
261
496
|
Returns:
|
|
262
497
|
The converted parameter
|
|
263
498
|
"""
|
|
264
|
-
self.
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
if ds_param.parent is None:
|
|
282
|
-
row = df.iloc[0]
|
|
283
|
-
min_value, max_value, increment = self._convert_helper(row)
|
|
284
|
-
lower_value, upper_value = _get_default_lower_upper_values(row)
|
|
285
|
-
return p.NumRangeParameter(ds_param.name, ds_param.label, min_value, max_value, increment,
|
|
286
|
-
lower_value, upper_value, is_hidden=ds_param.is_hidden)
|
|
287
|
-
else:
|
|
288
|
-
all_options = tuple(_create_range_param_option(row) for _, row in df.iterrows())
|
|
289
|
-
return p.NumRangeParameter.WithParent(ds_param.name, ds_param.label, all_options, ds_param.parent,
|
|
290
|
-
is_hidden=ds_param.is_hidden)
|
|
499
|
+
self._validate_parameter_type(ds_param, pc.NumberRangeParameterConfig)
|
|
500
|
+
|
|
501
|
+
columns = [self._min_value_col, self._max_value_col, self._increment_col, self._default_lower_value_col, self._default_upper_value_col]
|
|
502
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
503
|
+
|
|
504
|
+
records: dict[str, Any] = df_agg.to_dict("index")
|
|
505
|
+
options = tuple(
|
|
506
|
+
po.NumberRangeParameterOption(record[self._min_value_col], record[self._max_value_col],
|
|
507
|
+
increment=self._get_key_from_record(self._increment_col, record, 1),
|
|
508
|
+
default_lower_value=self._get_key_from_record(self._default_lower_value_col, record, None),
|
|
509
|
+
default_upper_value=self._get_key_from_record(self._default_upper_value_col, record, None),
|
|
510
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
511
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record))
|
|
512
|
+
for _, record in records.items()
|
|
513
|
+
)
|
|
514
|
+
return pc.NumberRangeParameterConfig(ds_param.name, ds_param.label, options, is_hidden=ds_param.is_hidden,
|
|
515
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name)
|