squirrels 0.4.1__py3-none-any.whl → 0.5.0__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 (125) 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 +13 -11
  6. squirrels/_api_routes/__init__.py +5 -0
  7. squirrels/_api_routes/auth.py +271 -0
  8. squirrels/_api_routes/base.py +165 -0
  9. squirrels/_api_routes/dashboards.py +150 -0
  10. squirrels/_api_routes/data_management.py +145 -0
  11. squirrels/_api_routes/datasets.py +257 -0
  12. squirrels/_api_routes/oauth2.py +298 -0
  13. squirrels/_api_routes/project.py +252 -0
  14. squirrels/_api_server.py +256 -450
  15. squirrels/_arguments/__init__.py +0 -0
  16. squirrels/_arguments/init_time_args.py +108 -0
  17. squirrels/_arguments/run_time_args.py +147 -0
  18. squirrels/_auth.py +960 -0
  19. squirrels/_command_line.py +126 -45
  20. squirrels/_compile_prompts.py +147 -0
  21. squirrels/_connection_set.py +48 -26
  22. squirrels/_constants.py +68 -38
  23. squirrels/_dashboards.py +160 -0
  24. squirrels/_data_sources.py +570 -0
  25. squirrels/_dataset_types.py +84 -0
  26. squirrels/_exceptions.py +29 -0
  27. squirrels/_initializer.py +177 -80
  28. squirrels/_logging.py +115 -0
  29. squirrels/_manifest.py +208 -79
  30. squirrels/_model_builder.py +69 -0
  31. squirrels/_model_configs.py +74 -0
  32. squirrels/_model_queries.py +52 -0
  33. squirrels/_models.py +926 -367
  34. squirrels/_package_data/base_project/.env +42 -0
  35. squirrels/_package_data/base_project/.env.example +42 -0
  36. squirrels/_package_data/base_project/assets/expenses.db +0 -0
  37. squirrels/_package_data/base_project/connections.yml +16 -0
  38. squirrels/_package_data/base_project/dashboards/dashboard_example.py +34 -0
  39. squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
  40. squirrels/{package_data → _package_data}/base_project/docker/.dockerignore +5 -2
  41. squirrels/{package_data → _package_data}/base_project/docker/Dockerfile +3 -3
  42. squirrels/{package_data → _package_data}/base_project/docker/compose.yml +1 -1
  43. squirrels/_package_data/base_project/duckdb_init.sql +10 -0
  44. squirrels/{package_data/base_project/.gitignore → _package_data/base_project/gitignore} +3 -2
  45. squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
  46. squirrels/_package_data/base_project/models/builds/build_example.py +26 -0
  47. squirrels/_package_data/base_project/models/builds/build_example.sql +16 -0
  48. squirrels/_package_data/base_project/models/builds/build_example.yml +57 -0
  49. squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +12 -0
  50. squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +26 -0
  51. squirrels/_package_data/base_project/models/federates/federate_example.py +37 -0
  52. squirrels/_package_data/base_project/models/federates/federate_example.sql +19 -0
  53. squirrels/_package_data/base_project/models/federates/federate_example.yml +65 -0
  54. squirrels/_package_data/base_project/models/sources.yml +38 -0
  55. squirrels/{package_data → _package_data}/base_project/parameters.yml +56 -40
  56. squirrels/_package_data/base_project/pyconfigs/connections.py +14 -0
  57. squirrels/{package_data → _package_data}/base_project/pyconfigs/context.py +21 -40
  58. squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
  59. squirrels/_package_data/base_project/pyconfigs/user.py +44 -0
  60. squirrels/_package_data/base_project/seeds/seed_categories.yml +15 -0
  61. squirrels/_package_data/base_project/seeds/seed_subcategories.csv +15 -0
  62. squirrels/_package_data/base_project/seeds/seed_subcategories.yml +21 -0
  63. squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
  64. squirrels/_package_data/templates/dataset_results.html +112 -0
  65. squirrels/_package_data/templates/oauth_login.html +271 -0
  66. squirrels/_package_data/templates/squirrels_studio.html +20 -0
  67. squirrels/_package_loader.py +8 -4
  68. squirrels/_parameter_configs.py +104 -103
  69. squirrels/_parameter_options.py +348 -0
  70. squirrels/_parameter_sets.py +57 -47
  71. squirrels/_parameters.py +1664 -0
  72. squirrels/_project.py +721 -0
  73. squirrels/_py_module.py +7 -5
  74. squirrels/_schemas/__init__.py +0 -0
  75. squirrels/_schemas/auth_models.py +167 -0
  76. squirrels/_schemas/query_param_models.py +75 -0
  77. squirrels/{_api_response_models.py → _schemas/response_models.py} +126 -47
  78. squirrels/_seeds.py +35 -16
  79. squirrels/_sources.py +110 -0
  80. squirrels/_utils.py +248 -73
  81. squirrels/_version.py +1 -1
  82. squirrels/arguments.py +7 -0
  83. squirrels/auth.py +4 -0
  84. squirrels/connections.py +3 -0
  85. squirrels/dashboards.py +2 -81
  86. squirrels/data_sources.py +14 -631
  87. squirrels/parameter_options.py +13 -348
  88. squirrels/parameters.py +14 -1266
  89. squirrels/types.py +16 -0
  90. squirrels-0.5.0.dist-info/METADATA +113 -0
  91. squirrels-0.5.0.dist-info/RECORD +97 -0
  92. {squirrels-0.4.1.dist-info → squirrels-0.5.0.dist-info}/WHEEL +1 -1
  93. squirrels-0.5.0.dist-info/entry_points.txt +3 -0
  94. {squirrels-0.4.1.dist-info → squirrels-0.5.0.dist-info/licenses}/LICENSE +1 -1
  95. squirrels/_authenticator.py +0 -85
  96. squirrels/_dashboards_io.py +0 -61
  97. squirrels/_environcfg.py +0 -84
  98. squirrels/arguments/init_time_args.py +0 -40
  99. squirrels/arguments/run_time_args.py +0 -208
  100. squirrels/package_data/assets/favicon.ico +0 -0
  101. squirrels/package_data/assets/index.css +0 -1
  102. squirrels/package_data/assets/index.js +0 -58
  103. squirrels/package_data/base_project/assets/expenses.db +0 -0
  104. squirrels/package_data/base_project/connections.yml +0 -7
  105. squirrels/package_data/base_project/dashboards/dashboard_example.py +0 -32
  106. squirrels/package_data/base_project/dashboards.yml +0 -10
  107. squirrels/package_data/base_project/env.yml +0 -29
  108. squirrels/package_data/base_project/models/dbviews/dbview_example.py +0 -47
  109. squirrels/package_data/base_project/models/dbviews/dbview_example.sql +0 -22
  110. squirrels/package_data/base_project/models/federates/federate_example.py +0 -21
  111. squirrels/package_data/base_project/models/federates/federate_example.sql +0 -3
  112. squirrels/package_data/base_project/pyconfigs/auth.py +0 -45
  113. squirrels/package_data/base_project/pyconfigs/connections.py +0 -19
  114. squirrels/package_data/base_project/pyconfigs/parameters.py +0 -95
  115. squirrels/package_data/base_project/seeds/seed_subcategories.csv +0 -15
  116. squirrels/package_data/base_project/squirrels.yml.j2 +0 -94
  117. squirrels/package_data/templates/index.html +0 -18
  118. squirrels/project.py +0 -378
  119. squirrels/user_base.py +0 -55
  120. squirrels-0.4.1.dist-info/METADATA +0 -117
  121. squirrels-0.4.1.dist-info/RECORD +0 -60
  122. squirrels-0.4.1.dist-info/entry_points.txt +0 -4
  123. /squirrels/{package_data → _package_data}/base_project/assets/weather.db +0 -0
  124. /squirrels/{package_data → _package_data}/base_project/seeds/seed_categories.csv +0 -0
  125. /squirrels/{package_data → _package_data}/base_project/tmp/.gitignore +0 -0
File without changes
@@ -0,0 +1,108 @@
1
+ from typing import Any, Iterable, Callable
2
+ from dataclasses import dataclass
3
+ import polars as pl
4
+
5
+ from .. import _utils as u
6
+
7
+ @dataclass
8
+ class ConnectionsArgs:
9
+ project_path: str
10
+ _proj_vars: dict[str, Any]
11
+ _env_vars: dict[str, str]
12
+
13
+ @property
14
+ def proj_vars(self) -> dict[str, Any]:
15
+ return self._proj_vars.copy()
16
+
17
+ @property
18
+ def env_vars(self) -> dict[str, str]:
19
+ return self._env_vars.copy()
20
+
21
+
22
+ @dataclass
23
+ class AuthProviderArgs(ConnectionsArgs):
24
+ pass
25
+
26
+
27
+ @dataclass
28
+ class ParametersArgs(ConnectionsArgs):
29
+ pass
30
+
31
+
32
+ @dataclass
33
+ class _WithConnectionDictArgs(ConnectionsArgs):
34
+ _connections: dict[str, Any]
35
+
36
+ @property
37
+ def connections(self) -> dict[str, Any]:
38
+ """
39
+ A dictionary of connection keys to SQLAlchemy Engines for database connections.
40
+
41
+ Can also be used to store other in-memory objects in advance such as ML models.
42
+ """
43
+ return self._connections.copy()
44
+
45
+
46
+ class BuildModelArgs(_WithConnectionDictArgs):
47
+
48
+ def __init__(
49
+ self, conn_args: ConnectionsArgs, _connections: dict[str, Any],
50
+ dependencies: Iterable[str],
51
+ ref: Callable[[str], pl.LazyFrame],
52
+ run_external_sql: Callable[[str, str], pl.DataFrame]
53
+ ):
54
+ super().__init__(conn_args.project_path, conn_args.proj_vars, conn_args.env_vars, _connections)
55
+ self._dependencies = dependencies
56
+ self._ref = ref
57
+ self._run_external_sql = run_external_sql
58
+
59
+ @property
60
+ def dependencies(self) -> set[str]:
61
+ """
62
+ The set of dependent data model names
63
+ """
64
+ return set(self._dependencies)
65
+
66
+ def ref(self, model: str) -> pl.LazyFrame:
67
+ """
68
+ Returns the result (as polars DataFrame) of a dependent model (predefined in "dependencies" function)
69
+
70
+ Note: This is different behaviour than the "ref" function for SQL models, which figures out the dependent models for you,
71
+ and returns a string for the table/view name instead of a polars DataFrame.
72
+
73
+ Arguments:
74
+ model: The model name
75
+
76
+ Returns:
77
+ A polars DataFrame
78
+ """
79
+ return self._ref(model)
80
+
81
+ def run_external_sql(self, connection_name: str, sql_query: str, **kwargs) -> pl.DataFrame:
82
+ """
83
+ Runs a SQL query against an external database, with option to specify the connection name. Placeholder values are provided automatically
84
+
85
+ Arguments:
86
+ sql_query: The SQL query. Can be parameterized with placeholders
87
+ connection_name: The connection name for the database. If None, uses the one configured for the model
88
+
89
+ Returns:
90
+ The query result as a polars DataFrame
91
+ """
92
+ return self._run_external_sql(sql_query, connection_name)
93
+
94
+ def run_sql_on_dataframes(self, sql_query: str, *, dataframes: dict[str, pl.LazyFrame] | None = None, **kwargs) -> pl.DataFrame:
95
+ """
96
+ Uses a dictionary of dataframes to execute a SQL query in an embedded in-memory DuckDB database
97
+
98
+ Arguments:
99
+ sql_query: The SQL query to run
100
+ dataframes: A dictionary of table names to their polars LazyFrame. If None, uses results of dependent models
101
+
102
+ Returns:
103
+ The result as a polars DataFrame from running the query
104
+ """
105
+ if dataframes is None:
106
+ dataframes = {x: self.ref(x) for x in self._dependencies}
107
+
108
+ return u.run_sql_on_dataframes(sql_query, dataframes)
@@ -0,0 +1,147 @@
1
+ from typing import Callable, Any, Coroutine
2
+ import polars as pl
3
+
4
+ from .init_time_args import ParametersArgs, BuildModelArgs
5
+ from .._schemas.auth_models import AbstractUser
6
+ from .._parameters import Parameter, TextValue
7
+
8
+
9
+ class ContextArgs(ParametersArgs):
10
+
11
+ def __init__(
12
+ self, param_args: ParametersArgs,
13
+ user: AbstractUser,
14
+ prms: dict[str, Parameter],
15
+ configurables: dict[str, str]
16
+ ):
17
+ super().__init__(param_args.project_path, param_args.proj_vars, param_args.env_vars)
18
+ self.user = user
19
+ self._prms = prms
20
+ self._configurables = configurables
21
+ self._placeholders = {}
22
+
23
+ @property
24
+ def prms(self) -> dict[str, Parameter]:
25
+ """
26
+ A dictionary of parameter names to parameter
27
+ """
28
+ return self._prms.copy()
29
+
30
+ @property
31
+ def configurables(self) -> dict[str, str]:
32
+ """
33
+ A dictionary of configurable name to value (set by application)
34
+ """
35
+ return self._configurables.copy()
36
+
37
+ @property
38
+ def _placeholders_copy(self) -> dict[str, Any]:
39
+ """
40
+ A dictionary of placeholder name to placeholder value
41
+ """
42
+ return self._placeholders.copy()
43
+
44
+ def set_placeholder(self, placeholder: str, value: TextValue | Any) -> str:
45
+ """
46
+ Method to set a placeholder value.
47
+
48
+ Arguments:
49
+ placeholder: A string for the name of the placeholder
50
+ value: The value of the placeholder. Can be of any type
51
+ """
52
+ if isinstance(value, TextValue):
53
+ value = value._value_do_not_touch
54
+ self._placeholders[placeholder] = value
55
+ return ""
56
+
57
+ def param_exists(self, param_name: str) -> bool:
58
+ """
59
+ Method to check whether a given parameter exists and is enabled (i.e., not hidden based on other parameter selections) for the current
60
+ dataset at runtime.
61
+
62
+ Arguments:
63
+ param_name: A string for the name of the parameter
64
+
65
+ Returns:
66
+ A boolean for whether the parameter exists
67
+ """
68
+ return (param_name in self.prms and self.prms[param_name].is_enabled())
69
+
70
+
71
+ class ModelArgs(BuildModelArgs, ContextArgs):
72
+
73
+ def __init__(
74
+ self, ctx_args: ContextArgs, build_model_args: BuildModelArgs,
75
+ ctx: dict[str, Any]
76
+ ):
77
+ super(ContextArgs, self).__init__(ctx_args.project_path, ctx_args.proj_vars, ctx_args.env_vars)
78
+ self._project_path = ctx_args.project_path
79
+ self._proj_vars = ctx_args.proj_vars
80
+ self._env_vars = ctx_args.env_vars
81
+ self.user = ctx_args.user
82
+ self._prms = ctx_args.prms
83
+ self._configurables = ctx_args.configurables
84
+ self._placeholders = ctx_args._placeholders_copy
85
+ self._connections = build_model_args.connections
86
+ self._dependencies = build_model_args.dependencies
87
+ self._ref = build_model_args.ref
88
+ self._run_external_sql = build_model_args.run_external_sql
89
+ self._ctx = ctx
90
+
91
+ @property
92
+ def ctx(self) -> dict[str, Any]:
93
+ """
94
+ Dictionary of context variables
95
+ """
96
+ return self._ctx.copy()
97
+
98
+ def is_placeholder(self, placeholder: str) -> bool:
99
+ """
100
+ Checks whether a name is a valid placeholder
101
+
102
+ Arguments:
103
+ placeholder: A string for the name of the placeholder
104
+
105
+ Returns:
106
+ A boolean for whether name exists
107
+ """
108
+ return placeholder in self._placeholders
109
+
110
+ def get_placeholder_value(self, placeholder: str) -> Any | None:
111
+ """
112
+ Gets the value of a placeholder.
113
+
114
+ USE WITH CAUTION. Do not use the return value directly in a SQL query since that could be prone to SQL injection
115
+
116
+ Arguments:
117
+ placeholder: A string for the name of the placeholder
118
+
119
+ Returns:
120
+ An type for the value of the placeholder
121
+ """
122
+ return self._placeholders.get(placeholder)
123
+
124
+
125
+ class DashboardArgs(ParametersArgs):
126
+
127
+ def __init__(
128
+ self, param_args: ParametersArgs,
129
+ get_dataset: Callable[[str, dict[str, Any]], Coroutine[Any, Any, pl.DataFrame]]
130
+ ):
131
+ super().__init__(param_args.project_path, param_args.proj_vars, param_args.env_vars)
132
+ self._get_dataset = get_dataset
133
+
134
+ async def dataset(self, name: str, *, fixed_parameters: dict[str, Any] = {}) -> pl.DataFrame:
135
+ """
136
+ Get dataset as DataFrame given dataset name. Can use this to access protected/private datasets regardless of user authenticated to the dashboard.
137
+
138
+ The parameters used for the dataset include the parameter selections coming from the REST API and the fixed_parameters argument. The fixed_parameters takes precedence.
139
+
140
+ Arguments:
141
+ name: A string for the dataset name
142
+ fixed_parameters: Parameters to set for this dataset (in addition to the ones set through real-time selections)
143
+
144
+ Returns:
145
+ A DataFrame for the result of the dataset
146
+ """
147
+ return await self._get_dataset(name, fixed_parameters)