squirrels 0.5.0rc0__py3-none-any.whl → 0.5.1__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 (108) hide show
  1. dateutils/__init__.py +6 -0
  2. dateutils/_enums.py +25 -0
  3. squirrels/dateutils.py → dateutils/_implementation.py +58 -111
  4. dateutils/types.py +6 -0
  5. squirrels/__init__.py +10 -12
  6. squirrels/_api_routes/__init__.py +5 -0
  7. squirrels/_api_routes/auth.py +271 -0
  8. squirrels/_api_routes/base.py +171 -0
  9. squirrels/_api_routes/dashboards.py +158 -0
  10. squirrels/_api_routes/data_management.py +148 -0
  11. squirrels/_api_routes/datasets.py +265 -0
  12. squirrels/_api_routes/oauth2.py +298 -0
  13. squirrels/_api_routes/project.py +252 -0
  14. squirrels/_api_server.py +245 -781
  15. squirrels/_arguments/__init__.py +0 -0
  16. squirrels/{arguments → _arguments}/init_time_args.py +7 -2
  17. squirrels/{arguments → _arguments}/run_time_args.py +13 -35
  18. squirrels/_auth.py +720 -212
  19. squirrels/_command_line.py +81 -41
  20. squirrels/_compile_prompts.py +147 -0
  21. squirrels/_connection_set.py +16 -7
  22. squirrels/_constants.py +29 -9
  23. squirrels/{_dashboards_io.py → _dashboards.py} +87 -6
  24. squirrels/_data_sources.py +570 -0
  25. squirrels/{dataset_result.py → _dataset_types.py} +2 -4
  26. squirrels/_exceptions.py +9 -37
  27. squirrels/_initializer.py +83 -59
  28. squirrels/_logging.py +117 -0
  29. squirrels/_manifest.py +129 -62
  30. squirrels/_model_builder.py +10 -52
  31. squirrels/_model_configs.py +3 -3
  32. squirrels/_model_queries.py +1 -1
  33. squirrels/_models.py +249 -118
  34. squirrels/{package_data → _package_data}/base_project/.env +16 -4
  35. squirrels/{package_data → _package_data}/base_project/.env.example +15 -3
  36. squirrels/{package_data → _package_data}/base_project/connections.yml +4 -3
  37. squirrels/{package_data → _package_data}/base_project/dashboards/dashboard_example.py +4 -4
  38. squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
  39. squirrels/{package_data → _package_data}/base_project/duckdb_init.sql +1 -0
  40. squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
  41. squirrels/{package_data → _package_data}/base_project/models/builds/build_example.py +2 -2
  42. squirrels/{package_data → _package_data}/base_project/models/builds/build_example.sql +1 -1
  43. squirrels/{package_data → _package_data}/base_project/models/builds/build_example.yml +2 -0
  44. squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +17 -0
  45. squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +32 -0
  46. squirrels/_package_data/base_project/models/federates/federate_example.py +48 -0
  47. squirrels/_package_data/base_project/models/federates/federate_example.sql +21 -0
  48. squirrels/{package_data → _package_data}/base_project/models/federates/federate_example.yml +7 -7
  49. squirrels/{package_data → _package_data}/base_project/models/sources.yml +5 -6
  50. squirrels/{package_data → _package_data}/base_project/parameters.yml +32 -45
  51. squirrels/_package_data/base_project/pyconfigs/connections.py +18 -0
  52. squirrels/{package_data → _package_data}/base_project/pyconfigs/context.py +31 -22
  53. squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
  54. squirrels/_package_data/base_project/pyconfigs/user.py +44 -0
  55. squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.yml +1 -1
  56. squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.yml +1 -1
  57. squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
  58. squirrels/_package_data/templates/dataset_results.html +112 -0
  59. squirrels/_package_data/templates/oauth_login.html +271 -0
  60. squirrels/_package_data/templates/squirrels_studio.html +20 -0
  61. squirrels/_parameter_configs.py +76 -55
  62. squirrels/_parameter_options.py +348 -0
  63. squirrels/_parameter_sets.py +53 -45
  64. squirrels/_parameters.py +1664 -0
  65. squirrels/_project.py +403 -242
  66. squirrels/_py_module.py +3 -2
  67. squirrels/_request_context.py +33 -0
  68. squirrels/_schemas/__init__.py +0 -0
  69. squirrels/_schemas/auth_models.py +167 -0
  70. squirrels/_schemas/query_param_models.py +75 -0
  71. squirrels/{_api_response_models.py → _schemas/response_models.py} +48 -18
  72. squirrels/_seeds.py +1 -1
  73. squirrels/_sources.py +23 -19
  74. squirrels/_utils.py +121 -39
  75. squirrels/_version.py +1 -1
  76. squirrels/arguments.py +7 -0
  77. squirrels/auth.py +4 -0
  78. squirrels/connections.py +3 -0
  79. squirrels/dashboards.py +2 -81
  80. squirrels/data_sources.py +14 -563
  81. squirrels/parameter_options.py +13 -348
  82. squirrels/parameters.py +14 -1266
  83. squirrels/types.py +16 -0
  84. {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/METADATA +42 -30
  85. squirrels-0.5.1.dist-info/RECORD +98 -0
  86. squirrels/package_data/base_project/dashboards/dashboard_example.yml +0 -22
  87. squirrels/package_data/base_project/macros/macros_example.sql +0 -15
  88. squirrels/package_data/base_project/models/dbviews/dbview_example.sql +0 -12
  89. squirrels/package_data/base_project/models/dbviews/dbview_example.yml +0 -26
  90. squirrels/package_data/base_project/models/federates/federate_example.py +0 -44
  91. squirrels/package_data/base_project/models/federates/federate_example.sql +0 -17
  92. squirrels/package_data/base_project/pyconfigs/connections.py +0 -14
  93. squirrels/package_data/base_project/pyconfigs/parameters.py +0 -93
  94. squirrels/package_data/base_project/pyconfigs/user.py +0 -23
  95. squirrels/package_data/base_project/squirrels.yml.j2 +0 -71
  96. squirrels-0.5.0rc0.dist-info/RECORD +0 -70
  97. /squirrels/{package_data → _package_data}/base_project/assets/expenses.db +0 -0
  98. /squirrels/{package_data → _package_data}/base_project/assets/weather.db +0 -0
  99. /squirrels/{package_data → _package_data}/base_project/docker/.dockerignore +0 -0
  100. /squirrels/{package_data → _package_data}/base_project/docker/Dockerfile +0 -0
  101. /squirrels/{package_data → _package_data}/base_project/docker/compose.yml +0 -0
  102. /squirrels/{package_data/base_project/.gitignore → _package_data/base_project/gitignore} +0 -0
  103. /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.csv +0 -0
  104. /squirrels/{package_data → _package_data}/base_project/seeds/seed_subcategories.csv +0 -0
  105. /squirrels/{package_data → _package_data}/base_project/tmp/.gitignore +0 -0
  106. {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/WHEEL +0 -0
  107. {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/entry_points.txt +0 -0
  108. {squirrels-0.5.0rc0.dist-info → squirrels-0.5.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,348 +1,13 @@
1
- from typing import TypeVar, Iterable, Any
2
- from dataclasses import dataclass
3
- from decimal import Decimal, InvalidOperation as InvalidDecimalConversion
4
- from datetime import datetime, date
5
- from abc import ABCMeta, abstractmethod
6
-
7
- from ._utils import ConfigurationError
8
-
9
- Number = Decimal | int | float | str
10
- Comparables = TypeVar("Comparables", Decimal, date)
11
-
12
-
13
- @dataclass
14
- class ParameterOption(metaclass=ABCMeta):
15
- """
16
- Abstract class for parameter options
17
- """
18
- _user_groups: frozenset[Any]
19
- _parent_option_ids: frozenset[str]
20
-
21
- @abstractmethod
22
- def __init__(
23
- self, *, user_groups: Iterable[Any] | str = frozenset(), parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
24
- ) -> None:
25
- self._user_groups = frozenset({user_groups} if isinstance(user_groups, str) else user_groups)
26
- self._parent_option_ids = frozenset({parent_option_ids} if isinstance(parent_option_ids, str) else parent_option_ids)
27
-
28
- def _validate_lower_upper_values(self, lower_label: str, lower_value: Comparables, upper_label: str, upper_value: Comparables):
29
- if lower_value > upper_value:
30
- raise ConfigurationError(f'The {lower_label} "{lower_value}" must be less than or equal to the {upper_label} "{upper_value}"')
31
-
32
- def _is_valid(self, user_group: Any, selected_parent_option_ids: Iterable[str] | None) -> bool:
33
- """
34
- Checks if this option is valid given the selected parent options and user group of user if applicable.
35
-
36
- Arguments:
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
- selected_parent_option_ids: List of selected option ids from the parent parameter. Only None when the Parameter
40
- object has no parent parameter.
41
-
42
- Returns:
43
- True if valid, False otherwise
44
- """
45
- if user_group is not None and user_group not in self._user_groups:
46
- return False
47
-
48
- if selected_parent_option_ids is not None and self._parent_option_ids.isdisjoint(selected_parent_option_ids):
49
- return False
50
-
51
- return True
52
-
53
-
54
- @dataclass
55
- class SelectParameterOption(ParameterOption):
56
- """
57
- Parameter option for a select parameter
58
- """
59
- _identifier: str
60
- _label: str
61
- _is_default: bool
62
- custom_fields: dict[str, Any]
63
-
64
- def __init__(
65
- self, id: str, label: str, *, is_default: bool = False, user_groups: Iterable[Any] | str = frozenset(),
66
- parent_option_ids: Iterable[str] | str = frozenset(), custom_fields: dict[str, Any] = {}, **kwargs
67
- ) -> None:
68
- """
69
- Constructor for SelectParameterOption
70
-
71
- Arguments:
72
- identifier: Unique identifier for this option that never changes over time
73
- label: Human readable label that gets shown as a dropdown option
74
- is_default: True if this is a default option, False otherwise
75
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
76
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
77
- custom_fields: Dictionary to associate custom attributes to the parameter option
78
- **kwargs: Any additional keyword arguments specified (except the ones above) gets included into custom_fields as well
79
- """
80
- super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
81
- self._identifier = id
82
- self._label = label
83
- self._is_default = is_default
84
- self.custom_fields = {
85
- **kwargs, **custom_fields, **self._to_json_dict()
86
- }
87
-
88
- def get_custom_field(self, field: str, *, default_field: str | None = None, default: Any = None, **kwargs) -> Any:
89
- """
90
- Get field value from the custom_fields attribute
91
-
92
- Arguments:
93
- field: The key to use to fetch the custom field from "custom_fields"
94
- default_field: If value at "field" key does not exist in "custom_fields", then this is used instead as the field (if not None)
95
- default: If value at "field" or "default_field" (if not None) key does not exist in "custom_fields", then this value
96
- is used as default, or throws an error if None
97
-
98
- Returns:
99
- The type of the custom field
100
- """
101
- if default_field is not None:
102
- default = self.get_custom_field(default_field, default=default)
103
-
104
- if default is not None:
105
- selected_field = self.custom_fields.get(field, default)
106
- else:
107
- try:
108
- selected_field = self.custom_fields[field]
109
- except KeyError as e:
110
- raise ConfigurationError(f"Field '{field}' must exist for parameter option {self._to_json_dict()}") from e
111
-
112
- return selected_field
113
-
114
- def _to_json_dict(self):
115
- return {'id': self._identifier, 'label': self._label}
116
-
117
-
118
- @dataclass
119
- class _DateTypeParameterOption(ParameterOption):
120
- """
121
- Abstract class (or type) for date type parameter options
122
- """
123
- _min_date: date | None
124
- _max_date: date | None
125
- _date_format: str
126
-
127
- @abstractmethod
128
- def __init__(
129
- self, *, min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d',
130
- user_groups: Iterable[Any] | str = frozenset(), parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
131
- ) -> None:
132
- super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
133
- self._date_format = date_format
134
- self._min_date, self._max_date = None, None # preset for using _validate_date()
135
- self._min_date = self._validate_date(min_date) if min_date is not None else None
136
- self._max_date = self._validate_date(max_date) if max_date is not None else None
137
- if self._min_date is not None and self._max_date is not None:
138
- self._validate_lower_upper_values("min_date", self._min_date, "max_date", self._max_date)
139
-
140
- def _validate_date(self, date_str: str | date) -> date:
141
- try:
142
- date_obj = datetime.strptime(date_str, self._date_format).date() if isinstance(date_str, str) else date_str
143
- except ValueError as e:
144
- raise ConfigurationError(f'Invalid format for date "{date_str}".') from e
145
-
146
- if self._min_date is not None and date_obj < self._min_date:
147
- raise ConfigurationError(f'The provided date "{date_obj}" is less than the min date "{self._min_date}"')
148
- if self._max_date is not None and date_obj > self._max_date:
149
- raise ConfigurationError(f'The provided date "{date_obj}" is greater than the max date "{self._max_date}"')
150
-
151
- return date_obj
152
-
153
-
154
- @dataclass
155
- class DateParameterOption(_DateTypeParameterOption):
156
- """
157
- Parameter option for default dates if it varies based on selection of another parameter
158
- """
159
- _default_date: date
160
-
161
- def __init__(
162
- self, default_date: str | date, *, min_date: str | date | None = None, max_date: str | date | None = None, date_format: str = '%Y-%m-%d',
163
- user_groups: Iterable[Any] | str = frozenset(), parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
164
- ) -> None:
165
- """
166
- Constructor for DateParameterOption
167
-
168
- Arguments:
169
- default_date: Default date for this option
170
- min_date: Minimum date for this option
171
- max_date: Maximum date for this option
172
- date_format: Format of the default date, default is '%Y-%m-%d'
173
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
174
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
175
- """
176
- super().__init__(
177
- date_format=date_format, min_date=min_date, max_date=max_date, user_groups=user_groups, parent_option_ids=parent_option_ids
178
- )
179
- self._default_date = self._validate_date(default_date)
180
-
181
-
182
- @dataclass
183
- class DateRangeParameterOption(_DateTypeParameterOption):
184
- """
185
- Parameter option for default dates if it varies based on selection of another parameter
186
- """
187
- _default_start_date: date
188
- _default_end_date: date
189
-
190
- def __init__(
191
- self, default_start_date: str | date, default_end_date: str | date, *, min_date: str | date | None = None,
192
- max_date: str | date | None = None, date_format: str = '%Y-%m-%d', user_groups: Iterable[Any] | str = frozenset(),
193
- parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
194
- ) -> None:
195
- """
196
- Constructor for DateRangeParameterOption
197
-
198
- Arguments:
199
- default_start_date: Default start date for this option
200
- default_end_date: Default end date for this option
201
- min_date: Minimum date for this option
202
- max_date: Maximum date for this option
203
- date_format: Format of the default date, default is '%Y-%m-%d'
204
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
205
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
206
- """
207
- super().__init__(
208
- date_format=date_format, min_date=min_date, max_date=max_date, user_groups=user_groups, parent_option_ids=parent_option_ids
209
- )
210
- self._default_start_date = self._validate_date(default_start_date)
211
- self._default_end_date = self._validate_date(default_end_date)
212
- self._validate_lower_upper_values("default_start_date", self._default_start_date, "default_end_date", self._default_end_date)
213
-
214
-
215
- @dataclass
216
- class _NumericParameterOption(ParameterOption):
217
- """
218
- Abstract class (or type) for numeric parameter options
219
- """
220
- _min_value: Decimal
221
- _max_value: Decimal
222
- _increment: Decimal
223
-
224
- @abstractmethod
225
- def __init__(
226
- self, min_value: Number, max_value: Number, *, increment: Number = 1, user_groups: Iterable[Any] | str = frozenset(),
227
- parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
228
- ) -> None:
229
- super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
230
- try:
231
- self._min_value = Decimal(str(min_value))
232
- self._max_value = Decimal(str(max_value))
233
- self._increment = Decimal(str(increment))
234
- except InvalidDecimalConversion as e:
235
- raise ConfigurationError(f'Could not convert either min, max, or increment to number') from e
236
-
237
- self._validate_lower_upper_values("min_value", self._min_value, "max_value", self._max_value)
238
-
239
- if (self._max_value - self._min_value) % self._increment != 0:
240
- raise ConfigurationError(f'The increment "{self._increment}" must fit evenly between ' +
241
- f'the min_value "{self._min_value}" and max_value "{self._max_value}"')
242
-
243
- def __value_in_range(self, value: Decimal) -> bool:
244
- return self._min_value <= value <= self._max_value
245
-
246
- def __value_on_increment(self, value: Decimal) -> bool:
247
- diff = (value - self._min_value)
248
- return diff >= 0 and diff % self._increment == 0
249
-
250
- def _validate_value(self, value: Number) -> Decimal:
251
- try:
252
- value = Decimal(str(value))
253
- except InvalidDecimalConversion as e:
254
- raise ConfigurationError(f'Could not convert "{value}" to number', e)
255
-
256
- if not self.__value_in_range(value):
257
- raise ConfigurationError(f'The selected value "{value}" is outside of bounds ' +
258
- f'"{self._min_value}" and "{self._max_value}".')
259
- if not self.__value_on_increment(value):
260
- raise ConfigurationError(f'The difference between selected value "{value}" and lower value ' +
261
- f'"{self._min_value}" must be a multiple of increment "{self._increment}".')
262
- return value
263
-
264
-
265
- @dataclass
266
- class NumberParameterOption(_NumericParameterOption):
267
- """
268
- Parameter option for default numbers if it varies based on selection of another parameter
269
- """
270
- _default_value: Decimal
271
-
272
- def __init__(
273
- self, min_value: Number, max_value: Number, *, increment: Number = 1, default_value: Number | None = None,
274
- user_groups: Iterable[Any] | str = frozenset(), parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
275
- ) -> None:
276
- """
277
- Constructor for NumberParameterOption
278
-
279
- * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
280
-
281
- Arguments:
282
- min_value: Minimum selectable value
283
- max_value: Maximum selectable value
284
- increment: Increment of selectable values, and must fit evenly between min_value and max_value
285
- default_value: Default value for this option, and must be selectable based on min_value, max_value, and increment
286
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
287
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
288
- """
289
- super().__init__(min_value, max_value, increment=increment, user_groups=user_groups, parent_option_ids=parent_option_ids)
290
- self._default_value = self._validate_value(default_value) if default_value is not None else self._min_value
291
-
292
-
293
- @dataclass
294
- class NumberRangeParameterOption(_NumericParameterOption):
295
- """
296
- Parameter option for default numeric ranges if it varies based on selection of another parameter
297
- """
298
- _default_lower_value: Decimal
299
- _default_upper_value: Decimal
300
-
301
- def __init__(
302
- self, min_value: Number, max_value: Number, *, increment: Number = 1, default_lower_value: Number | None = None,
303
- default_upper_value: Number | None = None, user_groups: Iterable[Any] | str = frozenset(),
304
- parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
305
- ) -> None:
306
- """
307
- Constructor for NumberRangeParameterOption
308
-
309
- * Note that the "Number" type denotes an int, a Decimal (from decimal module), or a string that can be parsed to Decimal
310
-
311
- Arguments:
312
- min_value: Minimum selectable value
313
- max_value: Maximum selectable value
314
- increment: Increment of selectable values, and must fit evenly between min_value and max_value
315
- default_lower_value: Default lower value for this option, and must be selectable based on min_value, max_value, and increment
316
- default_upper_value: Default upper value for this option, and must be selectable based on min_value, max_value, and increment.
317
- Must also be greater than default_lower_value
318
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
319
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
320
- """
321
- super().__init__(min_value, max_value, increment=increment, user_groups=user_groups, parent_option_ids=parent_option_ids)
322
- self._default_lower_value = self._validate_value(default_lower_value) if default_lower_value is not None else self._min_value
323
- self._default_upper_value = self._validate_value(default_upper_value) if default_upper_value is not None else self._max_value
324
- self._validate_lower_upper_values("default_lower_value", self._default_lower_value, "default_upper_value", self._default_upper_value)
325
-
326
-
327
- @dataclass
328
- class TextParameterOption(ParameterOption):
329
- """
330
- Parameter option for default text values if it varies based on selection of another parameter
331
- """
332
- _default_text: str
333
-
334
- def __init__(
335
- self, *, default_text: str = "", user_groups: Iterable[Any] | str = frozenset(),
336
- parent_option_ids: Iterable[str] | str = frozenset(), **kwargs
337
- ) -> None:
338
- """
339
- Constructor for TextParameterOption
340
-
341
- Arguments:
342
- default_text: Default text for this option
343
- user_groups: The user groups this parameter option would show for if "user_attribute" is specified in the Parameter factory
344
- parent_option_ids: Set of parent option ids this parameter option would show for if "parent" is specified in the Parameter factory
345
- """
346
- super().__init__(user_groups=user_groups, parent_option_ids=parent_option_ids)
347
- self._default_text = default_text
348
-
1
+ from ._parameter_options import (
2
+ SelectParameterOption,
3
+ DateParameterOption,
4
+ DateRangeParameterOption,
5
+ NumberParameterOption,
6
+ NumberRangeParameterOption,
7
+ TextParameterOption
8
+ )
9
+
10
+ __all__ = [
11
+ "SelectParameterOption", "DateParameterOption", "DateRangeParameterOption",
12
+ "NumberParameterOption", "NumberRangeParameterOption", "TextParameterOption"
13
+ ]