squirrels 0.2.0rc1__py3-none-any.whl → 0.2.2__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 +2 -2
- squirrels/_api_server.py +66 -49
- squirrels/_authenticator.py +2 -3
- squirrels/_command_line.py +1 -1
- squirrels/_constants.py +7 -5
- squirrels/_environcfg.py +1 -1
- squirrels/_initializer.py +1 -2
- squirrels/_manifest.py +8 -12
- squirrels/_models.py +43 -21
- squirrels/_parameter_configs.py +4 -4
- squirrels/_parameter_sets.py +1 -3
- squirrels/_py_module.py +4 -2
- squirrels/_utils.py +7 -0
- squirrels/arguments/run_time_args.py +15 -4
- squirrels/package_data/assets/favicon.ico +0 -0
- squirrels/package_data/assets/index.js +13 -13
- squirrels/package_data/base_project/{ignores/.gitignore → .gitignore} +4 -0
- squirrels/package_data/base_project/{Dockerfile → docker/Dockerfile} +2 -2
- squirrels/package_data/base_project/docker/compose.yml +7 -0
- squirrels/package_data/base_project/environcfg.yml +1 -1
- squirrels/package_data/base_project/parameters.yml +18 -18
- squirrels/package_data/base_project/pyconfigs/auth.py +10 -14
- squirrels/package_data/base_project/pyconfigs/context.py +12 -2
- squirrels/package_data/base_project/squirrels.yml.j2 +18 -6
- squirrels/parameter_options.py +24 -24
- squirrels/parameters.py +3 -3
- squirrels/user_base.py +10 -11
- {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/METADATA +13 -11
- squirrels-0.2.2.dist-info/RECORD +55 -0
- {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/WHEEL +1 -1
- {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/entry_points.txt +1 -0
- squirrels-0.2.0rc1.dist-info/RECORD +0 -54
- /squirrels/package_data/base_project/{ignores → docker}/.dockerignore +0 -0
- {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/LICENSE +0 -0
|
@@ -3,13 +3,13 @@ FROM python:3.11-slim
|
|
|
3
3
|
WORKDIR /app
|
|
4
4
|
|
|
5
5
|
# Needed if any python dependencies are installed from git, or for
|
|
6
|
-
#
|
|
6
|
+
# "squirrels deps" if there are modules in "squirrels.yml"
|
|
7
7
|
RUN apt-get update && apt-get install -y git
|
|
8
8
|
|
|
9
9
|
COPY requirements-lock.txt .
|
|
10
10
|
RUN pip install --no-cache-dir -r requirements-lock.txt
|
|
11
11
|
|
|
12
12
|
COPY . .
|
|
13
|
-
RUN squirrels
|
|
13
|
+
RUN squirrels deps
|
|
14
14
|
|
|
15
15
|
CMD ["squirrels", "run", "--host", "0.0.0.0", "--port", "4465"]
|
|
@@ -26,4 +26,4 @@ credentials:
|
|
|
26
26
|
|
|
27
27
|
## Predefined secrets used by the squirrels framework
|
|
28
28
|
secrets:
|
|
29
|
-
|
|
29
|
+
jwt_secret: ## generate a random 32 byte hex string here for the jwt secret/private key. For instance, you can run "openssl rand -hex 32" in bash
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
parameters:
|
|
2
|
-
-
|
|
3
|
-
type: SingleSelectParameter
|
|
2
|
+
- type: SingleSelectParameter
|
|
4
3
|
factory: Create ## one of 'Create', 'CreateSimple', or 'CreateFromSource'
|
|
5
4
|
arguments: ## arguments to specify depend on values for 'type' and 'factory'
|
|
5
|
+
name: group_by
|
|
6
6
|
label: Group By
|
|
7
7
|
all_options:
|
|
8
8
|
- id: g0
|
|
@@ -23,33 +23,33 @@ parameters:
|
|
|
23
23
|
is_hidden: false ## optional, default, exists for all parameter types
|
|
24
24
|
user_attribute: null ## optional, default, exists for all parameter types
|
|
25
25
|
parent_name: null ## optional, default, exists for all parameter types
|
|
26
|
-
-
|
|
27
|
-
type: DateParameter
|
|
26
|
+
- type: DateParameter
|
|
28
27
|
factory: Create
|
|
29
28
|
arguments:
|
|
29
|
+
name: start_date
|
|
30
30
|
label: Start Date
|
|
31
31
|
all_options:
|
|
32
32
|
- default_date: 2023-01-01
|
|
33
33
|
date_format: '%Y-%m-%d' ## optional, default, format comes from python datetime, exists for Date and DateRange parameter options
|
|
34
|
-
-
|
|
35
|
-
type: DateParameter
|
|
34
|
+
- type: DateParameter
|
|
36
35
|
factory: Create
|
|
37
36
|
arguments:
|
|
37
|
+
name: end_date
|
|
38
38
|
label: End Date
|
|
39
39
|
all_options:
|
|
40
40
|
- default_date: 2023-12-31
|
|
41
|
-
-
|
|
42
|
-
type: DateRangeParameter
|
|
41
|
+
- type: DateRangeParameter
|
|
43
42
|
factory: Create
|
|
44
43
|
arguments:
|
|
44
|
+
name: date_range
|
|
45
45
|
label: Date Range
|
|
46
46
|
all_options:
|
|
47
47
|
- default_start_date: 2023-01-01
|
|
48
48
|
default_end_date: 2023-12-31
|
|
49
|
-
-
|
|
50
|
-
type: MultiSelectParameter
|
|
49
|
+
- type: MultiSelectParameter
|
|
51
50
|
factory: CreateFromSource
|
|
52
51
|
arguments:
|
|
52
|
+
name: category
|
|
53
53
|
label: Category Filter
|
|
54
54
|
data_source:
|
|
55
55
|
table_or_query: categories
|
|
@@ -62,10 +62,10 @@ parameters:
|
|
|
62
62
|
order_matters: false ## optional, default, exists for MultiSelect only
|
|
63
63
|
user_group_col: null ## optional, default, exists for all parameters
|
|
64
64
|
connection_name: default ## optional, default, exists for all parameters
|
|
65
|
-
-
|
|
66
|
-
type: MultiSelectParameter
|
|
65
|
+
- type: MultiSelectParameter
|
|
67
66
|
factory: CreateFromSource
|
|
68
67
|
arguments:
|
|
68
|
+
name: subcategory
|
|
69
69
|
label: Subcategory Filter
|
|
70
70
|
data_source:
|
|
71
71
|
table_or_query: subcategories
|
|
@@ -73,20 +73,20 @@ parameters:
|
|
|
73
73
|
options_col: subcategory
|
|
74
74
|
parent_id_col: category_id ## optional, default is null, exists for all parameter types
|
|
75
75
|
parent_name: category
|
|
76
|
-
-
|
|
77
|
-
type: NumberParameter
|
|
76
|
+
- type: NumberParameter
|
|
78
77
|
factory: Create
|
|
79
78
|
arguments:
|
|
79
|
+
name: min_filter
|
|
80
80
|
label: Amounts Greater Than
|
|
81
81
|
all_options:
|
|
82
82
|
- min_value: 0
|
|
83
83
|
max_value: 500
|
|
84
84
|
increment: 1 ## optional, default, exists for Number and NumRange options
|
|
85
85
|
default_value: null ## optional, default, exists for Number options only
|
|
86
|
-
-
|
|
87
|
-
type: NumberParameter
|
|
86
|
+
- type: NumberParameter
|
|
88
87
|
factory: CreateFromSource
|
|
89
88
|
arguments:
|
|
89
|
+
name: max_filter
|
|
90
90
|
label: Amounts Less Than
|
|
91
91
|
data_source:
|
|
92
92
|
table_or_query: "SELECT 0 as min_value, max(-amount) as max_value, 10 as increment FROM transactions WHERE category <> 'Income'"
|
|
@@ -95,10 +95,10 @@ parameters:
|
|
|
95
95
|
increment_col: increment ## optional, default is null
|
|
96
96
|
default_value_col: max_value ## optional, default is null
|
|
97
97
|
id_col: null ## optional, default, required for SingleSelect and MultiSelect, optional for all others
|
|
98
|
-
-
|
|
99
|
-
type: NumberRangeParameter
|
|
98
|
+
- type: NumberRangeParameter
|
|
100
99
|
factory: Create
|
|
101
100
|
arguments:
|
|
101
|
+
name: between_filter
|
|
102
102
|
label: Amounts Between
|
|
103
103
|
all_options:
|
|
104
104
|
- min_value: 0
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
1
|
from typing import Union, Any
|
|
3
2
|
from squirrels import User as UserBase, AuthArgs, WrongPassword
|
|
4
3
|
|
|
@@ -17,8 +16,8 @@ def get_user_if_valid(sqrl: AuthArgs) -> Union[User, WrongPassword, None]:
|
|
|
17
16
|
|
|
18
17
|
Return:
|
|
19
18
|
- User instance - if username and password are correct
|
|
20
|
-
- WrongPassword(
|
|
21
|
-
- None - if the username doesn't exist (and username
|
|
19
|
+
- WrongPassword() - if username exists but password is incorrect
|
|
20
|
+
- None - if the username doesn't exist (and search for username will continue for "fake users" configured in environcfg.yml)
|
|
22
21
|
"""
|
|
23
22
|
mock_users_db = {
|
|
24
23
|
"johndoe": {
|
|
@@ -35,14 +34,11 @@ def get_user_if_valid(sqrl: AuthArgs) -> Union[User, WrongPassword, None]:
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
if
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
else:
|
|
47
|
-
return WrongPassword(username)
|
|
48
|
-
return None
|
|
37
|
+
user_dict = mock_users_db.get(sqrl.username)
|
|
38
|
+
if user_dict is None:
|
|
39
|
+
return None
|
|
40
|
+
|
|
41
|
+
if str(hash(sqrl.password)) == user_dict["hashed_password"]:
|
|
42
|
+
return User.Create(sqrl.username, user_dict, is_internal=user_dict["is_admin"])
|
|
43
|
+
else:
|
|
44
|
+
return WrongPassword()
|
|
@@ -8,12 +8,12 @@ def main(ctx: dict[str, Any], sqrl: sr.ContextArgs) -> None:
|
|
|
8
8
|
These context variables can then be used in the models.
|
|
9
9
|
|
|
10
10
|
Note that the code here is used by all datasets, regardless of the parameters they use. You can use
|
|
11
|
-
sqrl.prms and sqrl.
|
|
11
|
+
sqrl.prms and/or sqrl.traits to determine the conditions to execute certain blocks of code.
|
|
12
12
|
"""
|
|
13
13
|
|
|
14
14
|
if "group_by" in sqrl.prms:
|
|
15
15
|
group_by_param: sr.SingleSelectParameter = sqrl.prms["group_by"]
|
|
16
|
-
ctx["group_by_cols_list"]
|
|
16
|
+
ctx["group_by_cols_list"] = group_by_param.get_selected("columns")
|
|
17
17
|
ctx["group_by_cols"] = ",".join(ctx["group_by_cols_list"])
|
|
18
18
|
ctx["order_by_cols"] = ",".join((x+" DESC") for x in ctx["group_by_cols_list"])
|
|
19
19
|
|
|
@@ -24,6 +24,11 @@ def main(ctx: dict[str, Any], sqrl: sr.ContextArgs) -> None:
|
|
|
24
24
|
if "end_date" in sqrl.prms:
|
|
25
25
|
end_date_param: sr.DateParameter = sqrl.prms["end_date"]
|
|
26
26
|
ctx["end_date"] = end_date_param.get_selected_date_quoted()
|
|
27
|
+
|
|
28
|
+
if "date_range" in sqrl.prms:
|
|
29
|
+
date_range_param: sr.DateRangeParameter = sqrl.prms["date_range"]
|
|
30
|
+
ctx["start_date"] = date_range_param.get_selected_start_date_quoted()
|
|
31
|
+
ctx["end_date"] = date_range_param.get_selected_end_date_quoted()
|
|
27
32
|
|
|
28
33
|
if "category" in sqrl.prms:
|
|
29
34
|
category_param: sr.MultiSelectParameter = sqrl.prms["category"]
|
|
@@ -42,4 +47,9 @@ def main(ctx: dict[str, Any], sqrl: sr.ContextArgs) -> None:
|
|
|
42
47
|
if "max_filter" in sqrl.prms:
|
|
43
48
|
max_amount_filter: sr.NumberParameter = sqrl.prms["max_filter"]
|
|
44
49
|
ctx["max_amount"] = max_amount_filter.get_selected_value()
|
|
50
|
+
|
|
51
|
+
if "between_filter" in sqrl.prms:
|
|
52
|
+
between_filter: sr.NumberRangeParameter = sqrl.prms["between_filter"]
|
|
53
|
+
ctx["min_amount"] = between_filter.get_selected_lower_value()
|
|
54
|
+
ctx["max_amount"] = between_filter.get_selected_upper_value()
|
|
45
55
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
project_variables:
|
|
2
2
|
name: sample
|
|
3
|
-
label: Sample
|
|
3
|
+
label: Sample Project
|
|
4
4
|
major_version: 1
|
|
5
|
-
minor_version: 0
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
packages: []
|
|
@@ -22,6 +21,7 @@ packages: []
|
|
|
22
21
|
selection_test_sets:
|
|
23
22
|
- name: sample_test_set
|
|
24
23
|
user_attributes: ## optional unless there are user attributes used by parameters or models
|
|
24
|
+
is_internal: True
|
|
25
25
|
organization: org1
|
|
26
26
|
parameters: ## optional - for unspecified parameters, default value is used
|
|
27
27
|
group_by: g3
|
|
@@ -42,17 +42,29 @@ datasets:
|
|
|
42
42
|
- subcategory
|
|
43
43
|
- min_filter
|
|
44
44
|
- max_filter
|
|
45
|
-
|
|
45
|
+
traits: {} ## optional
|
|
46
|
+
|
|
47
|
+
- name: private_dataset_example
|
|
48
|
+
label: Dataset Example 2
|
|
49
|
+
model: dataset_example
|
|
50
|
+
scope: private
|
|
51
|
+
parameters:
|
|
52
|
+
- group_by
|
|
53
|
+
- date_range
|
|
54
|
+
- category
|
|
55
|
+
- subcategory
|
|
56
|
+
- between_filter
|
|
46
57
|
|
|
47
58
|
|
|
48
59
|
settings: {}
|
|
49
60
|
|
|
50
61
|
## Default values for settings:
|
|
51
|
-
# auth.token.
|
|
62
|
+
# auth.token.expire_minutes: 30
|
|
52
63
|
# parameters.cache.size: 1024
|
|
53
|
-
# parameters.cache.
|
|
64
|
+
# parameters.cache.ttl_minutes: 0
|
|
54
65
|
# results.cache.size: 128
|
|
55
|
-
# results.cache.
|
|
66
|
+
# results.cache.ttl_minutes: 0
|
|
56
67
|
# selection_test_sets.default_name_used: default
|
|
57
68
|
# connections.default_name_used: default
|
|
58
69
|
# defaults.federates.materialized: table
|
|
70
|
+
# in_memory_database: sqlite
|
squirrels/parameter_options.py
CHANGED
|
@@ -14,12 +14,12 @@ class ParameterOption(metaclass=ABCMeta):
|
|
|
14
14
|
"""
|
|
15
15
|
Abstract class for parameter options
|
|
16
16
|
"""
|
|
17
|
-
_user_groups: Set[
|
|
17
|
+
_user_groups: Set[Any] # = field(default_factory=frozenset, kw_only=True)
|
|
18
18
|
_parent_option_ids: Set[str] # = field(default_factory=frozenset, kw_only=True)
|
|
19
19
|
|
|
20
20
|
@abstractmethod
|
|
21
21
|
def __init__(
|
|
22
|
-
self, *, user_groups: Union[Iterable[
|
|
22
|
+
self, *, user_groups: Union[Iterable[Any], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
23
23
|
) -> None:
|
|
24
24
|
self._user_groups = frozenset({user_groups} if isinstance(user_groups, str) else user_groups)
|
|
25
25
|
self._parent_option_ids = frozenset({parent_option_ids} if isinstance(parent_option_ids, str) else parent_option_ids)
|
|
@@ -29,13 +29,13 @@ class ParameterOption(metaclass=ABCMeta):
|
|
|
29
29
|
if lower_value > upper_value:
|
|
30
30
|
raise ConfigurationError(f'The {lower_label} "{lower_value}" must be less than or equal to the {upper_label} "{upper_value}"')
|
|
31
31
|
|
|
32
|
-
def _is_valid(self, user_group:
|
|
32
|
+
def _is_valid(self, user_group: Any, selected_parent_option_ids: Optional[Iterable[str]]) -> bool:
|
|
33
33
|
"""
|
|
34
34
|
Checks if this option is valid given the selected parent options and user group of user if applicable.
|
|
35
35
|
|
|
36
36
|
Parameters:
|
|
37
|
-
user_group: The value of the user's "user group attribute". Only None when "
|
|
38
|
-
for the Parameter
|
|
37
|
+
user_group: The value of the user's "user group attribute". Only None when "user_attribute" is not specified
|
|
38
|
+
for the Parameter factory. Note that when user is None but "user_attribute" is specified, an error is thrown
|
|
39
39
|
selected_parent_option_ids: List of selected option ids from the parent parameter. Only None when the Parameter
|
|
40
40
|
object has no parent parameter.
|
|
41
41
|
|
|
@@ -64,8 +64,8 @@ class SelectParameterOption(ParameterOption):
|
|
|
64
64
|
identifier: Unique identifier for this option that never changes over time
|
|
65
65
|
label: Human readable label that gets shown as a dropdown option
|
|
66
66
|
is_default: True if this is a default option, False otherwise
|
|
67
|
-
user_groups: The user groups this parameter option would show for if "
|
|
68
|
-
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter
|
|
67
|
+
user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
|
|
68
|
+
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
|
|
69
69
|
custom_fields: Dictionary to associate custom attributes to the parameter option
|
|
70
70
|
"""
|
|
71
71
|
_identifier: str
|
|
@@ -74,7 +74,7 @@ class SelectParameterOption(ParameterOption):
|
|
|
74
74
|
custom_fields: dict[str, Any] # = field(default_factory=False, kw_only=True)
|
|
75
75
|
|
|
76
76
|
def __init__(
|
|
77
|
-
self, id: str, label: str, *, is_default: bool = False, user_groups: Union[Iterable[
|
|
77
|
+
self, id: str, label: str, *, is_default: bool = False, user_groups: Union[Iterable[Any], str] = frozenset(),
|
|
78
78
|
parent_option_ids: Union[Iterable[str], str] = frozenset(), custom_fields: dict[str, Any] = {}, **kwargs
|
|
79
79
|
) -> None:
|
|
80
80
|
"""
|
|
@@ -131,7 +131,7 @@ class _DateTypeParameterOption(ParameterOption):
|
|
|
131
131
|
|
|
132
132
|
@abstractmethod
|
|
133
133
|
def __init__(
|
|
134
|
-
self, *, date_format: str = '%Y-%m-%d', user_groups: Union[Iterable[
|
|
134
|
+
self, *, date_format: str = '%Y-%m-%d', user_groups: Union[Iterable[Any], str] = frozenset(),
|
|
135
135
|
parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
136
136
|
) -> None:
|
|
137
137
|
super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
|
|
@@ -155,13 +155,13 @@ class DateParameterOption(_DateTypeParameterOption):
|
|
|
155
155
|
Attributes:
|
|
156
156
|
default_date: Default date for this option
|
|
157
157
|
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
158
|
-
user_groups: The user groups this parameter option would show for if "
|
|
159
|
-
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter
|
|
158
|
+
user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
|
|
159
|
+
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
|
|
160
160
|
"""
|
|
161
161
|
_default_date: date
|
|
162
162
|
|
|
163
163
|
def __init__(
|
|
164
|
-
self, default_date: Union[str, date], *, date_format: str = '%Y-%m-%d', user_groups: Union[Iterable[
|
|
164
|
+
self, default_date: Union[str, date], *, date_format: str = '%Y-%m-%d', user_groups: Union[Iterable[Any], str] = frozenset(),
|
|
165
165
|
parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
166
166
|
) -> None:
|
|
167
167
|
"""
|
|
@@ -183,15 +183,15 @@ class DateRangeParameterOption(_DateTypeParameterOption):
|
|
|
183
183
|
default_start_date: Default start date for this option
|
|
184
184
|
default_end_date: Default end date for this option
|
|
185
185
|
date_format: Format of the default date, default is '%Y-%m-%d'
|
|
186
|
-
user_groups: The user groups this parameter option would show for if "
|
|
187
|
-
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter
|
|
186
|
+
user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
|
|
187
|
+
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
|
|
188
188
|
"""
|
|
189
189
|
_default_start_date: date
|
|
190
190
|
_default_end_date: date
|
|
191
191
|
|
|
192
192
|
def __init__(
|
|
193
193
|
self, default_start_date: Union[str, date], default_end_date: Union[str, date], *, date_format: str = '%Y-%m-%d',
|
|
194
|
-
user_groups: Union[Iterable[
|
|
194
|
+
user_groups: Union[Iterable[Any], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
195
195
|
) -> None:
|
|
196
196
|
"""
|
|
197
197
|
Constructor for DateRangeParameterOption
|
|
@@ -216,7 +216,7 @@ class _NumericParameterOption(ParameterOption):
|
|
|
216
216
|
|
|
217
217
|
@abstractmethod
|
|
218
218
|
def __init__(
|
|
219
|
-
self, min_value: Number, max_value: Number, *, increment: Number = 1, user_groups: Union[Iterable[
|
|
219
|
+
self, min_value: Number, max_value: Number, *, increment: Number = 1, user_groups: Union[Iterable[Any], str] = frozenset(),
|
|
220
220
|
parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
221
221
|
) -> None:
|
|
222
222
|
super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
|
|
@@ -248,10 +248,10 @@ class _NumericParameterOption(ParameterOption):
|
|
|
248
248
|
|
|
249
249
|
if not self.__value_in_range(value):
|
|
250
250
|
raise ConfigurationError(f'The selected value "{value}" is outside of bounds ' +
|
|
251
|
-
'"{
|
|
251
|
+
f'"{self._min_value}" and "{self._max_value}".')
|
|
252
252
|
if not self.__value_on_increment(value):
|
|
253
253
|
raise ConfigurationError(f'The difference between selected value "{value}" and lower value ' +
|
|
254
|
-
'"{
|
|
254
|
+
f'"{self._min_value}" must be a multiple of increment "{self._increment}".')
|
|
255
255
|
return value
|
|
256
256
|
|
|
257
257
|
def _to_json_dict(self):
|
|
@@ -272,14 +272,14 @@ class NumberParameterOption(_NumericParameterOption):
|
|
|
272
272
|
max_value: Maximum selectable value
|
|
273
273
|
increment: Increment of selectable values, and must fit evenly between min_value and max_value
|
|
274
274
|
default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
|
|
275
|
-
user_groups: The user groups this parameter option would show for if "
|
|
276
|
-
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter
|
|
275
|
+
user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
|
|
276
|
+
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
|
|
277
277
|
"""
|
|
278
278
|
_default_value: Decimal # = field(default=None, kw_only=True)
|
|
279
279
|
|
|
280
280
|
def __init__(
|
|
281
281
|
self, min_value: Number, max_value: Number, *, increment: Number = 1, default_value: Optional[Number] = None,
|
|
282
|
-
user_groups: Union[Iterable[
|
|
282
|
+
user_groups: Union[Iterable[Any], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
283
283
|
) -> None:
|
|
284
284
|
"""
|
|
285
285
|
Constructor for NumberParameterOption
|
|
@@ -305,15 +305,15 @@ class NumberRangeParameterOption(_NumericParameterOption):
|
|
|
305
305
|
default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
|
|
306
306
|
default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
|
|
307
307
|
Must also be greater than default_lower_value
|
|
308
|
-
user_groups: The user groups this parameter option would show for if "
|
|
309
|
-
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter
|
|
308
|
+
user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
|
|
309
|
+
parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
|
|
310
310
|
"""
|
|
311
311
|
_default_lower_value: Decimal # = field(default=None, kw_only=True)
|
|
312
312
|
_default_upper_value: Decimal # = field(default=None, kw_only=True)
|
|
313
313
|
|
|
314
314
|
def __init__(
|
|
315
315
|
self, min_value: Number, max_value: Number, *, increment: Number = 1, default_lower_value: Optional[Number] = None,
|
|
316
|
-
default_upper_value: Optional[Number] = None, user_groups: Union[Iterable[
|
|
316
|
+
default_upper_value: Optional[Number] = None, user_groups: Union[Iterable[Any], str] = frozenset(),
|
|
317
317
|
parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
|
|
318
318
|
) -> None:
|
|
319
319
|
"""
|
squirrels/parameters.py
CHANGED
|
@@ -74,13 +74,13 @@ class Parameter(metaclass=ABCMeta):
|
|
|
74
74
|
try:
|
|
75
75
|
return datetime.strptime(input_date.strip(), "%Y-%m-%d").date() if isinstance(input_date, str) else input_date
|
|
76
76
|
except ValueError as e:
|
|
77
|
-
self._config._raise_invalid_input_error(input_date,
|
|
77
|
+
self._config._raise_invalid_input_error(input_date, str(e), e)
|
|
78
78
|
|
|
79
79
|
def _validate_number(self, input_number: po.Number, curr_option: po._NumericParameterOption) -> Decimal:
|
|
80
80
|
try:
|
|
81
81
|
return curr_option._validate_value(input_number)
|
|
82
82
|
except u.ConfigurationError as e:
|
|
83
|
-
self._config._raise_invalid_input_error(input_number,
|
|
83
|
+
self._config._raise_invalid_input_error(input_number, str(e), e)
|
|
84
84
|
|
|
85
85
|
@abstractmethod
|
|
86
86
|
def to_json_dict0(self) -> dict:
|
|
@@ -104,7 +104,7 @@ class _SelectionParameter(Parameter):
|
|
|
104
104
|
|
|
105
105
|
def _validate_selected_id_in_options(self, selected_id):
|
|
106
106
|
if selected_id not in (x._identifier for x in self._options):
|
|
107
|
-
self._config._raise_invalid_input_error(selected_id)
|
|
107
|
+
self._config._raise_invalid_input_error(selected_id, f"The selected id {selected_id} does not exist in available options.")
|
|
108
108
|
|
|
109
109
|
@abstractmethod
|
|
110
110
|
def to_json_dict0(self):
|
squirrels/user_base.py
CHANGED
|
@@ -14,7 +14,7 @@ class User:
|
|
|
14
14
|
username: str
|
|
15
15
|
is_internal: bool
|
|
16
16
|
|
|
17
|
-
def __init__(self, username: str,
|
|
17
|
+
def __init__(self, username: str, is_internal: bool):
|
|
18
18
|
"""
|
|
19
19
|
Constructor for the User base class
|
|
20
20
|
|
|
@@ -33,14 +33,17 @@ class User:
|
|
|
33
33
|
"""
|
|
34
34
|
pass
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
@classmethod
|
|
37
|
+
def Create(cls, username: str, user_dict: dict[str, Any], *, is_internal: bool = False, **kwargs):
|
|
38
|
+
user = cls(username, is_internal)
|
|
39
|
+
user.set_attributes(user_dict)
|
|
40
|
+
return user
|
|
39
41
|
|
|
40
42
|
@classmethod
|
|
41
|
-
def _FromDict(cls,
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
def _FromDict(cls, user_obj_as_dict: dict[str, Any]):
|
|
44
|
+
username, is_internal = user_obj_as_dict["username"], user_obj_as_dict["is_internal"]
|
|
45
|
+
user = cls(username=username, is_internal=is_internal)
|
|
46
|
+
for key, val in user_obj_as_dict.items():
|
|
44
47
|
setattr(user, key, val)
|
|
45
48
|
return user
|
|
46
49
|
|
|
@@ -51,8 +54,4 @@ class WrongPassword:
|
|
|
51
54
|
Return this object if the username was found but the password was incorrect
|
|
52
55
|
|
|
53
56
|
This ensures that if the username exists as a real user, we won't continue to use the environcfg.yml file to authenticate
|
|
54
|
-
|
|
55
|
-
Attributes:
|
|
56
|
-
username: The identifier for the user
|
|
57
57
|
"""
|
|
58
|
-
username: str
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: squirrels
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Squirrels - API Framework for Data Analytics
|
|
5
|
-
Home-page: https://squirrels-nest.github.io
|
|
5
|
+
Home-page: https://squirrels-nest.github.io
|
|
6
6
|
License: MIT
|
|
7
7
|
Author: Tim Huang
|
|
8
8
|
Author-email: tim.yuting@hotmail.com
|
|
@@ -17,19 +17,21 @@ Classifier: Programming Language :: Python :: 3.12
|
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
18
18
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
19
|
Classifier: Typing :: Typed
|
|
20
|
+
Provides-Extra: duckdb
|
|
20
21
|
Requires-Dist: cachetools (>=5.3.2,<6.0.0)
|
|
21
22
|
Requires-Dist: cryptography (>=41.0.7,<42.0.0)
|
|
22
|
-
Requires-Dist:
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: duckdb (>=0.10.0) ; extra == "duckdb"
|
|
24
|
+
Requires-Dist: fastapi (>=0.109.2,<0.110.0)
|
|
25
|
+
Requires-Dist: gitpython (>=3.1.41,<4.0.0)
|
|
26
|
+
Requires-Dist: inquirer (>=3.2.1,<4.0.0)
|
|
27
|
+
Requires-Dist: jinja2 (>=3.1.3,<4.0.0)
|
|
26
28
|
Requires-Dist: pandas (>=2.1.4,<3.0.0)
|
|
27
29
|
Requires-Dist: python-jose (>=3.3.0,<4.0.0)
|
|
28
|
-
Requires-Dist: python-multipart (>=0.0.
|
|
30
|
+
Requires-Dist: python-multipart (>=0.0.9,<0.0.10)
|
|
29
31
|
Requires-Dist: pyyaml (>=6.0.1,<7.0.0)
|
|
30
|
-
Requires-Dist: sqlalchemy (>=2.0.
|
|
31
|
-
Requires-Dist: uvicorn (>=0.
|
|
32
|
-
Project-URL: Documentation, https://squirrels-nest.github.io
|
|
32
|
+
Requires-Dist: sqlalchemy (>=2.0.25,<3.0.0)
|
|
33
|
+
Requires-Dist: uvicorn (>=0.27.1,<0.28.0)
|
|
34
|
+
Project-URL: Documentation, https://squirrels-nest.github.io
|
|
33
35
|
Project-URL: Repository, https://github.com/squirrels-nest/squirrels
|
|
34
36
|
Description-Content-Type: text/markdown
|
|
35
37
|
|
|
@@ -37,7 +39,7 @@ Description-Content-Type: text/markdown
|
|
|
37
39
|
|
|
38
40
|
Squirrels is an API framework that lets you create REST APIs for dynamic data analytics!
|
|
39
41
|
|
|
40
|
-
**Documentation**: <a href="https://squirrels-nest.github.io/
|
|
42
|
+
**Documentation**: <a href="https://squirrels-nest.github.io/" target="_blank">https://squirrels-nest.github.io/</a>
|
|
41
43
|
|
|
42
44
|
**Source Code**: <a href="https://github.com/squirrels-nest/squirrels" target="_blank">https://github.com/squirrels-nest/squirrels</a>
|
|
43
45
|
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
squirrels/__init__.py,sha256=ulylm42MjjfHB2GPNuFZMjPr1ro5HOPzo1oDNmINUqg,664
|
|
2
|
+
squirrels/_api_server.py,sha256=a6wUXN7ZBg2EYiHGE5jneEjllZHEUWDCrlk5pVLhDc0,15499
|
|
3
|
+
squirrels/_authenticator.py,sha256=XLFECIZANIs1ecE1y-JU_PYMI-FCHiygI1FL4GKcMgg,3742
|
|
4
|
+
squirrels/_command_line.py,sha256=EahzH5dsveWjJ88DzPzrNaKNCp-mbE19-9_Q4MHiNHM,5668
|
|
5
|
+
squirrels/_connection_set.py,sha256=5X-1i9eVL5F1xbOSN5frEosbONIUKVqLmMOIUfBhy-Y,2563
|
|
6
|
+
squirrels/_constants.py,sha256=oDJsDA3A-Fgvb8tQCvNRMSzeTcr2WcpP08Cj7eNlzXw,3865
|
|
7
|
+
squirrels/_environcfg.py,sha256=0zCRxcJ_r1JA_0J-F79341_ezZsbGGdpfdNxTgsoMK4,2761
|
|
8
|
+
squirrels/_initializer.py,sha256=1xAY8Yyz8KM9wPzgOQWiD_RN_m7h_rtNbC9l3NJQ2wg,7750
|
|
9
|
+
squirrels/_manifest.py,sha256=xF070LtRm3fI5ctljYx_OA-JYUs-TA-U33WwLJQI9tk,8599
|
|
10
|
+
squirrels/_models.py,sha256=L0oYdaFrd9ttlXX5Z2EyBmxKxc1H70TGYe53Ew9ME_s,21828
|
|
11
|
+
squirrels/_package_loader.py,sha256=-EZ8qsmp6QEdZyHUKYi5e4OPOx3EnL2rxr1IYe1NwEI,1020
|
|
12
|
+
squirrels/_parameter_configs.py,sha256=gU-dLpdp0WIVrxB4EYh3URrdDxn0wp8uW-D3h9uP9us,17120
|
|
13
|
+
squirrels/_parameter_sets.py,sha256=9Eu6FakgmrdZ2a_RMnCRnXe-o-8R6DlHaAI5XaOeQpA,8917
|
|
14
|
+
squirrels/_py_module.py,sha256=ViEH-DNDSvX9BnA7Bo18sz5TeqspG14z4aMU2uAgjw8,2624
|
|
15
|
+
squirrels/_timer.py,sha256=pFgz6dJKypmap07dfzZvwBS686DuBXwJWj0e6PnkWFU,802
|
|
16
|
+
squirrels/_utils.py,sha256=S_3wYL4zviGpiWu_b7QbIAhwkAnUDDScWia1VgSS7a0,5438
|
|
17
|
+
squirrels/_version.py,sha256=ySOetuKYm0mnm1J9-D3IcEZkf4kFrP8SVDKX97awBxo,109
|
|
18
|
+
squirrels/arguments/init_time_args.py,sha256=w7bqlq9-gF85skxzxaVs8U6bk58TA39y7DlfXwUMbW0,783
|
|
19
|
+
squirrels/arguments/run_time_args.py,sha256=T2yJ5Zdfa6e2gexcxyzCj8_6CIRVCVIhsBqvrjBSYco,3195
|
|
20
|
+
squirrels/data_sources.py,sha256=IzAHjQPJsrhRXTjPG36p_E5cX3UafDaAOUU79irX_oA,25864
|
|
21
|
+
squirrels/dateutils.py,sha256=o-jQ0p3wGKomzFVn59qDdaadLtzKPeyXyKSfm0GMQPs,16487
|
|
22
|
+
squirrels/package_data/assets/favicon.ico,sha256=FZx26dn50cp0rgYdyBptJJob2TTVNiY0NZ-MeeL_uY0,61022
|
|
23
|
+
squirrels/package_data/assets/index.css,sha256=btE9XnSZP2ydCSKG7y0_Sm_9Mdp4RVpI41ht1SsZrUc,11572
|
|
24
|
+
squirrels/package_data/assets/index.js,sha256=sIrGfIZDuHoPvLLTgo8VmuxivxmjEY8nXf0ELDi_7jw,260298
|
|
25
|
+
squirrels/package_data/base_project/.gitignore,sha256=OD3TgclEDFD7tI-SR3yoloYu3EOwdZksUNHEjm9TTJg,134
|
|
26
|
+
squirrels/package_data/base_project/connections.yml,sha256=9ZbmX2onQNlX7WrzhLt2Iw7jH7CQDHliRLUBYYFXgtY,255
|
|
27
|
+
squirrels/package_data/base_project/database/expenses.db,sha256=igxfJMxGhX1mTTgdIQMthoILyFoP8K682Mit-CRC-ss,36864
|
|
28
|
+
squirrels/package_data/base_project/database/weather.db,sha256=PldWB7PLY_ltY-OWxN9ALcFEdiVDaP3Kef0I2k7WPso,188416
|
|
29
|
+
squirrels/package_data/base_project/docker/.dockerignore,sha256=sY6T-_UtTVw1jFBOfiMQ8XFS9191YqEotxYPCEsdNJ4,90
|
|
30
|
+
squirrels/package_data/base_project/docker/Dockerfile,sha256=7t8BMaMoDExj_3VOh86RjOXerEolxlbqUgZGJTfnPJs,467
|
|
31
|
+
squirrels/package_data/base_project/docker/compose.yml,sha256=UbChIXPuBm9p_lCiYEE_0t-gCZ_k1WhF7scDv6iEMZ8,125
|
|
32
|
+
squirrels/package_data/base_project/environcfg.yml,sha256=vrmocpeaHdHhwXRuXyUlFSCILpaz8N2viaZ_6xXSa8I,859
|
|
33
|
+
squirrels/package_data/base_project/models/dbviews/database_view1.py,sha256=GdqVEQJZoIM6iTN-QsH5ZyUOoC005AqVZUl-5W97QO0,1655
|
|
34
|
+
squirrels/package_data/base_project/models/dbviews/database_view1.sql,sha256=RDeL1JWZrUDACRxOVDrKMSpvLvjthT0IA570s2c54do,488
|
|
35
|
+
squirrels/package_data/base_project/models/federates/dataset_example.py,sha256=7OGgPS-m1nkRhF3JfF8T1XEEM-gJL2RGfthZe-Ct0pk,686
|
|
36
|
+
squirrels/package_data/base_project/models/federates/dataset_example.sql,sha256=cH9rVjXEJIFcxqZpW8dCvHLf_c-YwDuiGlcjoTIy6CM,78
|
|
37
|
+
squirrels/package_data/base_project/parameters.yml,sha256=vs3SOI-XM3g7xT38r7Fdf34a3q-Nhs_DL90yctdmAwc,4463
|
|
38
|
+
squirrels/package_data/base_project/pyconfigs/auth.py,sha256=jSDuUps7mzVV__IWkju1KVw43c8hldhAA1KY1ppWZIo,1567
|
|
39
|
+
squirrels/package_data/base_project/pyconfigs/connections.py,sha256=hOCpr71h-Gxs573rPwGerYCTVrDgmJwhj9w9hrCdCc8,809
|
|
40
|
+
squirrels/package_data/base_project/pyconfigs/context.py,sha256=327DV8A4sQ_p70c4JbxnTa04WBZefUUuAdvSvosa4pE,2599
|
|
41
|
+
squirrels/package_data/base_project/pyconfigs/parameters.py,sha256=ljS9uB-X6l-5vGKkb3tJTudDDo4unDsXsOv2h90OM2U,3077
|
|
42
|
+
squirrels/package_data/base_project/seeds/mocks/category.csv,sha256=iZB9Ncv-hRJlDK2VRdW3P_fgY0fMBB0S4IAL7YYQ7-s,35
|
|
43
|
+
squirrels/package_data/base_project/seeds/mocks/max_filter.csv,sha256=H34nwpvZVEhfTOgIJZez_UJ8N3nslxkh3CCSYUgs6w0,38
|
|
44
|
+
squirrels/package_data/base_project/seeds/mocks/subcategory.csv,sha256=Vsc7tEghLhGN4zz7uUzR2un50SMTDhbxDa4Fll58-vw,105
|
|
45
|
+
squirrels/package_data/base_project/squirrels.yml.j2,sha256=PbNpNmkJQ_gGeDITOK-yP5mVRxxNk87P2S2Ltq7PMf0,1727
|
|
46
|
+
squirrels/package_data/base_project/tmp/.gitignore,sha256=XImoqcWvJY0C0L_TWCx1ljvqU7qh9fUTJmK4ACCmNFI,13
|
|
47
|
+
squirrels/package_data/templates/index.html,sha256=zMiM1w77Rs6xcYXiGwgh_WksOXlMBmEjpcAbAfhAyDA,572
|
|
48
|
+
squirrels/parameter_options.py,sha256=YKbS_XtXyXi5FUK4U40SK0O9PNUn7AB-VCxhsudJD34,15638
|
|
49
|
+
squirrels/parameters.py,sha256=9TDEvs5LjSKcc8-BoFqt_FiUSUYE_CWwEz_kt8PxsHg,32401
|
|
50
|
+
squirrels/user_base.py,sha256=dVDc9pi95DFGFS93xuloyWvETN7BEkQ3TZ0UtB7UFh0,1698
|
|
51
|
+
squirrels-0.2.2.dist-info/LICENSE,sha256=rW94rBQiFGQtHU_v2IQJbvg715cQF-bXup4pEJVFHXA,1067
|
|
52
|
+
squirrels-0.2.2.dist-info/METADATA,sha256=XcfTWxGkq3aYSAqNcJxrkN1nD37ZRAu3Uxo-pH7lwxU,5180
|
|
53
|
+
squirrels-0.2.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
54
|
+
squirrels-0.2.2.dist-info/entry_points.txt,sha256=mYQRuGxbg8X82hjNRJuWiON4S6kE5CPvmXmxNPtYTbg,92
|
|
55
|
+
squirrels-0.2.2.dist-info/RECORD,,
|