squirrels 0.5.0b3__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.
- squirrels/__init__.py +4 -0
- squirrels/_api_routes/__init__.py +5 -0
- squirrels/_api_routes/auth.py +337 -0
- squirrels/_api_routes/base.py +196 -0
- squirrels/_api_routes/dashboards.py +156 -0
- squirrels/_api_routes/data_management.py +148 -0
- squirrels/_api_routes/datasets.py +220 -0
- squirrels/_api_routes/project.py +289 -0
- squirrels/_api_server.py +440 -792
- squirrels/_arguments/__init__.py +0 -0
- squirrels/_arguments/{_init_time_args.py → init_time_args.py} +23 -43
- squirrels/_arguments/{_run_time_args.py → run_time_args.py} +32 -68
- squirrels/_auth.py +590 -264
- squirrels/_command_line.py +130 -58
- squirrels/_compile_prompts.py +147 -0
- squirrels/_connection_set.py +16 -15
- squirrels/_constants.py +36 -11
- squirrels/_dashboards.py +179 -0
- squirrels/_data_sources.py +40 -34
- squirrels/_dataset_types.py +16 -11
- squirrels/_env_vars.py +209 -0
- squirrels/_exceptions.py +9 -37
- squirrels/_http_error_responses.py +52 -0
- squirrels/_initializer.py +7 -6
- squirrels/_logging.py +121 -0
- squirrels/_manifest.py +155 -77
- squirrels/_mcp_server.py +578 -0
- squirrels/_model_builder.py +11 -55
- squirrels/_model_configs.py +5 -5
- squirrels/_model_queries.py +1 -1
- squirrels/_models.py +276 -143
- squirrels/_package_data/base_project/.env +1 -24
- squirrels/_package_data/base_project/.env.example +31 -17
- squirrels/_package_data/base_project/connections.yml +4 -3
- squirrels/_package_data/base_project/dashboards/dashboard_example.py +13 -7
- squirrels/_package_data/base_project/dashboards/dashboard_example.yml +6 -6
- squirrels/_package_data/base_project/docker/Dockerfile +2 -2
- squirrels/_package_data/base_project/docker/compose.yml +1 -1
- squirrels/_package_data/base_project/duckdb_init.sql +1 -0
- squirrels/_package_data/base_project/models/builds/build_example.py +2 -2
- squirrels/_package_data/base_project/models/dbviews/dbview_example.sql +7 -2
- squirrels/_package_data/base_project/models/dbviews/dbview_example.yml +16 -10
- squirrels/_package_data/base_project/models/federates/federate_example.py +27 -17
- squirrels/_package_data/base_project/models/federates/federate_example.sql +3 -7
- squirrels/_package_data/base_project/models/federates/federate_example.yml +7 -7
- squirrels/_package_data/base_project/models/sources.yml +5 -6
- squirrels/_package_data/base_project/parameters.yml +24 -38
- squirrels/_package_data/base_project/pyconfigs/connections.py +8 -3
- squirrels/_package_data/base_project/pyconfigs/context.py +26 -14
- squirrels/_package_data/base_project/pyconfigs/parameters.py +124 -81
- squirrels/_package_data/base_project/pyconfigs/user.py +48 -15
- squirrels/_package_data/base_project/resources/public/.gitkeep +0 -0
- squirrels/_package_data/base_project/seeds/seed_categories.yml +1 -1
- squirrels/_package_data/base_project/seeds/seed_subcategories.yml +1 -1
- squirrels/_package_data/base_project/squirrels.yml.j2 +21 -31
- squirrels/_package_data/templates/login_successful.html +53 -0
- squirrels/_package_data/templates/squirrels_studio.html +22 -0
- squirrels/_parameter_configs.py +43 -22
- squirrels/_parameter_options.py +1 -1
- squirrels/_parameter_sets.py +41 -30
- squirrels/_parameters.py +560 -123
- squirrels/_project.py +487 -277
- squirrels/_py_module.py +71 -10
- squirrels/_request_context.py +33 -0
- squirrels/_schemas/__init__.py +0 -0
- squirrels/_schemas/auth_models.py +83 -0
- squirrels/_schemas/query_param_models.py +70 -0
- squirrels/_schemas/request_models.py +26 -0
- squirrels/_schemas/response_models.py +286 -0
- squirrels/_seeds.py +52 -13
- squirrels/_sources.py +29 -23
- squirrels/_utils.py +221 -42
- squirrels/_version.py +1 -3
- squirrels/arguments.py +7 -2
- squirrels/auth.py +4 -0
- squirrels/connections.py +2 -0
- squirrels/dashboards.py +3 -1
- squirrels/data_sources.py +6 -0
- squirrels/parameter_options.py +5 -0
- squirrels/parameters.py +5 -0
- squirrels/types.py +10 -3
- squirrels-0.6.0.post0.dist-info/METADATA +148 -0
- squirrels-0.6.0.post0.dist-info/RECORD +101 -0
- {squirrels-0.5.0b3.dist-info → squirrels-0.6.0.post0.dist-info}/WHEEL +1 -1
- squirrels/_api_response_models.py +0 -190
- squirrels/_dashboard_types.py +0 -82
- squirrels/_dashboards_io.py +0 -79
- squirrels-0.5.0b3.dist-info/METADATA +0 -110
- squirrels-0.5.0b3.dist-info/RECORD +0 -80
- /squirrels/_package_data/base_project/{assets → resources}/expenses.db +0 -0
- /squirrels/_package_data/base_project/{assets → resources}/weather.db +0 -0
- {squirrels-0.5.0b3.dist-info → squirrels-0.6.0.post0.dist-info}/entry_points.txt +0 -0
- {squirrels-0.5.0b3.dist-info → squirrels-0.6.0.post0.dist-info}/licenses/LICENSE +0 -0
squirrels/types.py
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
|
+
from ._api_server import FastAPIComponents
|
|
2
|
+
|
|
1
3
|
from ._data_sources import DataSource
|
|
2
4
|
|
|
3
5
|
from ._parameter_options import ParameterOption
|
|
4
6
|
|
|
5
7
|
from ._parameters import Parameter, TextValue
|
|
6
8
|
|
|
7
|
-
from ._auth import BaseUser
|
|
8
|
-
|
|
9
9
|
from ._dataset_types import DatasetMetadata, DatasetResult
|
|
10
10
|
|
|
11
|
-
from .
|
|
11
|
+
from ._dashboards import Dashboard
|
|
12
|
+
|
|
13
|
+
from ._parameter_configs import ParameterConfigBase
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"FastAPIComponents", "DataSource", "ParameterOption", "Parameter", "TextValue",
|
|
17
|
+
"DatasetMetadata", "DatasetResult", "Dashboard", "ParameterConfigBase"
|
|
18
|
+
]
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: squirrels
|
|
3
|
+
Version: 0.6.0.post0
|
|
4
|
+
Summary: Squirrels - SDK for Data Analytics API & MCP Server
|
|
5
|
+
Project-URL: Homepage, https://docs.pysquirrels.com
|
|
6
|
+
Project-URL: Repository, https://github.com/squirrels-analytics/squirrels
|
|
7
|
+
Project-URL: Documentation, https://docs.pysquirrels.com
|
|
8
|
+
Author-email: Tim Huang <timhuang95@gmail.com>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
13
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
14
|
+
Classifier: Typing :: Typed
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Requires-Dist: authlib>=1.5.2
|
|
17
|
+
Requires-Dist: bcrypt>=4.0.1
|
|
18
|
+
Requires-Dist: cachetools>=5.3.2
|
|
19
|
+
Requires-Dist: duckdb>=1.4.0
|
|
20
|
+
Requires-Dist: fastapi>=0.112.1
|
|
21
|
+
Requires-Dist: gitpython>=3.1.41
|
|
22
|
+
Requires-Dist: inquirer>=3.2.1
|
|
23
|
+
Requires-Dist: itsdangerous>=2.2.0
|
|
24
|
+
Requires-Dist: jinja2>=3.1.3
|
|
25
|
+
Requires-Dist: libpass>=1.9.0
|
|
26
|
+
Requires-Dist: matplotlib>=3.8.3
|
|
27
|
+
Requires-Dist: mcp>=1.24.0
|
|
28
|
+
Requires-Dist: pandas>=2.1.4
|
|
29
|
+
Requires-Dist: polars>=1.14.0
|
|
30
|
+
Requires-Dist: pyarrow>=19.0.1
|
|
31
|
+
Requires-Dist: pydantic>=2.8.2
|
|
32
|
+
Requires-Dist: pyjwt>=2.8.0
|
|
33
|
+
Requires-Dist: python-dotenv>=1.0.1
|
|
34
|
+
Requires-Dist: python-multipart>=0.0.9
|
|
35
|
+
Requires-Dist: pyyaml>=6.0.1
|
|
36
|
+
Requires-Dist: requests>=2.32.5
|
|
37
|
+
Requires-Dist: sqlalchemy>=2.0.25
|
|
38
|
+
Requires-Dist: sqlglot>=26.12.1
|
|
39
|
+
Requires-Dist: update-checker>=0.18.0
|
|
40
|
+
Requires-Dist: uvicorn>=0.30.6
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
|
|
43
|
+
# Squirrels
|
|
44
|
+
|
|
45
|
+
Squirrels is an API framework that lets you create REST APIs for dynamic data analytics!
|
|
46
|
+
|
|
47
|
+
**Documentation**: <a href="https://docs.pysquirrels.com" target="_blank">https://docs.pysquirrels.com</a>
|
|
48
|
+
|
|
49
|
+
**Source Code**: <a href="https://github.com/squirrels-analytics/squirrels" target="_blank">https://github.com/squirrels-analytics/squirrels</a>
|
|
50
|
+
|
|
51
|
+
## Table of Contents
|
|
52
|
+
|
|
53
|
+
- [Main Features](#main-features)
|
|
54
|
+
- [License](#license)
|
|
55
|
+
- [Contributing to Squirrels](#contributing-to-squirrels)
|
|
56
|
+
- [Setup](#setup)
|
|
57
|
+
- [Testing](#testing)
|
|
58
|
+
- [Project Structure](#project-structure)
|
|
59
|
+
|
|
60
|
+
## Main Features
|
|
61
|
+
|
|
62
|
+
Here are a few of the things that Squirrels can do:
|
|
63
|
+
|
|
64
|
+
- Connect to any database by specifying its SQLAlchemy url (in `squirrels.yml`) or by using its native connector library in python (in `connections.py`).
|
|
65
|
+
- Configure API routes for datasets (in `squirrels.yml`) without writing code.
|
|
66
|
+
- Configure parameter widgets (types include single-select, multi-select, date, number, etc.) for your datasets (in `parameters.py`).
|
|
67
|
+
- Use SQL templates (templated with Jinja, like dbt) or python functions (that return a Python dataframe in polars or pandas) to define dynamic query logic based on parameter selections.
|
|
68
|
+
- Query multiple databases and join the results together in a final view in one API endpoint/dataset!
|
|
69
|
+
- Test your API endpoints with Squirrels Studio or by a command line that generates rendered sql queries and results as files (for a given set of parameter selections).
|
|
70
|
+
- Define User model (in `user.py`) and authorize privacy scope per dataset (in `squirrels.yml`). The user's attributes can even be used in your query logic!
|
|
71
|
+
- Serve dataset metadata and results to AI agents via MCP (Model Context Protocol)
|
|
72
|
+
|
|
73
|
+
## Quick Start
|
|
74
|
+
|
|
75
|
+
In a new virtual environment, install `squirrels`. Then, in your project directory, activate the virtual environment and run the following commands:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
sqrl new --use-defaults --curr-dir
|
|
79
|
+
sqrl build
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
To run the API server, simply run:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
sqrl run
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
Squirrels is released under the Apache 2.0 license.
|
|
91
|
+
|
|
92
|
+
See the file LICENSE for more details.
|
|
93
|
+
|
|
94
|
+
## Contributing to Squirrels
|
|
95
|
+
|
|
96
|
+
The sections below describe how to set up your local environment for Squirrels development and run unit tests. A high level overview of the project structure is also provided.
|
|
97
|
+
|
|
98
|
+
### Setup
|
|
99
|
+
|
|
100
|
+
This project requires the python package manager `uv` with Python 3.10 or above. Information on setting up uv can be found at: https://docs.astral.sh/uv/getting-started/installation/.
|
|
101
|
+
|
|
102
|
+
Then, to install all dependencies in a virtual environment, run:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
uv sync -p 3.10
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
And activate the virtual environment with:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
source .venv/bin/activate
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
To confirm that the setup worked, run the following to show the help page for all Squirrels CLI commands:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
sqrl -h
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Project Structure
|
|
121
|
+
|
|
122
|
+
From the root of the git repo, the source code can be found in the `squirrels` folder and unit tests can be found in the `tests` folder.
|
|
123
|
+
|
|
124
|
+
The documentation contents are in the `docs/` folder and are built with Mintlify.
|
|
125
|
+
|
|
126
|
+
To understand what a specific Squirrels command is doing, start from the `_command_line.py` file as your entry point.
|
|
127
|
+
|
|
128
|
+
The library version is maintained in both the `pyproject.toml` and the `squirrels/_version.py` files.
|
|
129
|
+
|
|
130
|
+
### Testing
|
|
131
|
+
|
|
132
|
+
Run `uv run pytest`. Or if you have the virtual environment activated, simply run `pytest`.
|
|
133
|
+
|
|
134
|
+
### Documentation
|
|
135
|
+
|
|
136
|
+
Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview your documentation changes locally. To install, use the following command:
|
|
137
|
+
|
|
138
|
+
```
|
|
139
|
+
npm i -g mint
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Run the following command in the `docs/` folder, where the `docs.json` is located:
|
|
143
|
+
|
|
144
|
+
```
|
|
145
|
+
mint dev
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
View your local preview at `http://localhost:3000`.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
dateutils/__init__.py,sha256=dq4VSlJ5ztaDPdvYBRAvXSyanT_CZif3I4O0YVmWfa8,277
|
|
2
|
+
dateutils/_enums.py,sha256=WBrnLqta_iMMhGMEn24cCO1Vlr7bST0E8oEfAL3z0P8,373
|
|
3
|
+
dateutils/_implementation.py,sha256=PVJAdNolDdTpCZXwvokKoMIZzTSNpCUvZlVLWpMeSho,15173
|
|
4
|
+
dateutils/types.py,sha256=xcRwBoftQi-uHM1tlVTW5xgN84qdrqCo5tQT7A34S8Y,124
|
|
5
|
+
squirrels/__init__.py,sha256=nvzVVd5yHYbpQAfyKdQGDMxZpW7wVq3uUlpg4Urc_ws,320
|
|
6
|
+
squirrels/_api_server.py,sha256=wE3Wz-IfKWENrKiyC1b96ANjlG8STOplxqRe3eBhJJ0,25534
|
|
7
|
+
squirrels/_auth.py,sha256=aWYZ9tmx9FSIhWfA0OYVRVL04L9CnYVX2r56DycQ2Go,34961
|
|
8
|
+
squirrels/_command_line.py,sha256=gRXM1EkjRrwSdiC19BQGnlFQizdpf2LwcnP5JiUcvEU,15336
|
|
9
|
+
squirrels/_compile_prompts.py,sha256=XIbRciSXak6NuDD4KedeDoUV5YSHvctQGk6HMxKchBw,5562
|
|
10
|
+
squirrels/_connection_set.py,sha256=r8OXth9L3f_HUE7WU0Tjrsmu0EN3NFL_HVXDlQDCuUA,4032
|
|
11
|
+
squirrels/_constants.py,sha256=317Ab7EQz1VimzGghcQw26YAFmjNg5uJ2yIqWEZqOvg,4100
|
|
12
|
+
squirrels/_dashboards.py,sha256=momVodpSveuD-0HdKA9vIJTYYl0WHNfG9NxhfNQ9wmY,6004
|
|
13
|
+
squirrels/_data_sources.py,sha256=BsuNcUEt9fLdLARbjzaLcf7PhPVLyHNeZuEFbKlkw6I,26445
|
|
14
|
+
squirrels/_dataset_types.py,sha256=qp2z5SblubPKu2o-oiKuKJhKiyT4lAPZnsiDXUsFW2I,2959
|
|
15
|
+
squirrels/_env_vars.py,sha256=gPeZL1cZ8z_hDuOdyJH2h9uIfaIu9D3_0hgs42KICxU,7966
|
|
16
|
+
squirrels/_exceptions.py,sha256=-hfDZoV-JhvuNRAERTFg-5NFjr0uNk4i9ogNgJfAyyc,1171
|
|
17
|
+
squirrels/_http_error_responses.py,sha256=_LFBFWL0My4E_CStDBOJs8shdu0cp5mP_2WoiH-lqW8,2004
|
|
18
|
+
squirrels/_initializer.py,sha256=9isok4vJQriAPzKCHQ8sXgf50GIFSo5E5wPwl0CuXK8,14333
|
|
19
|
+
squirrels/_logging.py,sha256=WgL48t0-1aLhfLU235PQ9CaE1o2LOckdZD-jfYsQc1Y,4308
|
|
20
|
+
squirrels/_manifest.py,sha256=tspmREFlnl-mq0zFtrBzeAmfWph4CjUnJnMM71mxW9c,13236
|
|
21
|
+
squirrels/_mcp_server.py,sha256=jl60AMxekAGlG75ij8AE-LV101TAZVxmN9YqhYVR3-s,27446
|
|
22
|
+
squirrels/_model_builder.py,sha256=och7eKtde38xM-aZZ-VcSAFu8muuf0JtlELNaKIx-F4,2779
|
|
23
|
+
squirrels/_model_configs.py,sha256=szDu_byDoQOdSSui9pnZfD5ZGcY_UNNwKOJqtMgbK0c,3352
|
|
24
|
+
squirrels/_model_queries.py,sha256=2fl07feHtzddBpiXUWGfNBYeoN_EZ7K5mAz2Jc-vCvs,1087
|
|
25
|
+
squirrels/_models.py,sha256=PXzb-j8sRlJEXmJxZmTc29SKq2obQVoyJZrMOOC2gC8,55352
|
|
26
|
+
squirrels/_package_loader.py,sha256=xcIur5Z38OWd-OVjsueFstVV567zlkK9UBnLS4NawJY,1158
|
|
27
|
+
squirrels/_parameter_configs.py,sha256=K7p_pIobT-gPZ99ewzLKV1aUzhnmfbGO7WjuzgjhDM8,24867
|
|
28
|
+
squirrels/_parameter_options.py,sha256=HatFFPyHrZo2ct3BS-FCHPzNqcIst4dVh14SgkhhFyw,16874
|
|
29
|
+
squirrels/_parameter_sets.py,sha256=uvpSL_2eeqyQECKkBMv_gyLR2vKW-n42OuecN6h1730,10345
|
|
30
|
+
squirrels/_parameters.py,sha256=SQsVd7OEWFfoA21d_0uf_KD9Li2wgMNQzJMO8GhgyRw,77664
|
|
31
|
+
squirrels/_project.py,sha256=VKKJj8Srp8zNrWKHNuNm5a4VW-yBt5hdmlap22zX-OU,40490
|
|
32
|
+
squirrels/_py_module.py,sha256=62yfbIRrZvz8oO3wb2EHQW9SHvDpLptu36JVh50Q3YQ,4796
|
|
33
|
+
squirrels/_request_context.py,sha256=5FBxIQJ_Ki0sekZC_XrzS4GIegqoJuPnalQhGBsm-kQ,964
|
|
34
|
+
squirrels/_seeds.py,sha256=ROlMHhBz1xdS8mJYWPT9-zzH5KdzyCqgV_lDWNE_zEw,3311
|
|
35
|
+
squirrels/_sources.py,sha256=7zXrPZtJFR-JtAWH7NS7cJbNCiY1WE5GokGPUPwcZvs,5292
|
|
36
|
+
squirrels/_utils.py,sha256=12foyZTRw8rw5mj5b4E9VwHdGLEe7Tgde730jL9OMbw,18462
|
|
37
|
+
squirrels/_version.py,sha256=CBY3jsC-9HCm7eZ6CKD-sYLCejqOJ1pYWPQM4LGIXcI,22
|
|
38
|
+
squirrels/arguments.py,sha256=6rWDwv8jbimBUYv4peE2kEuFzOQ4jn9Tr_QXUmEj0_o,324
|
|
39
|
+
squirrels/auth.py,sha256=oX5-0QT4aKiUSyImKkLtPLYoki1SVNgaU3KBQzIizP4,193
|
|
40
|
+
squirrels/connections.py,sha256=FVK0se1LUAzsapPZYlWc1q6jTJ6hiU2RuYinBEvZ5a0,122
|
|
41
|
+
squirrels/dashboards.py,sha256=egYWL7jV9hvyxZ0vFziQb4q3sKDLfE_TNJN5niQbzX4,98
|
|
42
|
+
squirrels/data_sources.py,sha256=P3VIGWqspXLlxKUTDXc5u5eJ2yQoo4rvy9RGEb_OIbQ,347
|
|
43
|
+
squirrels/parameter_options.py,sha256=5ucgTWvdwefurMrk7xiJhmRn6fbBXXOhQdH7Mbnm-1I,382
|
|
44
|
+
squirrels/parameters.py,sha256=TJcsjtj0Kg0F69I5Zk7r0uDJC7p8duk3gtjXjcQPE40,366
|
|
45
|
+
squirrels/types.py,sha256=kUWz-S-CmCWS5Q9zwoJyLKJ46l202uVcBOPKjegztdo,502
|
|
46
|
+
squirrels/_api_routes/__init__.py,sha256=-oGMDfM5Qo7NDiwpjHt8BKVZNNZ4798-NZCJzYCUdbc,106
|
|
47
|
+
squirrels/_api_routes/auth.py,sha256=em2jE0_DxwbqHFHdMr3vQNMCUqx8WXuYhRGFaf4p5Bw,17983
|
|
48
|
+
squirrels/_api_routes/base.py,sha256=7ExlpxKXxGz2c6obw9gmFANYOB1nhIl48uASJf8B338,8878
|
|
49
|
+
squirrels/_api_routes/dashboards.py,sha256=4pDjPXSCm8BNRci_qYQSY4mLeqEEGwuPaIFhxlrqNyw,8574
|
|
50
|
+
squirrels/_api_routes/data_management.py,sha256=XzhIH1XILqwhI9gkr_b8J1c2eZTRBdM6Ht_5amUM1xs,8275
|
|
51
|
+
squirrels/_api_routes/datasets.py,sha256=h19sH8No9L9Bl0frnkRGq1piqCu1p4t9b4n85uexbUo,11803
|
|
52
|
+
squirrels/_api_routes/project.py,sha256=bY8jmLF3fzRl4Q3YlAndO8zWBnlY8uQ-A-tO58rF88g,16179
|
|
53
|
+
squirrels/_arguments/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
|
+
squirrels/_arguments/init_time_args.py,sha256=a6oX_OwK-6SorGlyAIhR7BfMUNZcH4qQkAcYgAQ2T4I,2784
|
|
55
|
+
squirrels/_arguments/run_time_args.py,sha256=X3XZ2zkRtUE2c3yarb-LlNG4UTPB-sZTr9fUp1DerDw,3884
|
|
56
|
+
squirrels/_package_data/base_project/.env,sha256=gTk0lu-yEvPeoXI0xhXbJEOh2C7ECQgz9oT9FOPoGuM,352
|
|
57
|
+
squirrels/_package_data/base_project/.env.example,sha256=U9DpOZfSI1MLkGAKd7jH6SiczWsBjGE7lJlyq_HObg4,1812
|
|
58
|
+
squirrels/_package_data/base_project/connections.yml,sha256=eBIbTQqyp5FlxDs0HyQ_NuE2Nx87EW53Qp1Y_c1ygv0,1093
|
|
59
|
+
squirrels/_package_data/base_project/duckdb_init.sql,sha256=PYUiQZajja-TG7EU1__PoiyDajgngEil4Lxenv5FWT0,284
|
|
60
|
+
squirrels/_package_data/base_project/gitignore,sha256=B9OEkQ_j9fZGA2IAyVUvXeylxpya-AUwzLzqzMN4Bfc,155
|
|
61
|
+
squirrels/_package_data/base_project/parameters.yml,sha256=--N_u3vA2tnT4uDxnkgxSs135i37N9N01gnYjD2jMRY,6741
|
|
62
|
+
squirrels/_package_data/base_project/squirrels.yml.j2,sha256=6MDG1FnLYU507i6jkrlnBQDIlAnpO0tNUPLhqRlNSXM,1919
|
|
63
|
+
squirrels/_package_data/base_project/dashboards/dashboard_example.py,sha256=XDRUxzb5Kyecylb2YV0Q3RD56Bw4doye_hhdgiQ6ck0,1800
|
|
64
|
+
squirrels/_package_data/base_project/dashboards/dashboard_example.yml,sha256=2XU4zH8dBxnGxusMX8eOMOTPQAVLdQQ50w3B9GOiMR4,481
|
|
65
|
+
squirrels/_package_data/base_project/docker/.dockerignore,sha256=IN0ZmxwLdmYlw6I2ziTdzXkTbZWCUyV4kfUI9_lDz-A,201
|
|
66
|
+
squirrels/_package_data/base_project/docker/Dockerfile,sha256=0pi4IMXhZKcS6Nfg2wKATESZP84_r2Sp-Kh8cfMGOcY,470
|
|
67
|
+
squirrels/_package_data/base_project/docker/compose.yml,sha256=c5_Zng1lF4eOYM2tPNk7n4WroLjz0Apu4PCXni77fws,105
|
|
68
|
+
squirrels/_package_data/base_project/macros/macros_example.sql,sha256=kJMAxL9ihCd-ULPOfHkqt8TDIMcH6QAOFFw89VplGL0,508
|
|
69
|
+
squirrels/_package_data/base_project/models/sources.yml,sha256=axBHFoJtWjAcklZyibrr7zhyDRATxi9r_bGjI09Kulk,1816
|
|
70
|
+
squirrels/_package_data/base_project/models/builds/build_example.py,sha256=Obs1DpPTkXF4X7XxETJKxFnoPWPCrUWnaiV8N75IeWw,1024
|
|
71
|
+
squirrels/_package_data/base_project/models/builds/build_example.sql,sha256=52tqAIzFWJgX13CP4HNeBd5BFy7Z929Z0XxfLgGKthM,508
|
|
72
|
+
squirrels/_package_data/base_project/models/builds/build_example.yml,sha256=kUd6j5u8qU6UD294AowPBHFOb8yYDA_dxWlCIBrPl90,1407
|
|
73
|
+
squirrels/_package_data/base_project/models/dbviews/dbview_example.sql,sha256=DXBdikZayi7XJrE3a4_PFgFZwT1hBzpnOp89858IGPE,369
|
|
74
|
+
squirrels/_package_data/base_project/models/dbviews/dbview_example.yml,sha256=_wW3m0_pDMMbZHaJYjG5PKwOpcM5QlJbO0QiunOmEdA,1175
|
|
75
|
+
squirrels/_package_data/base_project/models/federates/federate_example.py,sha256=13dcIibmsyvbNGOEAHYoYzE5jisZizH-Sghevd4pqmo,2057
|
|
76
|
+
squirrels/_package_data/base_project/models/federates/federate_example.sql,sha256=9eTJfTSWAMV8lGtQ0Bg4A_Wpv0w1LRIf5fMx6OIZ7Uk,674
|
|
77
|
+
squirrels/_package_data/base_project/models/federates/federate_example.yml,sha256=9zxJrpY3V-wRfGTyD4cBNc8hy5gPxGgOsAnIh-3YMCY,2163
|
|
78
|
+
squirrels/_package_data/base_project/pyconfigs/connections.py,sha256=DGPQL39Aa3VyFQbFbmVmL_OvpjpQqmy2g_wfiPw5xfc,683
|
|
79
|
+
squirrels/_package_data/base_project/pyconfigs/context.py,sha256=ln5p8r2DZX98qqxuEMSn0GG4ZIc6_ISAq7EnlzYSDZA,4325
|
|
80
|
+
squirrels/_package_data/base_project/pyconfigs/parameters.py,sha256=-UlrCcuW2NqlNlEnYttQ-S09Lq5IpNkAVP5FNR2e33g,4794
|
|
81
|
+
squirrels/_package_data/base_project/pyconfigs/user.py,sha256=ZVXxvMSO6mcuAKy_m2VOR55urlj5RVdrf18ga1qG49k,2554
|
|
82
|
+
squirrels/_package_data/base_project/resources/expenses.db,sha256=aO0QdApW9ad8LRc73MW1o3eimryzmOAH5vz9Vc3dWK0,77824
|
|
83
|
+
squirrels/_package_data/base_project/resources/weather.db,sha256=dsHPO36gQdZ4ULAA726Hg3jp8a1dCdig1DhrGg8wTeg,86016
|
|
84
|
+
squirrels/_package_data/base_project/resources/public/.gitkeep,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
85
|
+
squirrels/_package_data/base_project/seeds/seed_categories.csv,sha256=jppjf1nOIxy7-bi5lJn5CVqmnLfJHHq0ABgp6UqbXnw,104
|
|
86
|
+
squirrels/_package_data/base_project/seeds/seed_categories.yml,sha256=UM2gIrwHU2qogKdQqeqP6s4QfE7fEzUsPr7HjqlX7ow,425
|
|
87
|
+
squirrels/_package_data/base_project/seeds/seed_subcategories.csv,sha256=Tta1oIgnc2nukNMDlUkIErRKNH_8YT5EPp1A2kQKcow,327
|
|
88
|
+
squirrels/_package_data/base_project/seeds/seed_subcategories.yml,sha256=fqXzZfVIQIlrVjW83K3epnVYFvF0X2Kiqe3KpvHgI5c,573
|
|
89
|
+
squirrels/_package_data/base_project/tmp/.gitignore,sha256=XImoqcWvJY0C0L_TWCx1ljvqU7qh9fUTJmK4ACCmNFI,13
|
|
90
|
+
squirrels/_package_data/templates/login_successful.html,sha256=hWLQLG_cNxZhRD27p5k-C_ZZbQ-gl0I-mxgAX-BLoDk,1113
|
|
91
|
+
squirrels/_package_data/templates/squirrels_studio.html,sha256=n0ymweLcaQYeMDaLBXV3Dt7TPO6HuPirX-WwpuQznxA,945
|
|
92
|
+
squirrels/_schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
93
|
+
squirrels/_schemas/auth_models.py,sha256=iP-XSr20IurFMA-nb-vTEJeieEE58R97oFVKeXZgjNI,2985
|
|
94
|
+
squirrels/_schemas/query_param_models.py,sha256=_afevpPU_aTCce-cu721_w7c5-T1N3-1XNF-CMoiwrA,4021
|
|
95
|
+
squirrels/_schemas/request_models.py,sha256=_TYxdmy4zYpVzw2qIX2KjIba_-zvCVI7b1Nc3tE1BEw,919
|
|
96
|
+
squirrels/_schemas/response_models.py,sha256=xIrwNIYuhyDOkRLH8j4bu2JNBzqhoFUZLtN1Glb5XRQ,20059
|
|
97
|
+
squirrels-0.6.0.post0.dist-info/METADATA,sha256=LNQDfzm3A3px9BwBs3t84W4twm1W0V8NP4l7-InF-NA,5225
|
|
98
|
+
squirrels-0.6.0.post0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
99
|
+
squirrels-0.6.0.post0.dist-info/entry_points.txt,sha256=i6vgjhJ3o_cdSFYofFcNY9DFMPr4MIcuwnkskSTXfJc,95
|
|
100
|
+
squirrels-0.6.0.post0.dist-info/licenses/LICENSE,sha256=qqERuumQtQVsMrEXvJHuecJvV2sLxbleEubd_Zk8dY8,11338
|
|
101
|
+
squirrels-0.6.0.post0.dist-info/RECORD,,
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
from typing import Annotated, Literal
|
|
2
|
-
from pydantic import BaseModel, Field
|
|
3
|
-
from datetime import datetime, date
|
|
4
|
-
|
|
5
|
-
from . import _model_configs as mc, _sources as s
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class LoginReponse(BaseModel):
|
|
9
|
-
access_token: Annotated[str, Field(examples=["encoded_jwt_token"], description="An encoded JSON web token to use subsequent API requests")]
|
|
10
|
-
token_type: Annotated[str, Field(examples=["bearer"], description='Always "bearer" for Bearer token')]
|
|
11
|
-
username: Annotated[str, Field(examples=["johndoe"], description='The username authenticated with from the form data')]
|
|
12
|
-
is_admin: Annotated[bool, Field(examples=[False], description="A boolean for whether the user is an admin")]
|
|
13
|
-
expiry_time: Annotated[datetime, Field(examples=["2023-08-01T12:00:00.000000Z"], description="The expiry time of the access token in yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z' format")]
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
## Parameters Response Models
|
|
17
|
-
|
|
18
|
-
class ParameterOptionModel(BaseModel):
|
|
19
|
-
id: Annotated[str, Field(examples=["my_option_id"], description="The unique identifier for the option")]
|
|
20
|
-
label: Annotated[str, Field(examples=["My Option"], description="The human-friendly display name for the option")]
|
|
21
|
-
|
|
22
|
-
class ParameterModelBase(BaseModel):
|
|
23
|
-
widget_type: Annotated[str, Field(examples=["disabled"], description="The parameter type")]
|
|
24
|
-
name: Annotated[str, Field(examples=["my_unique_param_name"], description="The name of the parameter. Use this as the key when providing the API request parameters")]
|
|
25
|
-
label: Annotated[str, Field(examples=["My Parameter"], description="The human-friendly display name for the parameter")]
|
|
26
|
-
description: Annotated[str, Field(examples=[""], description="The description of the parameter")]
|
|
27
|
-
|
|
28
|
-
class NoneParameterModel(ParameterModelBase):
|
|
29
|
-
pass
|
|
30
|
-
|
|
31
|
-
class SelectParameterModel(ParameterModelBase):
|
|
32
|
-
options: Annotated[list[ParameterOptionModel], Field(description="The list of dropdown options as JSON objects containing 'id' and 'label' fields")]
|
|
33
|
-
trigger_refresh: Annotated[bool, Field(description="A boolean that's set to true for parent parameters that require a new parameters API call when the selection changes")]
|
|
34
|
-
|
|
35
|
-
class SingleSelectParameterModel(SelectParameterModel):
|
|
36
|
-
widget_type: Annotated[str, Field(examples=["single_select"], description="The parameter type (set to 'single_select' for this model)")]
|
|
37
|
-
selected_id: Annotated[str | None, Field(examples=["my_option_id"], description="The ID of the selected / default option")]
|
|
38
|
-
|
|
39
|
-
class MultiSelectParameterModel(SelectParameterModel):
|
|
40
|
-
widget_type: Annotated[str, Field(examples=["multi_select"], description="The parameter type (set to 'multi_select' for this model)")]
|
|
41
|
-
show_select_all: Annotated[bool, Field(description="A boolean for whether there should be a toggle to select all options")]
|
|
42
|
-
order_matters: Annotated[bool, Field(description="A boolean for whether the ordering of the input selections would affect the result of the dataset")]
|
|
43
|
-
selected_ids: Annotated[list[str], Field(examples=[["my_option_id"]], description="A list of ids of the selected / default options")]
|
|
44
|
-
|
|
45
|
-
class _DateTypeParameterModel(ParameterModelBase):
|
|
46
|
-
min_date: Annotated[date | None, Field(examples=["2023-01-01"], description='A string in "yyyy-MM-dd" format for the minimum date')]
|
|
47
|
-
max_date: Annotated[date | None, Field(examples=["2023-12-31"], description='A string in "yyyy-MM-dd" format for the maximum date')]
|
|
48
|
-
|
|
49
|
-
class DateParameterModel(_DateTypeParameterModel):
|
|
50
|
-
widget_type: Annotated[str, Field(examples=["date"], description="The parameter type (set to 'date' for this model)")]
|
|
51
|
-
selected_date: Annotated[date, Field(examples=["2023-01-01"], description='A string in "yyyy-MM-dd" format for the selected / default date')]
|
|
52
|
-
|
|
53
|
-
class DateRangeParameterModel(_DateTypeParameterModel):
|
|
54
|
-
widget_type: Annotated[str, Field(examples=["date_range"], description="The parameter type (set to 'date_range' for this model)")]
|
|
55
|
-
selected_start_date: Annotated[date, Field(examples=["2023-01-01"], description='A string in "yyyy-MM-dd" format for the selected / default start date')]
|
|
56
|
-
selected_end_date: Annotated[date, Field(examples=["2023-12-31"], description='A string in "yyyy-MM-dd" format for the selected / default end date')]
|
|
57
|
-
|
|
58
|
-
class _NumericParameterModel(ParameterModelBase):
|
|
59
|
-
min_value: Annotated[float, Field(examples=[0], description="A number for the lower bound of the selectable number")]
|
|
60
|
-
max_value: Annotated[float, Field(examples=[10], description="A number for the upper bound of the selectable number")]
|
|
61
|
-
increment: Annotated[float, Field(examples=[1], description="A number for the selectable increments between the lower bound and upper bound")]
|
|
62
|
-
|
|
63
|
-
class NumberParameterModel(_NumericParameterModel):
|
|
64
|
-
widget_type: Annotated[str, Field(examples=["number"], description="The parameter type (set to 'number' for this model)")]
|
|
65
|
-
selected_value: Annotated[float, Field(examples=[2], description="A number for the selected / default number")]
|
|
66
|
-
|
|
67
|
-
class NumberRangeParameterModel(_NumericParameterModel):
|
|
68
|
-
widget_type: Annotated[str, Field(examples=["number_range"], description="The parameter type (set to 'number_range' for this model)")]
|
|
69
|
-
selected_lower_value: Annotated[float, Field(examples=[2], description="A number for the selected / default lower number")]
|
|
70
|
-
selected_upper_value: Annotated[float, Field(examples=[8], description="A number for the selected / default upper number")]
|
|
71
|
-
|
|
72
|
-
class TextParameterModel(ParameterModelBase):
|
|
73
|
-
widget_type: Annotated[str, Field(examples=["text"], description="The parameter type (set to 'text' for this model)")]
|
|
74
|
-
entered_text: Annotated[str, Field(examples=["sushi"], description="A string for the default entered text")]
|
|
75
|
-
input_type: Annotated[str, Field(
|
|
76
|
-
examples=["text", "textarea", "number", "date", "datetime-local", "month", "time", "color", "password"],
|
|
77
|
-
description='A string for the input type (one of "text", "textarea", "number", "date", "datetime-local", "month", "time", "color", or "password")'
|
|
78
|
-
)]
|
|
79
|
-
|
|
80
|
-
ParametersListType = list[
|
|
81
|
-
NoneParameterModel | SingleSelectParameterModel | MultiSelectParameterModel | DateParameterModel | DateRangeParameterModel |
|
|
82
|
-
NumberParameterModel | NumberRangeParameterModel | TextParameterModel
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
class ParametersModel(BaseModel):
|
|
86
|
-
parameters: Annotated[ParametersListType, Field(description="The list of parameters for the dataset / dashboard")]
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
## Datasets / Dashboards Catalog Response Models
|
|
90
|
-
|
|
91
|
-
name_description = "The name of the dataset / dashboard (usually in snake case)"
|
|
92
|
-
label_description = "The human-friendly display name for the dataset / dashboard"
|
|
93
|
-
description_description = "The description of the dataset / dashboard"
|
|
94
|
-
parameters_path_description = "The API path to the parameters for the dataset / dashboard"
|
|
95
|
-
metadata_path_description = "The API path to the metadata (i.e., description and schema) for the dataset"
|
|
96
|
-
result_path_description = "The API path to the results for the dataset / dashboard"
|
|
97
|
-
|
|
98
|
-
class ColumnModel(BaseModel):
|
|
99
|
-
name: Annotated[str, Field(examples=["mycol"], description="Name of column")]
|
|
100
|
-
type: Annotated[str, Field(examples=["string", "integer", "boolean", "datetime"], description='Column type (such as "string", "integer", "boolean", "datetime", etc.)')]
|
|
101
|
-
description: Annotated[str, Field(examples=["My column description"], description="The description of the column")]
|
|
102
|
-
category: Annotated[str, Field(examples=["dimension", "measure", "misc"], description="The category of the column (such as 'dimension', 'measure', or 'misc')")]
|
|
103
|
-
|
|
104
|
-
class ColumnWithConditionModel(ColumnModel):
|
|
105
|
-
condition: Annotated[str | None, Field(None, examples=["My condition"], description="The condition of when the column is included (such as based on a parameter selection)")]
|
|
106
|
-
|
|
107
|
-
class SchemaModel(BaseModel):
|
|
108
|
-
fields: Annotated[list[ColumnModel], Field(description="A list of JSON objects containing the 'name' and 'type' for each of the columns in the result")]
|
|
109
|
-
|
|
110
|
-
class SchemaWithConditionModel(BaseModel):
|
|
111
|
-
fields: Annotated[list[ColumnWithConditionModel], Field(description="A list of JSON objects containing the 'name' and 'type' for each of the columns in the result")]
|
|
112
|
-
|
|
113
|
-
class DatasetItemModel(BaseModel):
|
|
114
|
-
name: Annotated[str, Field(examples=["mydataset"], description=name_description)]
|
|
115
|
-
label: Annotated[str, Field(examples=["My Dataset"], description=label_description)]
|
|
116
|
-
description: Annotated[str, Field(examples=[""], description=description_description)]
|
|
117
|
-
parameters: Annotated[list[str], Field(examples=["myparam1", "myparam2"], description="The list of parameter names used by the dataset")]
|
|
118
|
-
data_schema: Annotated[SchemaWithConditionModel, Field(alias="schema", description="JSON object describing the schema of the dataset")]
|
|
119
|
-
parameters_path: Annotated[str, Field(examples=["/squirrels-v0/myproject/v1/dataset/mydataset/parameters"], description=parameters_path_description)]
|
|
120
|
-
result_path: Annotated[str, Field(examples=["/squirrels-v0/myproject/v1/dataset/mydataset"], description=result_path_description)]
|
|
121
|
-
|
|
122
|
-
class DashboardItemModel(ParametersModel):
|
|
123
|
-
name: Annotated[str, Field(examples=["mydashboard"], description=name_description)]
|
|
124
|
-
label: Annotated[str, Field(examples=["My Dashboard"], description=label_description)]
|
|
125
|
-
description: Annotated[str, Field(examples=[""], description=description_description)]
|
|
126
|
-
parameters: Annotated[list[str], Field(examples=["myparam1", "myparam2"], description="The list of parameter names used by the dashboard")]
|
|
127
|
-
parameters_path: Annotated[str, Field(examples=["/squirrels-v0/myproject/v1/dashboard/mydashboard/parameters"], description=parameters_path_description)]
|
|
128
|
-
result_path: Annotated[str, Field(examples=["/squirrels-v0/myproject/v1/dashboard/mydashboard"], description=result_path_description)]
|
|
129
|
-
result_format: Annotated[str, Field(examples=["png", "html"], description="The format of the dashboard's result API response (one of 'png' or 'html')")]
|
|
130
|
-
|
|
131
|
-
ModelConfigType = mc.ModelConfig | s.Source | mc.SeedConfig | mc.BuildModelConfig | mc.DbviewModelConfig | mc.FederateModelConfig
|
|
132
|
-
|
|
133
|
-
class ConnectionItemModel(BaseModel):
|
|
134
|
-
name: Annotated[str, Field(examples=["myconnection"], description="The name of the connection")]
|
|
135
|
-
label: Annotated[str, Field(examples=["My Connection"], description="The human-friendly display name for the connection")]
|
|
136
|
-
|
|
137
|
-
class DataModelItem(BaseModel):
|
|
138
|
-
name: Annotated[str, Field(examples=["model_name"], description="The name of the model")]
|
|
139
|
-
model_type: Annotated[Literal["source", "dbview", "federate", "seed", "build"], Field(
|
|
140
|
-
examples=["source", "dbview", "federate", "seed", "build"], description="The type of the model"
|
|
141
|
-
)]
|
|
142
|
-
config: Annotated[ModelConfigType, Field(description="The configuration of the model")]
|
|
143
|
-
is_queryable: Annotated[bool, Field(examples=[True], description="Whether the model is queryable")]
|
|
144
|
-
|
|
145
|
-
class LineageNode(BaseModel):
|
|
146
|
-
name: str
|
|
147
|
-
type: Literal["model", "dataset", "dashboard"]
|
|
148
|
-
|
|
149
|
-
class LineageRelation(BaseModel):
|
|
150
|
-
type: Literal["buildtime", "runtime"]
|
|
151
|
-
source: LineageNode
|
|
152
|
-
target: LineageNode
|
|
153
|
-
|
|
154
|
-
class CatalogModel(BaseModel):
|
|
155
|
-
parameters: Annotated[ParametersListType, Field(description="The list of all parameters in the project")]
|
|
156
|
-
datasets: Annotated[list[DatasetItemModel], Field(description="The list of accessible datasets")]
|
|
157
|
-
dashboards: Annotated[list[DashboardItemModel], Field(description="The list of accessible dashboards")]
|
|
158
|
-
connections: Annotated[list[ConnectionItemModel], Field(description="The list of connections in the project (only provided for admin users)")]
|
|
159
|
-
models: Annotated[list[DataModelItem], Field(description="The list of data models in the project (only provided for admin users)")]
|
|
160
|
-
lineage: Annotated[list[LineageRelation], Field(description="The lineage information between data assets (only provided for admin users)")]
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
## Dataset Results Response Models
|
|
164
|
-
|
|
165
|
-
class DataDetailsModel(BaseModel):
|
|
166
|
-
num_rows: Annotated[int, Field(examples=[2], description="The number of rows in the data field")]
|
|
167
|
-
orientation: Annotated[Literal["records", "rows", "columns"], Field(examples=["records", "rows", "columns"], description="The orientation of the data field")]
|
|
168
|
-
|
|
169
|
-
class DatasetResultModel(BaseModel):
|
|
170
|
-
data_schema: Annotated[SchemaModel, Field(alias="schema", description="JSON object describing the schema of the dataset")]
|
|
171
|
-
total_num_rows: Annotated[int, Field(examples=[2], description="The total number of rows for the dataset")]
|
|
172
|
-
data_details: Annotated[DataDetailsModel, Field(description="A JSON object containing the details of the data field")]
|
|
173
|
-
data: Annotated[list[dict] | list[list] | dict[str, list], Field(
|
|
174
|
-
examples=[[{"mycol": "col_value1"}, {"mycol": "col_value2"}], [["col_value1"], ["col_value2"]], {"mycol": ["col_value1", "col_value2"]}],
|
|
175
|
-
description="A list of JSON objects where each object is a row of the tabular results. The keys and values of the object are column names (described in fields) and values of the row."
|
|
176
|
-
)]
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
## Project Metadata Response Models
|
|
180
|
-
|
|
181
|
-
class ProjectVersionModel(BaseModel):
|
|
182
|
-
major_version: Annotated[int, Field(examples=[1])]
|
|
183
|
-
data_catalog_path: Annotated[str, Field(examples=["/squirrels-v0/project/myproject/v1/data-catalog"])]
|
|
184
|
-
|
|
185
|
-
class ProjectModel(BaseModel):
|
|
186
|
-
name: Annotated[str, Field(examples=["myproject"])]
|
|
187
|
-
version: Annotated[str, Field(examples=["v1"])]
|
|
188
|
-
label: Annotated[str, Field(examples=["My Project"])]
|
|
189
|
-
description: Annotated[str, Field(examples=["My project description"])]
|
|
190
|
-
squirrels_version: Annotated[str, Field(examples=["0.1.0"])]
|
squirrels/_dashboard_types.py
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import matplotlib.figure as figure, io, abc, typing
|
|
2
|
-
|
|
3
|
-
from . import _constants as c
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class Dashboard(metaclass=abc.ABCMeta):
|
|
7
|
-
"""
|
|
8
|
-
Abstract parent class for all Dashboard classes.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
@property
|
|
12
|
-
@abc.abstractmethod
|
|
13
|
-
def _content(self) -> bytes | str:
|
|
14
|
-
pass
|
|
15
|
-
|
|
16
|
-
@property
|
|
17
|
-
@abc.abstractmethod
|
|
18
|
-
def _format(self) -> str:
|
|
19
|
-
pass
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class PngDashboard(Dashboard):
|
|
23
|
-
"""
|
|
24
|
-
Instantiate a Dashboard in PNG format from a matplotlib figure or bytes
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(self, content: figure.Figure | io.BytesIO | bytes) -> None:
|
|
28
|
-
"""
|
|
29
|
-
Constructor for PngDashboard
|
|
30
|
-
|
|
31
|
-
Arguments:
|
|
32
|
-
content: The content of the dashboard as a matplotlib.figure.Figure or bytes
|
|
33
|
-
"""
|
|
34
|
-
if isinstance(content, figure.Figure):
|
|
35
|
-
buffer = io.BytesIO()
|
|
36
|
-
content.savefig(buffer, format=c.PNG)
|
|
37
|
-
content = buffer.getvalue()
|
|
38
|
-
|
|
39
|
-
if isinstance(content, io.BytesIO):
|
|
40
|
-
content = content.getvalue()
|
|
41
|
-
|
|
42
|
-
self.__content = content
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def _content(self) -> bytes:
|
|
46
|
-
return self.__content
|
|
47
|
-
|
|
48
|
-
@property
|
|
49
|
-
def _format(self) -> typing.Literal['png']:
|
|
50
|
-
return c.PNG
|
|
51
|
-
|
|
52
|
-
def _repr_png_(self):
|
|
53
|
-
return self._content
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class HtmlDashboard(Dashboard):
|
|
57
|
-
"""
|
|
58
|
-
Instantiate a Dashboard from an HTML string
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
def __init__(self, content: io.StringIO | str) -> None:
|
|
62
|
-
"""
|
|
63
|
-
Constructor for HtmlDashboard
|
|
64
|
-
|
|
65
|
-
Arguments:
|
|
66
|
-
content: The content of the dashboard as HTML string
|
|
67
|
-
"""
|
|
68
|
-
if isinstance(content, io.StringIO):
|
|
69
|
-
content = content.getvalue()
|
|
70
|
-
|
|
71
|
-
self.__content = content
|
|
72
|
-
|
|
73
|
-
@property
|
|
74
|
-
def _content(self) -> str:
|
|
75
|
-
return self.__content
|
|
76
|
-
|
|
77
|
-
@property
|
|
78
|
-
def _format(self) -> typing.Literal['html']:
|
|
79
|
-
return c.HTML
|
|
80
|
-
|
|
81
|
-
def _repr_html_(self):
|
|
82
|
-
return self._content
|
squirrels/_dashboards_io.py
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
from typing import Type, TypeVar, Callable, Coroutine, Any
|
|
2
|
-
from enum import Enum
|
|
3
|
-
from dataclasses import dataclass
|
|
4
|
-
from pydantic import BaseModel, Field
|
|
5
|
-
import os, time
|
|
6
|
-
|
|
7
|
-
from ._arguments._run_time_args import DashboardArgs
|
|
8
|
-
from ._py_module import PyModule
|
|
9
|
-
from ._manifest import AnalyticsOutputConfig
|
|
10
|
-
from ._exceptions import InvalidInputError, ConfigurationError, FileExecutionError
|
|
11
|
-
from . import _constants as c, _dashboard_types as d, _utils as u
|
|
12
|
-
|
|
13
|
-
T = TypeVar('T', bound=d.Dashboard)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
class DashboardFormat(Enum):
|
|
17
|
-
PNG = "png"
|
|
18
|
-
HTML = "html"
|
|
19
|
-
|
|
20
|
-
class DashboardDependencies(BaseModel):
|
|
21
|
-
name: str
|
|
22
|
-
dataset: str
|
|
23
|
-
fixed_parameters: list[dict[str, str]] = Field(default_factory=list)
|
|
24
|
-
|
|
25
|
-
class DashboardConfig(AnalyticsOutputConfig):
|
|
26
|
-
format: DashboardFormat = Field(default=DashboardFormat.PNG)
|
|
27
|
-
depends_on: list[DashboardDependencies] = Field(default_factory=list)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclass
|
|
31
|
-
class DashboardDefinition:
|
|
32
|
-
dashboard_name: str
|
|
33
|
-
filepath: str
|
|
34
|
-
config: DashboardConfig
|
|
35
|
-
|
|
36
|
-
@property
|
|
37
|
-
def dashboard_func(self) -> Callable[[DashboardArgs], Coroutine[Any, Any, d.Dashboard]]:
|
|
38
|
-
if not hasattr(self, '_dashboard_func'):
|
|
39
|
-
module = PyModule(self.filepath)
|
|
40
|
-
self._dashboard_func = module.get_func_or_class(c.MAIN_FUNC)
|
|
41
|
-
return self._dashboard_func
|
|
42
|
-
|
|
43
|
-
def get_dashboard_format(self) -> str:
|
|
44
|
-
return self.config.format.value
|
|
45
|
-
|
|
46
|
-
async def get_dashboard(self, args: DashboardArgs, *, dashboard_type: Type[T] = d.Dashboard) -> T:
|
|
47
|
-
try:
|
|
48
|
-
dashboard = await self.dashboard_func(args)
|
|
49
|
-
assert isinstance(dashboard, dashboard_type), f"Function does not return expected Dashboard type: {dashboard_type}"
|
|
50
|
-
except (InvalidInputError, ConfigurationError, FileExecutionError) as e:
|
|
51
|
-
raise e
|
|
52
|
-
except Exception as e:
|
|
53
|
-
raise FileExecutionError(f'Failed to run "{c.MAIN_FUNC}" function for dashboard "{self.dashboard_name}"', e) from e
|
|
54
|
-
|
|
55
|
-
return dashboard
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class DashboardsIO:
|
|
59
|
-
|
|
60
|
-
@classmethod
|
|
61
|
-
def load_files(cls, logger: u.Logger, base_path: str) -> dict[str, DashboardDefinition]:
|
|
62
|
-
start = time.time()
|
|
63
|
-
|
|
64
|
-
dashboards_by_name = {}
|
|
65
|
-
for dp, _, filenames in os.walk(u.Path(base_path, c.DASHBOARDS_FOLDER)):
|
|
66
|
-
for file in filenames:
|
|
67
|
-
filepath = os.path.join(dp, file)
|
|
68
|
-
file_stem, extension = os.path.splitext(file)
|
|
69
|
-
if not extension == '.py':
|
|
70
|
-
continue
|
|
71
|
-
|
|
72
|
-
# Check for corresponding .yml file
|
|
73
|
-
yml_path = os.path.join(dp, file_stem + '.yml')
|
|
74
|
-
config_dict = u.load_yaml_config(yml_path) if os.path.exists(yml_path) else {}
|
|
75
|
-
config = DashboardConfig(name=file_stem, **config_dict)
|
|
76
|
-
dashboards_by_name[file_stem] = DashboardDefinition(file_stem, filepath, config)
|
|
77
|
-
|
|
78
|
-
logger.log_activity_time("loading files for dashboards", start)
|
|
79
|
-
return dashboards_by_name
|