squirrels 0.1.0__py3-none-any.whl → 0.6.0.post0__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.
Files changed (127) hide show
  1. dateutils/__init__.py +6 -0
  2. dateutils/_enums.py +25 -0
  3. squirrels/dateutils.py → dateutils/_implementation.py +409 -380
  4. dateutils/types.py +6 -0
  5. squirrels/__init__.py +21 -18
  6. squirrels/_api_routes/__init__.py +5 -0
  7. squirrels/_api_routes/auth.py +337 -0
  8. squirrels/_api_routes/base.py +196 -0
  9. squirrels/_api_routes/dashboards.py +156 -0
  10. squirrels/_api_routes/data_management.py +148 -0
  11. squirrels/_api_routes/datasets.py +220 -0
  12. squirrels/_api_routes/project.py +289 -0
  13. squirrels/_api_server.py +552 -134
  14. squirrels/_arguments/__init__.py +0 -0
  15. squirrels/_arguments/init_time_args.py +83 -0
  16. squirrels/_arguments/run_time_args.py +111 -0
  17. squirrels/_auth.py +777 -0
  18. squirrels/_command_line.py +239 -107
  19. squirrels/_compile_prompts.py +147 -0
  20. squirrels/_connection_set.py +94 -0
  21. squirrels/_constants.py +141 -64
  22. squirrels/_dashboards.py +179 -0
  23. squirrels/_data_sources.py +570 -0
  24. squirrels/_dataset_types.py +91 -0
  25. squirrels/_env_vars.py +209 -0
  26. squirrels/_exceptions.py +29 -0
  27. squirrels/_http_error_responses.py +52 -0
  28. squirrels/_initializer.py +319 -110
  29. squirrels/_logging.py +121 -0
  30. squirrels/_manifest.py +357 -187
  31. squirrels/_mcp_server.py +578 -0
  32. squirrels/_model_builder.py +69 -0
  33. squirrels/_model_configs.py +74 -0
  34. squirrels/_model_queries.py +52 -0
  35. squirrels/_models.py +1201 -0
  36. squirrels/_package_data/base_project/.env +7 -0
  37. squirrels/_package_data/base_project/.env.example +44 -0
  38. squirrels/_package_data/base_project/connections.yml +16 -0
  39. squirrels/_package_data/base_project/dashboards/dashboard_example.py +40 -0
  40. squirrels/_package_data/base_project/dashboards/dashboard_example.yml +22 -0
  41. squirrels/_package_data/base_project/docker/.dockerignore +16 -0
  42. squirrels/_package_data/base_project/docker/Dockerfile +16 -0
  43. squirrels/_package_data/base_project/docker/compose.yml +7 -0
  44. squirrels/_package_data/base_project/duckdb_init.sql +10 -0
  45. squirrels/_package_data/base_project/gitignore +13 -0
  46. squirrels/_package_data/base_project/macros/macros_example.sql +17 -0
  47. squirrels/_package_data/base_project/models/builds/build_example.py +26 -0
  48. squirrels/_package_data/base_project/models/builds/build_example.sql +16 -0
  49. squirrels/_package_data/base_project/models/builds/build_example.yml +57 -0
  50. squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +17 -0
  51. squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +32 -0
  52. squirrels/_package_data/base_project/models/federates/federate_example.py +51 -0
  53. squirrels/_package_data/base_project/models/federates/federate_example.sql +21 -0
  54. squirrels/_package_data/base_project/models/federates/federate_example.yml +65 -0
  55. squirrels/_package_data/base_project/models/sources.yml +38 -0
  56. squirrels/_package_data/base_project/parameters.yml +142 -0
  57. squirrels/_package_data/base_project/pyconfigs/connections.py +19 -0
  58. squirrels/_package_data/base_project/pyconfigs/context.py +96 -0
  59. squirrels/_package_data/base_project/pyconfigs/parameters.py +141 -0
  60. squirrels/_package_data/base_project/pyconfigs/user.py +56 -0
  61. squirrels/_package_data/base_project/resources/expenses.db +0 -0
  62. squirrels/_package_data/base_project/resources/public/.gitkeep +0 -0
  63. squirrels/_package_data/base_project/resources/weather.db +0 -0
  64. squirrels/_package_data/base_project/seeds/seed_categories.csv +6 -0
  65. squirrels/_package_data/base_project/seeds/seed_categories.yml +15 -0
  66. squirrels/_package_data/base_project/seeds/seed_subcategories.csv +15 -0
  67. squirrels/_package_data/base_project/seeds/seed_subcategories.yml +21 -0
  68. squirrels/_package_data/base_project/squirrels.yml.j2 +61 -0
  69. squirrels/_package_data/base_project/tmp/.gitignore +2 -0
  70. squirrels/_package_data/templates/login_successful.html +53 -0
  71. squirrels/_package_data/templates/squirrels_studio.html +22 -0
  72. squirrels/_package_loader.py +29 -0
  73. squirrels/_parameter_configs.py +592 -0
  74. squirrels/_parameter_options.py +348 -0
  75. squirrels/_parameter_sets.py +207 -0
  76. squirrels/_parameters.py +1703 -0
  77. squirrels/_project.py +796 -0
  78. squirrels/_py_module.py +122 -0
  79. squirrels/_request_context.py +33 -0
  80. squirrels/_schemas/__init__.py +0 -0
  81. squirrels/_schemas/auth_models.py +83 -0
  82. squirrels/_schemas/query_param_models.py +70 -0
  83. squirrels/_schemas/request_models.py +26 -0
  84. squirrels/_schemas/response_models.py +286 -0
  85. squirrels/_seeds.py +97 -0
  86. squirrels/_sources.py +112 -0
  87. squirrels/_utils.py +540 -149
  88. squirrels/_version.py +1 -3
  89. squirrels/arguments.py +7 -0
  90. squirrels/auth.py +4 -0
  91. squirrels/connections.py +3 -0
  92. squirrels/dashboards.py +3 -0
  93. squirrels/data_sources.py +14 -282
  94. squirrels/parameter_options.py +13 -189
  95. squirrels/parameters.py +14 -801
  96. squirrels/types.py +18 -0
  97. squirrels-0.6.0.post0.dist-info/METADATA +148 -0
  98. squirrels-0.6.0.post0.dist-info/RECORD +101 -0
  99. {squirrels-0.1.0.dist-info → squirrels-0.6.0.post0.dist-info}/WHEEL +1 -2
  100. {squirrels-0.1.0.dist-info → squirrels-0.6.0.post0.dist-info}/entry_points.txt +1 -0
  101. squirrels-0.6.0.post0.dist-info/licenses/LICENSE +201 -0
  102. squirrels/_credentials_manager.py +0 -87
  103. squirrels/_module_loader.py +0 -37
  104. squirrels/_parameter_set.py +0 -151
  105. squirrels/_renderer.py +0 -286
  106. squirrels/_timed_imports.py +0 -37
  107. squirrels/connection_set.py +0 -126
  108. squirrels/package_data/base_project/.gitignore +0 -4
  109. squirrels/package_data/base_project/connections.py +0 -21
  110. squirrels/package_data/base_project/database/sample_database.db +0 -0
  111. squirrels/package_data/base_project/database/seattle_weather.db +0 -0
  112. squirrels/package_data/base_project/datasets/sample_dataset/context.py +0 -8
  113. squirrels/package_data/base_project/datasets/sample_dataset/database_view1.py +0 -23
  114. squirrels/package_data/base_project/datasets/sample_dataset/database_view1.sql.j2 +0 -7
  115. squirrels/package_data/base_project/datasets/sample_dataset/final_view.py +0 -10
  116. squirrels/package_data/base_project/datasets/sample_dataset/final_view.sql.j2 +0 -2
  117. squirrels/package_data/base_project/datasets/sample_dataset/parameters.py +0 -30
  118. squirrels/package_data/base_project/datasets/sample_dataset/selections.cfg +0 -6
  119. squirrels/package_data/base_project/squirrels.yaml +0 -26
  120. squirrels/package_data/static/favicon.ico +0 -0
  121. squirrels/package_data/static/script.js +0 -234
  122. squirrels/package_data/static/style.css +0 -110
  123. squirrels/package_data/templates/index.html +0 -32
  124. squirrels-0.1.0.dist-info/LICENSE +0 -22
  125. squirrels-0.1.0.dist-info/METADATA +0 -67
  126. squirrels-0.1.0.dist-info/RECORD +0 -40
  127. squirrels-0.1.0.dist-info/top_level.txt +0 -1
File without changes
@@ -0,0 +1,83 @@
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
+
8
+ @dataclass
9
+ class ConnectionsArgs:
10
+ project_path: str
11
+ proj_vars: dict[str, Any]
12
+ env_vars: dict[str, str]
13
+
14
+ def __post_init__(self) -> None:
15
+ self.proj_vars = self.proj_vars.copy()
16
+ self.env_vars = self.env_vars.copy()
17
+
18
+
19
+ @dataclass
20
+ class AuthProviderArgs(ConnectionsArgs):
21
+ pass
22
+
23
+
24
+ @dataclass
25
+ class ParametersArgs(ConnectionsArgs):
26
+ pass
27
+
28
+
29
+ @dataclass
30
+ class BuildModelArgs(ConnectionsArgs):
31
+ connections: dict[str, Any]
32
+ dependencies: Iterable[str]
33
+ _ref_func: Callable[[str], pl.LazyFrame]
34
+ _run_external_sql_func: Callable[[str, str], pl.DataFrame]
35
+
36
+ def __post_init__(self) -> None:
37
+ super().__post_init__()
38
+ self.connections = self.connections.copy()
39
+ self.dependencies = set(self.dependencies)
40
+
41
+ def ref(self, model: str) -> pl.LazyFrame:
42
+ """
43
+ Returns the result (as polars DataFrame) of a dependent model (predefined in "dependencies" function)
44
+
45
+ Note: This is different behaviour than the "ref" function for SQL models, which figures out the dependent models for you,
46
+ and returns a string for the table/view name instead of a polars DataFrame.
47
+
48
+ Arguments:
49
+ model: The model name
50
+
51
+ Returns:
52
+ A polars DataFrame
53
+ """
54
+ return self._ref_func(model)
55
+
56
+ def run_external_sql(self, connection_name: str, sql_query: str, **kwargs) -> pl.DataFrame:
57
+ """
58
+ Runs a SQL query against an external database, with option to specify the connection name. Placeholder values are provided automatically
59
+
60
+ Arguments:
61
+ sql_query: The SQL query. Can be parameterized with placeholders
62
+ connection_name: The connection name for the database. If None, uses the one configured for the model
63
+
64
+ Returns:
65
+ The query result as a polars DataFrame
66
+ """
67
+ return self._run_external_sql_func(sql_query, connection_name)
68
+
69
+ def run_sql_on_dataframes(self, sql_query: str, *, dataframes: dict[str, pl.LazyFrame] | None = None, **kwargs) -> pl.DataFrame:
70
+ """
71
+ Uses a dictionary of dataframes to execute a SQL query in an embedded in-memory DuckDB database
72
+
73
+ Arguments:
74
+ sql_query: The SQL query to run (DuckDB dialect)
75
+ dataframes: A dictionary of table names to their polars LazyFrame. If None, uses results of dependent models
76
+
77
+ Returns:
78
+ The result as a polars DataFrame from running the query
79
+ """
80
+ if dataframes is None:
81
+ dataframes = {x: self.ref(x) for x in self.dependencies}
82
+
83
+ return u.run_sql_on_dataframes(sql_query, dataframes)
@@ -0,0 +1,111 @@
1
+ from typing import Callable, Any, Coroutine
2
+ from dataclasses import dataclass, field, KW_ONLY
3
+ import polars as pl
4
+
5
+ from .init_time_args import ConnectionsArgs, ParametersArgs, BuildModelArgs
6
+ from .._schemas.auth_models import AbstractUser
7
+ from .._parameters import Parameter, TextValue
8
+
9
+
10
+ @dataclass
11
+ class ContextArgs(ParametersArgs):
12
+ user: AbstractUser
13
+ prms: dict[str, Parameter]
14
+ configurables: dict[str, str]
15
+ _conn_args: ConnectionsArgs
16
+ _: KW_ONLY
17
+ _placeholders: dict[str, Any] = field(default_factory=dict)
18
+
19
+ def __post_init__(self) -> None:
20
+ super().__post_init__()
21
+ self.prms = self.prms.copy()
22
+ self.configurables = self.configurables.copy()
23
+ self._conn_args = ConnectionsArgs(**self._conn_args.__dict__)
24
+ self._placeholders = self._placeholders.copy()
25
+
26
+ def set_placeholder(self, placeholder: str, value: TextValue | Any) -> str:
27
+ """
28
+ Method to set a placeholder value.
29
+
30
+ Arguments:
31
+ placeholder: A string for the name of the placeholder
32
+ value: The value of the placeholder. Can be of any type
33
+ """
34
+ if isinstance(value, TextValue):
35
+ value = value._value_do_not_touch
36
+ self._placeholders[placeholder] = value
37
+ return ""
38
+
39
+ def param_exists(self, param_name: str) -> bool:
40
+ """
41
+ Method to check whether a given parameter exists and is enabled (i.e., not hidden based on other parameter selections) for the current
42
+ dataset at runtime.
43
+
44
+ Arguments:
45
+ param_name: A string for the name of the parameter
46
+
47
+ Returns:
48
+ A boolean for whether the parameter exists
49
+ """
50
+ return (param_name in self.prms and self.prms[param_name].is_enabled())
51
+
52
+
53
+ @dataclass
54
+ class ModelArgs(ContextArgs, BuildModelArgs):
55
+ ctx: dict[str, Any]
56
+
57
+ def __post_init__(self) -> None:
58
+ ContextArgs.__post_init__(self)
59
+ BuildModelArgs.__post_init__(self)
60
+ self.ctx = self.ctx.copy()
61
+
62
+ def is_placeholder(self, placeholder: str) -> bool:
63
+ """
64
+ Checks whether a name is a valid placeholder
65
+
66
+ Arguments:
67
+ placeholder: A string for the name of the placeholder
68
+
69
+ Returns:
70
+ A boolean for whether name exists
71
+ """
72
+ return placeholder in self._placeholders
73
+
74
+ def get_placeholder_value(self, placeholder: str) -> Any | None:
75
+ """
76
+ Gets the value of a placeholder.
77
+
78
+ USE WITH CAUTION. Do not use the return value directly in a SQL query since that could be prone to SQL injection
79
+
80
+ Arguments:
81
+ placeholder: A string for the name of the placeholder
82
+
83
+ Returns:
84
+ An type for the value of the placeholder
85
+ """
86
+ return self._placeholders.get(placeholder)
87
+
88
+
89
+ @dataclass
90
+ class DashboardArgs(ContextArgs):
91
+ ctx: dict[str, Any]
92
+ _get_dataset: Callable[[str, dict[str, Any]], Coroutine[Any, Any, pl.DataFrame]]
93
+
94
+ def __post_init__(self) -> None:
95
+ super().__post_init__()
96
+ self.ctx = self.ctx.copy()
97
+
98
+ async def dataset(self, name: str, *, fixed_parameters: dict[str, Any] = {}) -> pl.DataFrame:
99
+ """
100
+ Get dataset as DataFrame given dataset name. Can use this to access protected/private datasets regardless of user authenticated to the dashboard.
101
+
102
+ 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.
103
+
104
+ Arguments:
105
+ name: A string for the dataset name
106
+ fixed_parameters: Parameters to set for this dataset (in addition to the ones set through real-time selections)
107
+
108
+ Returns:
109
+ A DataFrame for the result of the dataset
110
+ """
111
+ return await self._get_dataset(name, fixed_parameters)