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.

Files changed (34) hide show
  1. squirrels/__init__.py +2 -2
  2. squirrels/_api_server.py +66 -49
  3. squirrels/_authenticator.py +2 -3
  4. squirrels/_command_line.py +1 -1
  5. squirrels/_constants.py +7 -5
  6. squirrels/_environcfg.py +1 -1
  7. squirrels/_initializer.py +1 -2
  8. squirrels/_manifest.py +8 -12
  9. squirrels/_models.py +43 -21
  10. squirrels/_parameter_configs.py +4 -4
  11. squirrels/_parameter_sets.py +1 -3
  12. squirrels/_py_module.py +4 -2
  13. squirrels/_utils.py +7 -0
  14. squirrels/arguments/run_time_args.py +15 -4
  15. squirrels/package_data/assets/favicon.ico +0 -0
  16. squirrels/package_data/assets/index.js +13 -13
  17. squirrels/package_data/base_project/{ignores/.gitignore → .gitignore} +4 -0
  18. squirrels/package_data/base_project/{Dockerfile → docker/Dockerfile} +2 -2
  19. squirrels/package_data/base_project/docker/compose.yml +7 -0
  20. squirrels/package_data/base_project/environcfg.yml +1 -1
  21. squirrels/package_data/base_project/parameters.yml +18 -18
  22. squirrels/package_data/base_project/pyconfigs/auth.py +10 -14
  23. squirrels/package_data/base_project/pyconfigs/context.py +12 -2
  24. squirrels/package_data/base_project/squirrels.yml.j2 +18 -6
  25. squirrels/parameter_options.py +24 -24
  26. squirrels/parameters.py +3 -3
  27. squirrels/user_base.py +10 -11
  28. {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/METADATA +13 -11
  29. squirrels-0.2.2.dist-info/RECORD +55 -0
  30. {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/WHEEL +1 -1
  31. {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/entry_points.txt +1 -0
  32. squirrels-0.2.0rc1.dist-info/RECORD +0 -54
  33. /squirrels/package_data/base_project/{ignores → docker}/.dockerignore +0 -0
  34. {squirrels-0.2.0rc1.dist-info → squirrels-0.2.2.dist-info}/LICENSE +0 -0
@@ -1,4 +1,8 @@
1
1
  __pycache__
2
+
3
+ # common virtual environment names
4
+ .env/
5
+ .venv/
2
6
  venv/
3
7
 
4
8
  # squirrels files to ignore
@@ -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
- # "squirrels load-modules" if there are modules in "squirrels.yml"
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 load-modules
13
+ RUN squirrels deps
14
14
 
15
15
  CMD ["squirrels", "run", "--host", "0.0.0.0", "--port", "4465"]
@@ -0,0 +1,7 @@
1
+ services:
2
+ squirrels:
3
+ build: .
4
+ ports:
5
+ - "4465:4465"
6
+ volumes:
7
+ - ./environcfg.yml:/app/environcfg.yml
@@ -26,4 +26,4 @@ credentials:
26
26
 
27
27
  ## Predefined secrets used by the squirrels framework
28
28
  secrets:
29
- jwt_signature: ## generate a random 32 byte hex string here for jwt signatures. For instance, you can run "openssl rand -hex 32" in bash
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
- - name: group_by
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
- - name: start_date
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
- - name: end_date
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
- - name: date_range
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
- - name: category
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
- - name: subcategory
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
- - name: min_filter
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
- - name: max_filter
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
- - name: between_filter
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(username) - if username exists but password is incorrect
21
- - None - if the username doesn't exist (and username search will continue among any "fake users" configured in environcfg.yml)
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
- username, password = sqrl.username, sqrl.password
39
- if username in mock_users_db:
40
- user_dict = mock_users_db[username]
41
- hashed_pwd = user_dict["hashed_password"]
42
- if str(hash(password)) == hashed_pwd:
43
- is_admin = user_dict["is_admin"]
44
- user = User(username, is_internal=is_admin)
45
- return user.with_attributes(user_dict)
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.args to determine the conditions to execute certain blocks of code.
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"]: list[str] = group_by_param.get_selected("columns")
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 Product
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
- args: {} ## optional
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.expire.minutes: 30
62
+ # auth.token.expire_minutes: 30
52
63
  # parameters.cache.size: 1024
53
- # parameters.cache.ttl.minutes: 0
64
+ # parameters.cache.ttl_minutes: 0
54
65
  # results.cache.size: 128
55
- # results.cache.ttl.minutes: 0
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
@@ -14,12 +14,12 @@ class ParameterOption(metaclass=ABCMeta):
14
14
  """
15
15
  Abstract class for parameter options
16
16
  """
17
- _user_groups: Set[str] # = field(default_factory=frozenset, kw_only=True)
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[str], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
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: Optional[str], selected_parent_option_ids: Optional[Iterable[str]]) -> bool:
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 "user_group_attr" is not specified
38
- for the Parameter object. Note that when user is None but "user_group_attr" is specified, an error is thrown
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 "user_group_attr" is specified in the Parameter object
68
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter object
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[str], str] = frozenset(),
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[str], str] = frozenset(),
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 "user_group_attr" is specified in the Parameter object
159
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter object
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[str], str] = frozenset(),
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 "user_group_attr" is specified in the Parameter object
187
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter object
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[str], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
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[str], str] = frozenset(),
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
- '"{min_value}" and "{self.max_value}"')
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
- '"{min_value}" must be a multiple of increment "{self.increment}"')
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 "user_group_attr" is specified in the Parameter object
276
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter object
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[str], str] = frozenset(), parent_option_ids: Union[Iterable[str], str] = frozenset(), **kwargs
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 "user_group_attr" is specified in the Parameter object
309
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter object
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[str], str] = frozenset(),
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, 'Invalid selection for date.', e)
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, 'Invalid selection for number.', e)
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, *, is_internal: bool = False, **kwargs):
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
- def with_attributes(self, user_dict: dict[str, Any]):
37
- self.set_attributes(user_dict)
38
- return self
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, user_dict: dict[str, Any]):
42
- user = cls(username="TBA")
43
- for key, val in user_dict.items():
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.0rc1
3
+ Version: 0.2.2
4
4
  Summary: Squirrels - API Framework for Data Analytics
5
- Home-page: https://squirrels-nest.github.io/squirrels-docs/
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: fastapi (>=0.104.1,<0.105.0)
23
- Requires-Dist: gitpython (>=3.1.40,<4.0.0)
24
- Requires-Dist: inquirer (>=3.1.4,<4.0.0)
25
- Requires-Dist: jinja2 (>=3.1.2,<4.0.0)
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.6,<0.0.7)
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.23,<3.0.0)
31
- Requires-Dist: uvicorn (>=0.24.0.post1,<0.25.0)
32
- Project-URL: Documentation, https://squirrels-nest.github.io/squirrels-docs/
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/squirrels-docs" target="_blank">https://squirrels-nest.github.io/squirrels-docs</a>
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: poetry-core 1.8.1
2
+ Generator: poetry-core 1.9.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,3 +1,4 @@
1
1
  [console_scripts]
2
+ sqrl=squirrels._command_line:main
2
3
  squirrels=squirrels._command_line:main
3
4