squirrels 0.5.0b2__py3-none-any.whl → 0.5.0b3__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 -460
- dateutils/_enums.py +25 -0
- dateutils/_implementation.py +409 -0
- dateutils/types.py +6 -0
- squirrels/__init__.py +7 -13
- squirrels/_api_server.py +5 -5
- squirrels/{arguments/init_time_args.py → _arguments/_init_time_args.py} +2 -2
- squirrels/{arguments/run_time_args.py → _arguments/_run_time_args.py} +4 -26
- squirrels/_auth.py +2 -2
- squirrels/_connection_set.py +5 -5
- squirrels/_constants.py +1 -1
- squirrels/_dashboard_types.py +82 -0
- squirrels/_dashboards_io.py +2 -2
- squirrels/_data_sources.py +564 -0
- squirrels/_exceptions.py +1 -1
- squirrels/_initializer.py +31 -26
- squirrels/_manifest.py +5 -5
- squirrels/_model_configs.py +2 -2
- squirrels/_model_queries.py +1 -1
- squirrels/_models.py +28 -16
- squirrels/{package_data → _package_data}/base_project/dashboards/dashboard_example.py +4 -4
- squirrels/{package_data → _package_data}/base_project/dashboards/dashboard_example.yml +2 -2
- 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/dbviews/dbview_example.sql +1 -1
- squirrels/_package_data/base_project/models/federates/federate_example.py +41 -0
- squirrels/_package_data/base_project/models/federates/federate_example.sql +25 -0
- squirrels/{package_data → _package_data}/base_project/models/federates/federate_example.yml +6 -6
- squirrels/{package_data → _package_data}/base_project/parameters.yml +9 -8
- squirrels/_package_data/base_project/pyconfigs/connections.py +14 -0
- squirrels/{package_data → _package_data}/base_project/pyconfigs/context.py +14 -16
- squirrels/{package_data → _package_data}/base_project/pyconfigs/parameters.py +13 -8
- squirrels/{package_data → _package_data}/base_project/pyconfigs/user.py +2 -2
- squirrels/_parameter_configs.py +34 -34
- squirrels/_parameter_options.py +348 -0
- squirrels/_parameter_sets.py +18 -18
- squirrels/_parameters.py +1266 -0
- squirrels/_project.py +37 -12
- squirrels/_utils.py +4 -2
- squirrels/arguments.py +2 -0
- squirrels/connections.py +1 -0
- squirrels/dashboards.py +1 -82
- squirrels/data_sources.py +8 -563
- squirrels/parameter_options.py +8 -348
- squirrels/parameters.py +9 -1266
- squirrels/types.py +11 -0
- {squirrels-0.5.0b2.dist-info → squirrels-0.5.0b3.dist-info}/METADATA +1 -1
- squirrels-0.5.0b3.dist-info/RECORD +80 -0
- squirrels/package_data/base_project/macros/macros_example.sql +0 -15
- 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-0.5.0b2.dist-info/RECORD +0 -70
- /squirrels/{dataset_result.py → _dataset_types.py} +0 -0
- /squirrels/{package_data → _package_data}/base_project/.env +0 -0
- /squirrels/{package_data → _package_data}/base_project/.env.example +0 -0
- /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/connections.yml +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 → _package_data}/base_project/duckdb_init.sql +0 -0
- /squirrels/{package_data/base_project/.gitignore → _package_data/base_project/gitignore} +0 -0
- /squirrels/{package_data → _package_data}/base_project/models/builds/build_example.yml +0 -0
- /squirrels/{package_data → _package_data}/base_project/models/dbviews/dbview_example.yml +0 -0
- /squirrels/{package_data → _package_data}/base_project/models/sources.yml +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.csv +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.yml +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.csv +0 -0
- /squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.yml +0 -0
- /squirrels/{package_data → _package_data}/base_project/squirrels.yml.j2 +0 -0
- /squirrels/{package_data → _package_data}/base_project/tmp/.gitignore +0 -0
- {squirrels-0.5.0b2.dist-info → squirrels-0.5.0b3.dist-info}/WHEEL +0 -0
- {squirrels-0.5.0b2.dist-info → squirrels-0.5.0b3.dist-info}/entry_points.txt +0 -0
- {squirrels-0.5.0b2.dist-info → squirrels-0.5.0b3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import matplotlib.figure as figure, io, abc, typing
|
|
2
|
+
|
|
3
|
+
from . import _constants as c
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Dashboard(metaclass=abc.ABCMeta):
|
|
7
|
+
"""
|
|
8
|
+
Abstract parent class for all Dashboard classes.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
@abc.abstractmethod
|
|
13
|
+
def _content(self) -> bytes | str:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
@abc.abstractmethod
|
|
18
|
+
def _format(self) -> str:
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class PngDashboard(Dashboard):
|
|
23
|
+
"""
|
|
24
|
+
Instantiate a Dashboard in PNG format from a matplotlib figure or bytes
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, content: figure.Figure | io.BytesIO | bytes) -> None:
|
|
28
|
+
"""
|
|
29
|
+
Constructor for PngDashboard
|
|
30
|
+
|
|
31
|
+
Arguments:
|
|
32
|
+
content: The content of the dashboard as a matplotlib.figure.Figure or bytes
|
|
33
|
+
"""
|
|
34
|
+
if isinstance(content, figure.Figure):
|
|
35
|
+
buffer = io.BytesIO()
|
|
36
|
+
content.savefig(buffer, format=c.PNG)
|
|
37
|
+
content = buffer.getvalue()
|
|
38
|
+
|
|
39
|
+
if isinstance(content, io.BytesIO):
|
|
40
|
+
content = content.getvalue()
|
|
41
|
+
|
|
42
|
+
self.__content = content
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def _content(self) -> bytes:
|
|
46
|
+
return self.__content
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def _format(self) -> typing.Literal['png']:
|
|
50
|
+
return c.PNG
|
|
51
|
+
|
|
52
|
+
def _repr_png_(self):
|
|
53
|
+
return self._content
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class HtmlDashboard(Dashboard):
|
|
57
|
+
"""
|
|
58
|
+
Instantiate a Dashboard from an HTML string
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
def __init__(self, content: io.StringIO | str) -> None:
|
|
62
|
+
"""
|
|
63
|
+
Constructor for HtmlDashboard
|
|
64
|
+
|
|
65
|
+
Arguments:
|
|
66
|
+
content: The content of the dashboard as HTML string
|
|
67
|
+
"""
|
|
68
|
+
if isinstance(content, io.StringIO):
|
|
69
|
+
content = content.getvalue()
|
|
70
|
+
|
|
71
|
+
self.__content = content
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def _content(self) -> str:
|
|
75
|
+
return self.__content
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def _format(self) -> typing.Literal['html']:
|
|
79
|
+
return c.HTML
|
|
80
|
+
|
|
81
|
+
def _repr_html_(self):
|
|
82
|
+
return self._content
|
squirrels/_dashboards_io.py
CHANGED
|
@@ -4,11 +4,11 @@ from dataclasses import dataclass
|
|
|
4
4
|
from pydantic import BaseModel, Field
|
|
5
5
|
import os, time
|
|
6
6
|
|
|
7
|
-
from .
|
|
7
|
+
from ._arguments._run_time_args import DashboardArgs
|
|
8
8
|
from ._py_module import PyModule
|
|
9
9
|
from ._manifest import AnalyticsOutputConfig
|
|
10
10
|
from ._exceptions import InvalidInputError, ConfigurationError, FileExecutionError
|
|
11
|
-
from . import _constants as c,
|
|
11
|
+
from . import _constants as c, _dashboard_types as d, _utils as u
|
|
12
12
|
|
|
13
13
|
T = TypeVar('T', bound=d.Dashboard)
|
|
14
14
|
|
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
import polars as pl, typing as t, abc
|
|
4
|
+
|
|
5
|
+
from . import _parameter_configs as pc, _parameter_options as po
|
|
6
|
+
from ._exceptions import ConfigurationError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class DataSource(metaclass=abc.ABCMeta):
|
|
11
|
+
"""
|
|
12
|
+
Abstract class for lookup tables coming from a database
|
|
13
|
+
"""
|
|
14
|
+
_table_or_query: str
|
|
15
|
+
_id_col: str | None
|
|
16
|
+
_is_from_seeds: bool
|
|
17
|
+
_user_group_col: str | None
|
|
18
|
+
_parent_id_col: str | None
|
|
19
|
+
_connection: str | None
|
|
20
|
+
|
|
21
|
+
@abc.abstractmethod
|
|
22
|
+
def __init__(
|
|
23
|
+
self, table_or_query: str, *, id_col: str | None = None, from_seeds: bool = False, user_group_col: str | None = None,
|
|
24
|
+
parent_id_col: str | None = None, connection: str | None = None, **kwargs
|
|
25
|
+
) -> None:
|
|
26
|
+
self._table_or_query = table_or_query
|
|
27
|
+
self._id_col = id_col
|
|
28
|
+
self._is_from_seeds = from_seeds
|
|
29
|
+
self._user_group_col = user_group_col
|
|
30
|
+
self._parent_id_col = parent_id_col
|
|
31
|
+
self._connection = connection
|
|
32
|
+
|
|
33
|
+
def _get_connection_name(self, default_conn_name: str) -> str:
|
|
34
|
+
return self._connection if self._connection is not None else default_conn_name
|
|
35
|
+
|
|
36
|
+
def _get_query(self) -> str:
|
|
37
|
+
"""
|
|
38
|
+
Get the "table_or_query" attribute as a select query
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
str: The converted select query
|
|
42
|
+
"""
|
|
43
|
+
if self._table_or_query.strip().lower().startswith('select '):
|
|
44
|
+
query = self._table_or_query
|
|
45
|
+
else:
|
|
46
|
+
query = f'SELECT * FROM {self._table_or_query}'
|
|
47
|
+
return query
|
|
48
|
+
|
|
49
|
+
@abc.abstractmethod
|
|
50
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.ParameterConfig:
|
|
51
|
+
"""
|
|
52
|
+
An abstract method for converting itself into a parameter
|
|
53
|
+
"""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
def _validate_parameter_type(self, ds_param: pc.DataSourceParameterConfig, target_parameter_type: t.Type[pc.ParameterConfig]) -> None:
|
|
57
|
+
if ds_param.parameter_type != target_parameter_type:
|
|
58
|
+
parameter_type_name = ds_param.parameter_type.__name__
|
|
59
|
+
datasource_type_name = self.__class__.__name__
|
|
60
|
+
raise ConfigurationError(f'Invalid widget type "{parameter_type_name}" for {datasource_type_name}')
|
|
61
|
+
|
|
62
|
+
def _get_aggregated_df(self, df: pl.DataFrame, columns_to_include: t.Iterable[str]) -> pl.DataFrame:
|
|
63
|
+
if self._id_col is None:
|
|
64
|
+
return df
|
|
65
|
+
|
|
66
|
+
agg_rules = []
|
|
67
|
+
for column in columns_to_include:
|
|
68
|
+
if column is not None:
|
|
69
|
+
agg_rules.append(pl.first(column))
|
|
70
|
+
if self._user_group_col is not None:
|
|
71
|
+
agg_rules.append(pl.col(self._user_group_col))
|
|
72
|
+
if self._parent_id_col is not None:
|
|
73
|
+
agg_rules.append(pl.col(self._parent_id_col))
|
|
74
|
+
|
|
75
|
+
try:
|
|
76
|
+
df_agg = df.group_by(self._id_col).agg(agg_rules).sort(by=self._id_col)
|
|
77
|
+
except pl.exceptions.ColumnNotFoundError as e:
|
|
78
|
+
raise ConfigurationError(e)
|
|
79
|
+
|
|
80
|
+
return df_agg
|
|
81
|
+
|
|
82
|
+
def _get_key_from_record(self, key: str | None, record: dict[t.Hashable, t.Any], default: t.Any) -> t.Any:
|
|
83
|
+
return record[key] if key is not None else default
|
|
84
|
+
|
|
85
|
+
def _get_key_from_record_as_list(self, key: str | None, record: dict[t.Hashable, t.Any]) -> t.Iterable[str]:
|
|
86
|
+
value = self._get_key_from_record(key, record, list())
|
|
87
|
+
return [str(x) for x in value]
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@dataclass
|
|
91
|
+
class _SelectionDataSource(DataSource):
|
|
92
|
+
"""
|
|
93
|
+
Abstract class for selection parameter data sources
|
|
94
|
+
"""
|
|
95
|
+
_options_col: str
|
|
96
|
+
_order_by_col: str | None
|
|
97
|
+
_is_default_col: str | None
|
|
98
|
+
_custom_cols: dict[str, str]
|
|
99
|
+
|
|
100
|
+
@abc.abstractmethod
|
|
101
|
+
def __init__(
|
|
102
|
+
self, table_or_query: str, id_col: str, options_col: str, *, order_by_col: str | None = None,
|
|
103
|
+
is_default_col: str | None = None, custom_cols: dict[str, str] = {}, from_seeds: bool = False,
|
|
104
|
+
user_group_col: str | None = None, parent_id_col: str | None = None, connection: str | None = None,
|
|
105
|
+
**kwargs
|
|
106
|
+
) -> None:
|
|
107
|
+
super().__init__(
|
|
108
|
+
table_or_query, id_col=id_col, from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
109
|
+
connection=connection
|
|
110
|
+
)
|
|
111
|
+
self._options_col = options_col
|
|
112
|
+
self._order_by_col = order_by_col
|
|
113
|
+
self._is_default_col = is_default_col
|
|
114
|
+
self._custom_cols = custom_cols
|
|
115
|
+
|
|
116
|
+
def _get_all_options(self, df: pl.DataFrame) -> t.Sequence[po.SelectParameterOption]:
|
|
117
|
+
columns = [self._options_col, self._order_by_col, self._is_default_col, *self._custom_cols.values()]
|
|
118
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
119
|
+
|
|
120
|
+
if self._order_by_col is None:
|
|
121
|
+
df_agg = df_agg.sort(by=self._id_col)
|
|
122
|
+
else:
|
|
123
|
+
df_agg = df_agg.sort(by=self._order_by_col)
|
|
124
|
+
|
|
125
|
+
def get_is_default(record: dict[t.Hashable, t.Any]) -> bool:
|
|
126
|
+
return int(record[self._is_default_col]) == 1 if self._is_default_col is not None else False
|
|
127
|
+
|
|
128
|
+
def get_custom_fields(record: dict[t.Hashable, t.Any]) -> dict[str, t.Any]:
|
|
129
|
+
result = {}
|
|
130
|
+
for key, val in self._custom_cols.items():
|
|
131
|
+
result[key] = record[val]
|
|
132
|
+
return result
|
|
133
|
+
|
|
134
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
135
|
+
return tuple(
|
|
136
|
+
po.SelectParameterOption(
|
|
137
|
+
str(record[self._id_col]), str(record[self._options_col]),
|
|
138
|
+
is_default=get_is_default(record), custom_fields=get_custom_fields(record),
|
|
139
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
140
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
141
|
+
)
|
|
142
|
+
for record in records
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
@dataclass
|
|
147
|
+
class SelectDataSource(_SelectionDataSource):
|
|
148
|
+
"""
|
|
149
|
+
Lookup table for select parameter options
|
|
150
|
+
"""
|
|
151
|
+
|
|
152
|
+
def __init__(
|
|
153
|
+
self, table_or_query: str, id_col: str, options_col: str, *, order_by_col: str | None = None,
|
|
154
|
+
is_default_col: str | None = None, custom_cols: dict[str, str] = {}, from_seeds: bool = False,
|
|
155
|
+
user_group_col: str | None = None, parent_id_col: str | None = None, connection: str | None = None,
|
|
156
|
+
**kwargs
|
|
157
|
+
) -> None:
|
|
158
|
+
"""
|
|
159
|
+
Constructor for SelectDataSource
|
|
160
|
+
|
|
161
|
+
Arguments:
|
|
162
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
163
|
+
id_col: The column name of the id
|
|
164
|
+
options_col: The column name of the options
|
|
165
|
+
order_by_col: The column name to order the options by. Orders by the id_col instead if this is None
|
|
166
|
+
is_default_col: The column name that indicates which options are the default
|
|
167
|
+
custom_cols: Dictionary of attribute to column name for custom fields for the SelectParameterOption
|
|
168
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
169
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
170
|
+
parent_id_col: The column name of the parent option id that must be selected for this option to be valid
|
|
171
|
+
connection: Name of the connection to use defined in connections.py
|
|
172
|
+
"""
|
|
173
|
+
super().__init__(
|
|
174
|
+
table_or_query, id_col, options_col, order_by_col=order_by_col, is_default_col=is_default_col, custom_cols=custom_cols,
|
|
175
|
+
from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col, connection=connection
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.SelectionParameterConfig:
|
|
179
|
+
"""
|
|
180
|
+
Method to convert the associated DataSourceParameter into a SingleSelectParameterConfig or MultiSelectParameterConfig
|
|
181
|
+
|
|
182
|
+
Arguments:
|
|
183
|
+
ds_param: The parameter to convert
|
|
184
|
+
df: The dataframe containing the parameter options data
|
|
185
|
+
|
|
186
|
+
Returns:
|
|
187
|
+
The converted parameter
|
|
188
|
+
"""
|
|
189
|
+
all_options = self._get_all_options(df)
|
|
190
|
+
if ds_param.parameter_type == pc.SingleSelectParameterConfig:
|
|
191
|
+
return pc.SingleSelectParameterConfig(
|
|
192
|
+
ds_param.name, ds_param.label, all_options, description=ds_param.description,
|
|
193
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
194
|
+
)
|
|
195
|
+
elif ds_param.parameter_type == pc.MultiSelectParameterConfig:
|
|
196
|
+
return pc.MultiSelectParameterConfig(
|
|
197
|
+
ds_param.name, ds_param.label, all_options, description=ds_param.description,
|
|
198
|
+
user_attribute=ds_param.user_attribute, parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
199
|
+
)
|
|
200
|
+
else:
|
|
201
|
+
raise ConfigurationError(f'Invalid widget type "{ds_param.parameter_type}" for SelectDataSource')
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
@dataclass
|
|
205
|
+
class DateDataSource(DataSource):
|
|
206
|
+
"""
|
|
207
|
+
Lookup table for date parameter default options
|
|
208
|
+
"""
|
|
209
|
+
_default_date_col: str
|
|
210
|
+
_date_format: str
|
|
211
|
+
|
|
212
|
+
def __init__(
|
|
213
|
+
self, table_or_query: str, default_date_col: str, *, min_date_col: str | None = None,
|
|
214
|
+
max_date_col: str | None = None, date_format: str = '%Y-%m-%d', id_col: str | None = None,
|
|
215
|
+
from_seeds: bool = False, user_group_col: str | None = None, parent_id_col: str | None = None,
|
|
216
|
+
connection: str | None = None, **kwargs
|
|
217
|
+
) -> None:
|
|
218
|
+
"""
|
|
219
|
+
Constructor for DateDataSource
|
|
220
|
+
|
|
221
|
+
Arguments:
|
|
222
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
223
|
+
default_date_col: The column name of the default date
|
|
224
|
+
date_format: The format of the default date(s). Defaults to '%Y-%m-%d'
|
|
225
|
+
id_col: The column name of the id
|
|
226
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
227
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
228
|
+
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
229
|
+
connection: Name of the connection to use defined in connections.py
|
|
230
|
+
"""
|
|
231
|
+
super().__init__(
|
|
232
|
+
table_or_query, id_col=id_col, from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
233
|
+
connection=connection
|
|
234
|
+
)
|
|
235
|
+
self._default_date_col = default_date_col
|
|
236
|
+
self._min_date_col = min_date_col
|
|
237
|
+
self._max_date_col = max_date_col
|
|
238
|
+
self._date_format = date_format
|
|
239
|
+
|
|
240
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.DateParameterConfig:
|
|
241
|
+
"""
|
|
242
|
+
Method to convert the associated DataSourceParameter into a DateParameterConfig
|
|
243
|
+
|
|
244
|
+
Arguments:
|
|
245
|
+
ds_param: The parameter to convert
|
|
246
|
+
df: The dataframe containing the parameter options data
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
The converted parameter
|
|
250
|
+
"""
|
|
251
|
+
self._validate_parameter_type(ds_param, pc.DateParameterConfig)
|
|
252
|
+
|
|
253
|
+
columns = [self._default_date_col, self._min_date_col, self._max_date_col]
|
|
254
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
255
|
+
|
|
256
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
257
|
+
options = tuple(
|
|
258
|
+
po.DateParameterOption(
|
|
259
|
+
str(record[self._default_date_col]), date_format=self._date_format,
|
|
260
|
+
min_date = str(record[self._min_date_col]) if self._min_date_col else None,
|
|
261
|
+
max_date = str(record[self._max_date_col]) if self._max_date_col else None,
|
|
262
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
263
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
264
|
+
)
|
|
265
|
+
for record in records
|
|
266
|
+
)
|
|
267
|
+
return pc.DateParameterConfig(
|
|
268
|
+
ds_param.name, ds_param.label, options, description=ds_param.description, user_attribute=ds_param.user_attribute,
|
|
269
|
+
parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
270
|
+
)
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
@dataclass
|
|
274
|
+
class DateRangeDataSource(DataSource):
|
|
275
|
+
"""
|
|
276
|
+
Lookup table for date parameter default options
|
|
277
|
+
"""
|
|
278
|
+
_default_start_date_col: str
|
|
279
|
+
_default_end_date_col: str
|
|
280
|
+
_date_format: str
|
|
281
|
+
|
|
282
|
+
def __init__(
|
|
283
|
+
self, table_or_query: str, default_start_date_col: str, default_end_date_col: str, *, date_format: str = '%Y-%m-%d',
|
|
284
|
+
min_date_col: str | None = None, max_date_col: str | None = None, id_col: str | None = None, from_seeds: bool = False,
|
|
285
|
+
user_group_col: str | None = None, parent_id_col: str | None = None, connection: str | None = None, **kwargs
|
|
286
|
+
) -> None:
|
|
287
|
+
"""
|
|
288
|
+
Constructor for DateRangeDataSource
|
|
289
|
+
|
|
290
|
+
Arguments:
|
|
291
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
292
|
+
default_start_date_col: The column name of the default start date
|
|
293
|
+
default_end_date_col: The column name of the default end date
|
|
294
|
+
date_format: The format of the default date(s). Defaults to '%Y-%m-%d'
|
|
295
|
+
id_col: The column name of the id
|
|
296
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
297
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
298
|
+
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
299
|
+
connection: Name of the connection to use defined in connections.py
|
|
300
|
+
"""
|
|
301
|
+
super().__init__(
|
|
302
|
+
table_or_query, id_col=id_col, from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
303
|
+
connection=connection
|
|
304
|
+
)
|
|
305
|
+
self._default_start_date_col = default_start_date_col
|
|
306
|
+
self._default_end_date_col = default_end_date_col
|
|
307
|
+
self._min_date_col = min_date_col
|
|
308
|
+
self._max_date_col = max_date_col
|
|
309
|
+
self._date_format = date_format
|
|
310
|
+
|
|
311
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.DateRangeParameterConfig:
|
|
312
|
+
"""
|
|
313
|
+
Method to convert the associated DataSourceParameter into a DateRangeParameterConfig
|
|
314
|
+
|
|
315
|
+
Arguments:
|
|
316
|
+
ds_param: The parameter to convert
|
|
317
|
+
df: The dataframe containing the parameter options data
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
The converted parameter
|
|
321
|
+
"""
|
|
322
|
+
self._validate_parameter_type(ds_param, pc.DateRangeParameterConfig)
|
|
323
|
+
|
|
324
|
+
columns = [self._default_start_date_col, self._default_end_date_col, self._min_date_col, self._max_date_col]
|
|
325
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
326
|
+
|
|
327
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
328
|
+
options = tuple(
|
|
329
|
+
po.DateRangeParameterOption(
|
|
330
|
+
str(record[self._default_start_date_col]), str(record[self._default_end_date_col]),
|
|
331
|
+
min_date=str(record[self._min_date_col]) if self._min_date_col else None,
|
|
332
|
+
max_date=str(record[self._max_date_col]) if self._max_date_col else None,
|
|
333
|
+
date_format=self._date_format,
|
|
334
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
335
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
336
|
+
)
|
|
337
|
+
for record in records
|
|
338
|
+
)
|
|
339
|
+
return pc.DateRangeParameterConfig(
|
|
340
|
+
ds_param.name, ds_param.label, options, description=ds_param.description, user_attribute=ds_param.user_attribute,
|
|
341
|
+
parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
@dataclass
|
|
346
|
+
class _NumericDataSource(DataSource):
|
|
347
|
+
"""
|
|
348
|
+
Abstract class for number or number range data sources
|
|
349
|
+
"""
|
|
350
|
+
_min_value_col: str
|
|
351
|
+
_max_value_col: str
|
|
352
|
+
_increment_col: str | None
|
|
353
|
+
|
|
354
|
+
@abc.abstractmethod
|
|
355
|
+
def __init__(
|
|
356
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: str | None = None,
|
|
357
|
+
id_col: str | None = None, from_seeds: bool = False, user_group_col: str | None = None,
|
|
358
|
+
parent_id_col: str | None = None, connection: str | None = None, **kwargs
|
|
359
|
+
) -> None:
|
|
360
|
+
super().__init__(
|
|
361
|
+
table_or_query, id_col=id_col, from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
362
|
+
connection=connection
|
|
363
|
+
)
|
|
364
|
+
self._min_value_col = min_value_col
|
|
365
|
+
self._max_value_col = max_value_col
|
|
366
|
+
self._increment_col = increment_col
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
@dataclass
|
|
370
|
+
class NumberDataSource(_NumericDataSource):
|
|
371
|
+
"""
|
|
372
|
+
Lookup table for number parameter default options
|
|
373
|
+
"""
|
|
374
|
+
_default_value_col: str | None
|
|
375
|
+
|
|
376
|
+
def __init__(
|
|
377
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: str | None = None,
|
|
378
|
+
default_value_col: str | None = None, id_col: str | None = None, from_seeds: bool = False,
|
|
379
|
+
user_group_col: str | None = None, parent_id_col: str | None = None, connection: str | None = None, **kwargs
|
|
380
|
+
) -> None:
|
|
381
|
+
"""
|
|
382
|
+
Constructor for NumberDataSource
|
|
383
|
+
|
|
384
|
+
Arguments:
|
|
385
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
386
|
+
min_value_col: The column name of the minimum value
|
|
387
|
+
max_value_col: The column name of the maximum value
|
|
388
|
+
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
389
|
+
default_value_col: The column name of the default value. Defaults to min_value_col if None
|
|
390
|
+
id_col: The column name of the id
|
|
391
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
392
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
393
|
+
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
394
|
+
connection: Name of the connection to use defined in connections.py
|
|
395
|
+
"""
|
|
396
|
+
super().__init__(
|
|
397
|
+
table_or_query, min_value_col, max_value_col, increment_col=increment_col, id_col=id_col, from_seeds=from_seeds,
|
|
398
|
+
user_group_col=user_group_col, parent_id_col=parent_id_col, connection=connection
|
|
399
|
+
)
|
|
400
|
+
self._default_value_col = default_value_col
|
|
401
|
+
|
|
402
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.NumberParameterConfig:
|
|
403
|
+
"""
|
|
404
|
+
Method to convert the associated DataSourceParameter into a NumberParameterConfig
|
|
405
|
+
|
|
406
|
+
Arguments:
|
|
407
|
+
ds_param: The parameter to convert
|
|
408
|
+
df: The dataframe containing the parameter options data
|
|
409
|
+
|
|
410
|
+
Returns:
|
|
411
|
+
The converted parameter
|
|
412
|
+
"""
|
|
413
|
+
self._validate_parameter_type(ds_param, pc.NumberParameterConfig)
|
|
414
|
+
|
|
415
|
+
columns = [self._min_value_col, self._max_value_col, self._increment_col, self._default_value_col]
|
|
416
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
417
|
+
|
|
418
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
419
|
+
options = tuple(
|
|
420
|
+
po.NumberParameterOption(
|
|
421
|
+
record[self._min_value_col], record[self._max_value_col],
|
|
422
|
+
increment=self._get_key_from_record(self._increment_col, record, 1),
|
|
423
|
+
default_value=self._get_key_from_record(self._default_value_col, record, None),
|
|
424
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
425
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
426
|
+
)
|
|
427
|
+
for record in records
|
|
428
|
+
)
|
|
429
|
+
return pc.NumberParameterConfig(
|
|
430
|
+
ds_param.name, ds_param.label, options, description=ds_param.description, user_attribute=ds_param.user_attribute,
|
|
431
|
+
parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
432
|
+
)
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
@dataclass
|
|
436
|
+
class NumberRangeDataSource(_NumericDataSource):
|
|
437
|
+
"""
|
|
438
|
+
Lookup table for number range parameter default options
|
|
439
|
+
"""
|
|
440
|
+
_default_lower_value_col: str | None
|
|
441
|
+
_default_upper_value_col: str | None
|
|
442
|
+
|
|
443
|
+
def __init__(
|
|
444
|
+
self, table_or_query: str, min_value_col: str, max_value_col: str, *, increment_col: str | None = None,
|
|
445
|
+
default_lower_value_col: str | None = None, default_upper_value_col: str | None = None, id_col: str | None = None,
|
|
446
|
+
from_seeds: bool = False, user_group_col: str | None = None, parent_id_col: str | None = None,
|
|
447
|
+
connection: str | None = None, **kwargs
|
|
448
|
+
) -> None:
|
|
449
|
+
"""
|
|
450
|
+
Constructor for NumRangeDataSource
|
|
451
|
+
|
|
452
|
+
Arguments:
|
|
453
|
+
table_or_query: Either the name of the table to use, or a query to
|
|
454
|
+
min_value_col: The column name of the minimum value
|
|
455
|
+
max_value_col: The column name of the maximum value
|
|
456
|
+
increment_col: The column name of the increment value. Defaults to column of 1's if None
|
|
457
|
+
default_lower_value_col: The column name of the default lower value. Defaults to min_value_col if None
|
|
458
|
+
default_upper_value_col: The column name of the default upper value. Defaults to max_value_col if None
|
|
459
|
+
id_col: The column name of the id
|
|
460
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
461
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
462
|
+
parent_id_col: The column name of the parent option id that the default value belongs to
|
|
463
|
+
connection: Name of the connection to use defined in connections.py
|
|
464
|
+
"""
|
|
465
|
+
super().__init__(
|
|
466
|
+
table_or_query, min_value_col, max_value_col, increment_col=increment_col, id_col=id_col, from_seeds=from_seeds,
|
|
467
|
+
user_group_col=user_group_col, parent_id_col=parent_id_col, connection=connection
|
|
468
|
+
)
|
|
469
|
+
self._default_lower_value_col = default_lower_value_col
|
|
470
|
+
self._default_upper_value_col = default_upper_value_col
|
|
471
|
+
|
|
472
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.NumberRangeParameterConfig:
|
|
473
|
+
"""
|
|
474
|
+
Method to convert the associated DataSourceParameter into a NumberRangeParameterConfig
|
|
475
|
+
|
|
476
|
+
Arguments:
|
|
477
|
+
ds_param: The parameter to convert
|
|
478
|
+
df: The dataframe containing the parameter options data
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
The converted parameter
|
|
482
|
+
"""
|
|
483
|
+
self._validate_parameter_type(ds_param, pc.NumberRangeParameterConfig)
|
|
484
|
+
|
|
485
|
+
columns = [self._min_value_col, self._max_value_col, self._increment_col, self._default_lower_value_col, self._default_upper_value_col]
|
|
486
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
487
|
+
|
|
488
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
489
|
+
options = tuple(
|
|
490
|
+
po.NumberRangeParameterOption(
|
|
491
|
+
record[self._min_value_col], record[self._max_value_col],
|
|
492
|
+
increment=self._get_key_from_record(self._increment_col, record, 1),
|
|
493
|
+
default_lower_value=self._get_key_from_record(self._default_lower_value_col, record, None),
|
|
494
|
+
default_upper_value=self._get_key_from_record(self._default_upper_value_col, record, None),
|
|
495
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
496
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
497
|
+
)
|
|
498
|
+
for record in records
|
|
499
|
+
)
|
|
500
|
+
return pc.NumberRangeParameterConfig(
|
|
501
|
+
ds_param.name, ds_param.label, options, description=ds_param.description, user_attribute=ds_param.user_attribute,
|
|
502
|
+
parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
503
|
+
)
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
@dataclass
|
|
507
|
+
class TextDataSource(DataSource):
|
|
508
|
+
"""
|
|
509
|
+
Lookup table for text parameter default options
|
|
510
|
+
"""
|
|
511
|
+
_default_text_col: str
|
|
512
|
+
|
|
513
|
+
def __init__(
|
|
514
|
+
self, table_or_query: str, default_text_col: str, *, id_col: str | None = None, from_seeds: bool = False,
|
|
515
|
+
user_group_col: str | None = None, parent_id_col: str | None = None, connection: str | None = None,
|
|
516
|
+
**kwargs
|
|
517
|
+
) -> None:
|
|
518
|
+
"""
|
|
519
|
+
Constructor for TextDataSource
|
|
520
|
+
|
|
521
|
+
Arguments:
|
|
522
|
+
table_or_query: Either the name of the table to use, or a query to run
|
|
523
|
+
default_text_col: The column name of the default text
|
|
524
|
+
id_col: The column name of the id
|
|
525
|
+
from_seeds: Boolean for whether this datasource is created from seeds
|
|
526
|
+
user_group_col: The column name of the user group that the user is in for this option to be valid
|
|
527
|
+
parent_id_col: The column name of the parent option id that the default date belongs to
|
|
528
|
+
connection: Name of the connection to use defined in connections.py
|
|
529
|
+
"""
|
|
530
|
+
super().__init__(
|
|
531
|
+
table_or_query, id_col=id_col, from_seeds=from_seeds, user_group_col=user_group_col, parent_id_col=parent_id_col,
|
|
532
|
+
connection=connection
|
|
533
|
+
)
|
|
534
|
+
self._default_text_col = default_text_col
|
|
535
|
+
|
|
536
|
+
def _convert(self, ds_param: pc.DataSourceParameterConfig, df: pl.DataFrame) -> pc.TextParameterConfig:
|
|
537
|
+
"""
|
|
538
|
+
Method to convert the associated DataSourceParameter into a TextParameterConfig
|
|
539
|
+
|
|
540
|
+
Arguments:
|
|
541
|
+
ds_param: The parameter to convert
|
|
542
|
+
df: The dataframe containing the parameter options data
|
|
543
|
+
|
|
544
|
+
Returns:
|
|
545
|
+
The converted parameter
|
|
546
|
+
"""
|
|
547
|
+
self._validate_parameter_type(ds_param, pc.TextParameterConfig)
|
|
548
|
+
|
|
549
|
+
columns = [self._default_text_col]
|
|
550
|
+
df_agg = self._get_aggregated_df(df, columns)
|
|
551
|
+
|
|
552
|
+
records = df_agg.to_pandas().to_dict("records")
|
|
553
|
+
options = tuple(
|
|
554
|
+
po.TextParameterOption(
|
|
555
|
+
default_text=str(record[self._default_text_col]),
|
|
556
|
+
user_groups=self._get_key_from_record_as_list(self._user_group_col, record),
|
|
557
|
+
parent_option_ids=self._get_key_from_record_as_list(self._parent_id_col, record)
|
|
558
|
+
)
|
|
559
|
+
for record in records
|
|
560
|
+
)
|
|
561
|
+
return pc.TextParameterConfig(
|
|
562
|
+
ds_param.name, ds_param.label, options, description=ds_param.description, user_attribute=ds_param.user_attribute,
|
|
563
|
+
parent_name=ds_param.parent_name, **ds_param.extra_args
|
|
564
|
+
)
|
squirrels/_exceptions.py
CHANGED
|
@@ -20,7 +20,7 @@ class InvalidInputError(Exception):
|
|
|
20
20
|
21 - Authorized user is forbidden to delete users
|
|
21
21
|
22 - Cannot delete your own user
|
|
22
22
|
23 - Cannot delete the admin user
|
|
23
|
-
24 -
|
|
23
|
+
24 - Setting the admin user to non-admin is not permitted
|
|
24
24
|
25 - User does not have permission to access the dataset / dashboard
|
|
25
25
|
26 - User does not have permission to build the virtual data environment
|
|
26
26
|
27 - User does not have permission to query data models
|