openbb-platform-api 1.3.5__tar.gz → 2.0.0__tar.gz
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.
- openbb_platform_api-2.0.0/.gitignore +65 -0
- openbb_platform_api-1.3.5/README.md → openbb_platform_api-2.0.0/PKG-INFO +158 -259
- openbb_platform_api-1.3.5/PKG-INFO → openbb_platform_api-2.0.0/README.md +147 -286
- openbb_platform_api-2.0.0/openbb_platform_api/app/__init__.py +25 -0
- openbb_platform_api-1.3.5/openbb_platform_api/main.py → openbb_platform_api-2.0.0/openbb_platform_api/app/app.py +150 -54
- openbb_platform_api-2.0.0/openbb_platform_api/app/args.py +456 -0
- openbb_platform_api-2.0.0/openbb_platform_api/app/bootstrap.py +229 -0
- openbb_platform_api-2.0.0/openbb_platform_api/app/config.py +350 -0
- openbb_platform_api-2.0.0/openbb_platform_api/app/middleware.py +185 -0
- openbb_platform_api-2.0.0/openbb_platform_api/app/spec.py +906 -0
- {openbb_platform_api-1.3.5 → openbb_platform_api-2.0.0}/openbb_platform_api/assets/default_apps.json +1 -172
- openbb_platform_api-2.0.0/openbb_platform_api/main.py +95 -0
- openbb_platform_api-2.0.0/openbb_platform_api/models/__init__.py +20 -0
- openbb_platform_api-1.3.5/openbb_platform_api/query_models.py → openbb_platform_api-2.0.0/openbb_platform_api/models/query.py +9 -3
- openbb_platform_api-1.3.5/openbb_platform_api/response_models.py → openbb_platform_api-2.0.0/openbb_platform_api/models/response.py +49 -11
- openbb_platform_api-2.0.0/openbb_platform_api/query_models.py +11 -0
- openbb_platform_api-2.0.0/openbb_platform_api/response_models.py +20 -0
- openbb_platform_api-2.0.0/openbb_platform_api/service/__init__.py +31 -0
- openbb_platform_api-2.0.0/openbb_platform_api/service/agents_service.py +69 -0
- openbb_platform_api-2.0.0/openbb_platform_api/service/apps_service.py +59 -0
- openbb_platform_api-2.0.0/openbb_platform_api/service/widgets_service.py +214 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/__init__.py +14 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/api.py +83 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/merge_agents.py +14 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/merge_apps.py +14 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/merge_widgets.py +97 -0
- openbb_platform_api-2.0.0/openbb_platform_api/utils/network.py +53 -0
- {openbb_platform_api-1.3.5 → openbb_platform_api-2.0.0}/openbb_platform_api/utils/openapi.py +239 -43
- {openbb_platform_api-1.3.5 → openbb_platform_api-2.0.0}/openbb_platform_api/utils/widgets.py +61 -21
- openbb_platform_api-2.0.0/pyproject.toml +123 -0
- openbb_platform_api-1.3.5/openbb_platform_api/utils/__init__.py +0 -1
- openbb_platform_api-1.3.5/openbb_platform_api/utils/api.py +0 -420
- openbb_platform_api-1.3.5/openbb_platform_api/utils/merge_agents.py +0 -55
- openbb_platform_api-1.3.5/openbb_platform_api/utils/merge_apps.py +0 -46
- openbb_platform_api-1.3.5/openbb_platform_api/utils/merge_widgets.py +0 -129
- openbb_platform_api-1.3.5/pyproject.toml +0 -23
- {openbb_platform_api-1.3.5 → openbb_platform_api-2.0.0}/openbb_platform_api/__init__.py +0 -0
- {openbb_platform_api-1.3.5 → openbb_platform_api-2.0.0}/openbb_platform_api/assets/landing_page.html +0 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# General
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.pyc
|
|
4
|
+
.DS_Store
|
|
5
|
+
*.env
|
|
6
|
+
.venv
|
|
7
|
+
venv*/
|
|
8
|
+
venv
|
|
9
|
+
.vscode
|
|
10
|
+
*.ipynb
|
|
11
|
+
env/
|
|
12
|
+
venv/
|
|
13
|
+
!notebooks/jupyter/.gitkeep
|
|
14
|
+
.python-version
|
|
15
|
+
.mypy_cache
|
|
16
|
+
.ruff_cache
|
|
17
|
+
.pytest_cache
|
|
18
|
+
iframe_figures/
|
|
19
|
+
exports/*
|
|
20
|
+
.idea
|
|
21
|
+
.coverage
|
|
22
|
+
.scannerwork
|
|
23
|
+
htmlcov
|
|
24
|
+
**/.ipynb_checkpoints
|
|
25
|
+
*.swp
|
|
26
|
+
*.http
|
|
27
|
+
.coverage.*
|
|
28
|
+
*_tests.csv
|
|
29
|
+
*_sdk_audit.csv
|
|
30
|
+
!build/docker/compose.env
|
|
31
|
+
.dccache
|
|
32
|
+
*rome.json
|
|
33
|
+
**/node_modules/*
|
|
34
|
+
.cursorignore
|
|
35
|
+
darts_logs/
|
|
36
|
+
custom_imports/*.csv
|
|
37
|
+
custom_imports/*/*.csv
|
|
38
|
+
cache/
|
|
39
|
+
lightning_logs/
|
|
40
|
+
*/mocked_path
|
|
41
|
+
*.pem
|
|
42
|
+
|
|
43
|
+
# CLI
|
|
44
|
+
*.pyo
|
|
45
|
+
**/dist/*
|
|
46
|
+
build/cli
|
|
47
|
+
build/nsis/app
|
|
48
|
+
DMG/*
|
|
49
|
+
*.dmg
|
|
50
|
+
*.sh
|
|
51
|
+
cli/openbb_cli/assets/styles/user/*
|
|
52
|
+
|
|
53
|
+
# Platform
|
|
54
|
+
openbb_platform/core/openbb/package/*
|
|
55
|
+
openbb_platform/core/openbb/.build.lock
|
|
56
|
+
**/assets/*.json.xz
|
|
57
|
+
|
|
58
|
+
# Dev Container env
|
|
59
|
+
obb/*
|
|
60
|
+
|
|
61
|
+
# OpenBB Distribution
|
|
62
|
+
!build/conda/installer/*.sh
|
|
63
|
+
*.pkg
|
|
64
|
+
*.exe
|
|
65
|
+
build/conda/tmp
|
|
@@ -1,53 +1,119 @@
|
|
|
1
|
-
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: openbb-platform-api
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: OpenBB Platform API: launcher and widgets builder for the Open Data Platform REST API and OpenBB Workspace custom-backend connector.
|
|
5
|
+
Project-URL: Homepage, https://openbb.co
|
|
6
|
+
Project-URL: Repository, https://github.com/OpenBB-finance/OpenBB
|
|
7
|
+
Project-URL: Documentation, https://docs.openbb.co/odp/python/extensions/interface/openbb-api
|
|
8
|
+
Author-email: OpenBB Team <hello@openbb.co>
|
|
9
|
+
License: Apache-2.0
|
|
10
|
+
Requires-Python: <4,>=3.10
|
|
11
|
+
Requires-Dist: deepdiff>=8.6.2
|
|
12
|
+
Requires-Dist: openbb-core>=2.0.0
|
|
13
|
+
Requires-Dist: tomli>=2.0; python_version < '3.11'
|
|
14
|
+
Description-Content-Type: text/markdown
|
|
2
15
|
|
|
3
|
-
|
|
16
|
+
# OpenBB Platform API
|
|
4
17
|
|
|
5
|
-
|
|
18
|
+
Launcher and widgets builder for the OpenBB Workspace [custom backend](https://docs.openbb.co/workspace/data-integration). Wraps any FastAPI application with the metadata, exception handling, and `widgets.json` generation that OpenBB Workspace expects — so a regular FastAPI app becomes a Workspace data source with no glue code.
|
|
6
19
|
|
|
7
|
-
|
|
8
|
-
for creating new backends that are not part of the OpenBB GitHub [repository](https://github.com/OpenBB-finance/OpenBB/).
|
|
20
|
+
> **Full documentation:** [docs.openbb.co/odp/python/extensions/interface/openbb-api](https://docs.openbb.co/odp/python/extensions/interface/openbb-api)
|
|
9
21
|
|
|
10
|
-
|
|
22
|
+
## Install
|
|
11
23
|
|
|
12
24
|
```sh
|
|
13
25
|
pip install openbb-platform-api
|
|
14
26
|
```
|
|
15
27
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
See the [keyword arguments](#keyword-arguments) section for parameters and descriptions.
|
|
28
|
+
Python ≥ 3.10. Already included when you install [`openbb`](https://docs.openbb.co/platform/installation).
|
|
19
29
|
|
|
20
30
|
### Launch OpenBB Platform
|
|
21
31
|
|
|
22
32
|
To start the OpenBB Platform API, open a terminal, activate the environment where it is installed, and then enter:
|
|
23
33
|
|
|
24
|
-
```
|
|
34
|
+
```sh
|
|
25
35
|
openbb-api
|
|
26
|
-
```
|
|
27
36
|
|
|
28
|
-
|
|
37
|
+
# Launch your own FastAPI app
|
|
38
|
+
openbb-api --app /path/to/your_app.py
|
|
29
39
|
|
|
30
|
-
|
|
40
|
+
# Factory function?
|
|
41
|
+
openbb-api --app some_file.py:create_app --factory
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
# Launch as a proxy from an openbb-cli .spec file
|
|
44
|
+
openbb-api --spec /path/to/cli.spec
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`widgets.json` is auto-generated from your routes' types, response models, and docstrings. Plotly returns become chart widgets, `BaseModel` returns become tables, scalars become metrics — no manual wiring.
|
|
33
48
|
|
|
34
|
-
|
|
49
|
+
## Spec-driven proxy mode
|
|
50
|
+
|
|
51
|
+
Generate a spec file with `openbb-cli` against any OpenBB Platform deployment, then launch a Workspace-compatible backend that proxies every command to that upstream:
|
|
35
52
|
|
|
36
53
|
```sh
|
|
37
|
-
|
|
54
|
+
# Generate the spec once
|
|
55
|
+
openbb --generate-spec --server https://api.example.com -o cli.spec
|
|
56
|
+
|
|
57
|
+
# Launch the proxy
|
|
58
|
+
openbb-api --spec cli.spec
|
|
38
59
|
```
|
|
39
60
|
|
|
40
|
-
|
|
61
|
+
Each command in the spec becomes a FastAPI route at its `url_path`; the launcher forwards every request to the spec's `base_url` (preserving query, body, and non-hop-by-hop headers). `widgets.json` is generated from the spec's parameter and response-schema metadata via the same builder used for in-process apps.
|
|
41
62
|
|
|
42
|
-
|
|
63
|
+
Useful for shipping a thin frontend container that talks to a managed backend in another cluster, without bundling `openbb-core` or any provider extensions. `--spec` is mutually exclusive with `--app`.
|
|
43
64
|
|
|
44
|
-
|
|
45
|
-
|
|
65
|
+
### `[spec]` config — credentials and base-URL override
|
|
66
|
+
|
|
67
|
+
A `[spec]` table in `openbb.toml` carries the path plus the bits the file alone can't provide — `base_url` overrides for staging/prod, and `headers` injected on every upstream request.
|
|
68
|
+
Header values support the same `$VAR` substitution as `[env]`, so credentials live in environment variables (or `[env]` entries that read from them) and the TOML just maps them onto upstream header names:
|
|
69
|
+
|
|
70
|
+
```toml
|
|
71
|
+
[env]
|
|
72
|
+
OPENBB_UPSTREAM_TOKEN = "$GITHUB_TOKEN" # or any orchestrator-injected secret
|
|
73
|
+
|
|
74
|
+
[spec]
|
|
75
|
+
path = "/etc/openbb/cli.spec"
|
|
76
|
+
base_url = "https://prod.example.com" # optional; overrides spec's recorded value
|
|
77
|
+
|
|
78
|
+
[spec.headers]
|
|
79
|
+
Authorization = "Bearer $OPENBB_UPSTREAM_TOKEN"
|
|
80
|
+
X-Tenant = "production"
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Config-supplied headers OVERRIDE matching incoming-request headers — `[spec.headers]` is the credential-injection point, so a misbehaving client can't leak its own auth value upstream by sending the same header name.
|
|
84
|
+
|
|
85
|
+
## Custom HTTP middleware (`[middleware]`)
|
|
86
|
+
|
|
87
|
+
Attach Starlette-style HTTP middleware functions from a config-supplied entrypoint — useful for auth, request logging, tracing, IP allow-listing, response transformation. Each entry is a `"module:async_callable"` reference resolved through the standard import system:
|
|
88
|
+
|
|
89
|
+
```toml
|
|
90
|
+
[middleware]
|
|
91
|
+
hooks = [
|
|
92
|
+
"my_pkg.middleware:auth_middleware",
|
|
93
|
+
"my_pkg.middleware:request_logger",
|
|
94
|
+
]
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
# my_pkg/middleware.py
|
|
99
|
+
from fastapi.responses import JSONResponse
|
|
100
|
+
|
|
101
|
+
async def auth_middleware(request, call_next):
|
|
102
|
+
if request.headers.get("X-API-Key") != "expected":
|
|
103
|
+
return JSONResponse({"error": "unauthorized"}, status_code=401)
|
|
104
|
+
return await call_next(request)
|
|
105
|
+
|
|
106
|
+
async def request_logger(request, call_next):
|
|
107
|
+
response = await call_next(request)
|
|
108
|
+
print(f"{request.method} {request.url.path} → {response.status_code}")
|
|
109
|
+
return response
|
|
46
110
|
```
|
|
47
111
|
|
|
48
|
-
|
|
112
|
+
List order is **outermost-to-innermost**: the first entry sees the request first on the way in and the response last on the way out. Misconfigured references (missing module, wrong attribute, sync function, wrong arity) raise loudly at startup so deployments fail fast instead of silently passing requests through unauthenticated.
|
|
49
113
|
|
|
50
|
-
|
|
114
|
+
## Single-file launch
|
|
115
|
+
|
|
116
|
+
Everything in this README — app source (`--app` or `--spec`), env injection, host/port, SSL, agents, middleware, credentials — can be set in one `openbb.toml` and launched without any other CLI flags:
|
|
51
117
|
|
|
52
118
|
```sh
|
|
53
119
|
openbb-api --app some_file.py:main --factory
|
|
@@ -59,38 +125,41 @@ The behavior of the script can be configured with the use of arguments and keywo
|
|
|
59
125
|
|
|
60
126
|
Launcher specific arguments:
|
|
61
127
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
128
|
+
```text
|
|
129
|
+
--app Absolute path to the Python file with the target FastAPI instance. Default is the installed OpenBB Platform API.
|
|
130
|
+
--name Name of the FastAPI instance in the app file. Default is 'app'.
|
|
131
|
+
--factory Flag to indicate if the app name is a factory function. Default is 'false'.
|
|
132
|
+
--editable Flag to make widgets.json an editable file that can be modified during runtime. Default is 'false'.
|
|
133
|
+
--build If the file already exists, changes prompt action to overwrite/append/ignore. Only valid when --editable true.
|
|
134
|
+
--no-build Do not build the widgets.json file. Use this flag to load an existing widgets.json file without checking for updates.
|
|
135
|
+
--exclude JSON encoded list of API paths to exclude from widgets.json. Disable entire routes with '*' - e.g. '["/api/v1/*"]'.
|
|
136
|
+
--no-filter Do not filter out widgets in widget_settings.json file.
|
|
137
|
+
--widgets-json Absolute/relative path to use as the widgets.json file. Default is ~/envs/{env}/assets/widgets.json, when --editable is 'true'.
|
|
138
|
+
--apps-json Absolute/relative path to use as the apps.json file. Default is ~/OpenBBUserData/workspace_apps.json.
|
|
139
|
+
--agents-json Absolute/relative path to use as the agents.json file. Including this will add the /agents endpoint to the API.
|
|
140
|
+
```
|
|
74
141
|
|
|
75
142
|
All other arguments will be passed to uvicorn. Here are the most common ones:
|
|
76
143
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
144
|
+
```text
|
|
145
|
+
--host TEXT Host IP address or hostname.
|
|
146
|
+
[default: 127.0.0.1]
|
|
147
|
+
--port INTEGER Port number.
|
|
148
|
+
[default: 6900]
|
|
149
|
+
--ssl_keyfile TEXT SSL key file.
|
|
150
|
+
--ssl_certfile TEXT SSL certificate file.
|
|
151
|
+
--ssl_keyfile_password TEXT SSL keyfile password.
|
|
152
|
+
--ssl_version INTEGER SSL version to use.
|
|
153
|
+
(see stdlib ssl module's)
|
|
154
|
+
[default: 17]
|
|
155
|
+
--ssl_cert_reqs INTEGER Whether client certificate is required.
|
|
156
|
+
(see stdlib ssl module's)
|
|
157
|
+
[default: 0]
|
|
158
|
+
--ssl_ca_certs TEXT CA certificates file.
|
|
159
|
+
--ssl_ciphers TEXT Ciphers to use.
|
|
160
|
+
(see stdlib ssl module's)
|
|
161
|
+
[default: TLSv1]
|
|
162
|
+
```
|
|
94
163
|
|
|
95
164
|
Run `uvicorn --help` to get the full list of arguments.
|
|
96
165
|
|
|
@@ -121,231 +190,69 @@ Contact the system administrator if you are using a work device and require addi
|
|
|
121
190
|
|
|
122
191
|

|
|
123
192
|
|
|
124
|
-
|
|
125
193
|
## Example Application
|
|
126
194
|
|
|
127
195
|
Examples below will assume this code block is at the start of the file.
|
|
128
196
|
|
|
129
197
|
```python
|
|
130
198
|
from fastapi import FastAPI
|
|
199
|
+
from openbb_platform_api.response_models import (
|
|
200
|
+
Data,
|
|
201
|
+
MetricResponseModel,
|
|
202
|
+
OmniWidgetResponseModel,
|
|
203
|
+
PdfResponseModel,
|
|
204
|
+
)
|
|
131
205
|
|
|
132
206
|
app = FastAPI()
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Markdown Widget
|
|
136
|
-
|
|
137
|
-
This script will create a "markdown" widget with the returned text.
|
|
138
207
|
|
|
139
|
-
|
|
208
|
+
# Markdown — return a string
|
|
140
209
|
@app.get("/hello")
|
|
141
210
|
async def hello() -> str:
|
|
142
|
-
"""
|
|
143
|
-
return "Hello,
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
@app.get("/
|
|
152
|
-
async def
|
|
153
|
-
""
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
To create a metric widget, import the custom response model below and define it as a return type.
|
|
162
|
-
|
|
163
|
-
```python
|
|
164
|
-
from openbb_platform_api.response_models import MetricResponseModel
|
|
165
|
-
|
|
166
|
-
@app.get("/hello_metric")
|
|
167
|
-
async def hello_metric() -> MetricResponseModel:
|
|
168
|
-
"""Widget description created by docstring."""
|
|
169
|
-
return MetricResponseModel(label="Good Vibes Score", value=100, delta="1%")
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
This type of widget can be created as an array of MetricResponseModels. Adjust the response to be a `list[MetricRespnoseModel]`
|
|
173
|
-
|
|
174
|
-
### Query Parameters
|
|
175
|
-
|
|
176
|
-
Function arguments will populate as widget parameters.
|
|
177
|
-
|
|
178
|
-
```python
|
|
179
|
-
from typing import Literal, Optional
|
|
180
|
-
|
|
181
|
-
@app.get("/hello")
|
|
182
|
-
async def hello(param1: Optional[str] = None, param2: Literal["Choice 1", "Choice 2"] = None, param3: bool = False) -> str:
|
|
183
|
-
"""Widget Description Generated By Docstring"""
|
|
184
|
-
if not param1 and not param2 and not param3:
|
|
185
|
-
return "Enter a parameter or make a choice!"
|
|
186
|
-
if param3:
|
|
187
|
-
return f"Param3 enabled!"
|
|
188
|
-
if param2:
|
|
189
|
-
return f"You selected: {param2}"
|
|
190
|
-
if param1:
|
|
191
|
-
return f"You entered: {param1}"
|
|
192
|
-
|
|
193
|
-
return "Nothing to return!"
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Easy Date Picker
|
|
197
|
-
|
|
198
|
-
Name the parameter "date", or include "_date" in the name, and type it as a string.
|
|
199
|
-
|
|
200
|
-
Additionally, a parameter type of `datetime.date` will work.
|
|
201
|
-
|
|
202
|
-
```python
|
|
203
|
-
import datetime
|
|
204
|
-
|
|
205
|
-
@app.get("/hello_date")
|
|
206
|
-
async def hello_date(date: str) -> list:
|
|
207
|
-
"""Widget description created by docstring."""
|
|
208
|
-
# Workspace returns the date as YYYY-MM-DD
|
|
209
|
-
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
@app.get("/hello_date_range")
|
|
213
|
-
async def hello_date_range(start: datetime.date, end: datetime.date) -> list:
|
|
214
|
-
"""Widget description created by docstring."""
|
|
215
|
-
# Workspace returns the date as YYYY-MM-DD
|
|
216
|
-
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
This demonstrates how to define any of the basic widget parameter types, in a no-frills way. If you just need something that works, it's an easy starting point.
|
|
220
|
-
|
|
221
|
-
```python
|
|
222
|
-
@app.get("/hello_params")
|
|
223
|
-
async def hello_params(
|
|
224
|
-
required_param: datetime.date,
|
|
225
|
-
param_1: str = "Default",
|
|
226
|
-
param_2: int = 0,
|
|
227
|
-
param_3: float = None,
|
|
228
|
-
param_4: Literal["Choice 1", "Choice 2", "Choice 3"] = "Choice 1",
|
|
229
|
-
param_5: bool = True,
|
|
230
|
-
) -> list:
|
|
231
|
-
"""Widget description created by docstring."""
|
|
232
|
-
# Handle the "choices" parameter inside the function to convert the displayed label to the desired one.
|
|
233
|
-
choices_dict = {"Choice 1": "do_one", "Choice 2": "do_two", "Choice 3": "do_three"}
|
|
234
|
-
choice = choices_dict.get(param_4, None)
|
|
235
|
-
|
|
236
|
-
# Do something with the parameters and return the result of work.
|
|
237
|
-
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Annotated Query Params
|
|
241
|
-
|
|
242
|
-
Adding helpful placeholder text and tooltips to parameters requires annotating them. This will also help code editors and improve the API documentation.
|
|
243
|
-
|
|
244
|
-
Additional settings, compatible with `widgets.json`, are defined in the `json_schema_extra` dictionary, under a key, `x-widget_config`
|
|
245
|
-
|
|
246
|
-
```python
|
|
247
|
-
from typing import Annotated
|
|
248
|
-
from fastapi import Query
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
The pattern for annotating a query parameter is:
|
|
252
|
-
|
|
253
|
-
```python
|
|
254
|
-
my_param: Annotated[str, Query(title="My Title", description="My custom hovertext with detailed information")] = None
|
|
255
|
-
```
|
|
256
|
-
|
|
257
|
-
```python
|
|
258
|
-
@app.get("/hello_annotated_params")
|
|
259
|
-
async def hello_annotated_params(
|
|
260
|
-
required_param: Annotated[
|
|
261
|
-
datetime.date, Query(description="The date is required.", title="Required Date")
|
|
262
|
-
],
|
|
263
|
-
not_required_param: Annotated[
|
|
264
|
-
Literal["Choice 1", "Choice 2", "Choice 3"],
|
|
265
|
-
Query(
|
|
266
|
-
description="Choose from a list of possible choices. The default is, 'Choice 1'",
|
|
267
|
-
title="Selector",
|
|
268
|
-
json_schema_extra={"x-widget_config": {"multiSelect": True}} # This lets you select multiple items from dropdown choices.
|
|
269
|
-
),
|
|
270
|
-
] = "Choice 1",
|
|
271
|
-
) -> list:
|
|
272
|
-
"""Widget description created by docstring."""
|
|
273
|
-
|
|
274
|
-
# Do something with the parameters and return the result of work.
|
|
275
|
-
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
|
|
211
|
+
"""Tooltip from the docstring."""
|
|
212
|
+
return "Hello, OpenBB!"
|
|
213
|
+
|
|
214
|
+
# Table — return a list of records or a typed Data subclass
|
|
215
|
+
@app.get("/rows")
|
|
216
|
+
async def rows() -> list[dict]:
|
|
217
|
+
return [{"symbol": "AAPL", "price": 150.0}]
|
|
218
|
+
|
|
219
|
+
# Metric — single label/value/delta
|
|
220
|
+
@app.get("/score")
|
|
221
|
+
async def score() -> MetricResponseModel:
|
|
222
|
+
return MetricResponseModel(label="Score", value=100, delta="1%")
|
|
223
|
+
|
|
224
|
+
# Chart — return a Plotly figure JSON
|
|
225
|
+
@app.get("/chart", openapi_extra={"widget_config": {"type": "chart"}})
|
|
226
|
+
async def chart() -> dict:
|
|
227
|
+
from plotly.graph_objs import Bar, Figure
|
|
228
|
+
return Figure(data=[Bar(x=["A"], y=[1])]).to_plotly_json()
|
|
276
229
|
```
|
|
277
230
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
The procedure for annotating the output is similar to the query parameters, and involves defining a response model.
|
|
281
|
-
|
|
282
|
-
A response model is a Data model of Fields. Create one by defining a new class that inherits from "Data", and then define each column as a "Field".
|
|
231
|
+
Annotated `Data` models drive auto-generated table column definitions:
|
|
283
232
|
|
|
284
233
|
```python
|
|
234
|
+
from datetime import date
|
|
285
235
|
from openbb_platform_api.response_models import Data
|
|
286
236
|
from pydantic import Field
|
|
287
|
-
```
|
|
288
237
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
# Add fields to the model.
|
|
296
|
-
column_1: datetime.date = Field(
|
|
297
|
-
description="The date column is a mandatory field.",
|
|
298
|
-
title="Some Date",
|
|
299
|
-
)
|
|
300
|
-
column_2: Optional[str] = Field(
|
|
301
|
-
default=None,
|
|
302
|
-
description="This is an optional string column.",
|
|
303
|
-
title="Some String",
|
|
304
|
-
)
|
|
305
|
-
column_3: int = Field(
|
|
306
|
-
default=-1,
|
|
307
|
-
description="This is an integer column.",
|
|
308
|
-
title="Some Integer",
|
|
309
|
-
)
|
|
310
|
-
column_4: float = Field(
|
|
311
|
-
default=10.25,
|
|
312
|
-
description="This is a float column.",
|
|
313
|
-
title="Some Float",
|
|
314
|
-
)
|
|
315
|
-
column_5: float = Field(
|
|
316
|
-
default=10.25,
|
|
317
|
-
description="This is a percent column.",
|
|
318
|
-
title="Some Percent",
|
|
319
|
-
json_schema_extra={"x-widget_config": {"formatterFn": "percent"}},
|
|
320
|
-
)
|
|
321
|
-
column_6: float = Field(
|
|
322
|
-
default=0.1025,
|
|
323
|
-
description="This is a normalized percent value adjusted for presentation.",
|
|
324
|
-
title="Some Normalized Percent",
|
|
325
|
-
json_schema_extra={
|
|
326
|
-
"x-widget_config": {
|
|
327
|
-
"formatterFn": "normalizedPercent",
|
|
328
|
-
"renderFn": "greenRed",
|
|
329
|
-
}
|
|
330
|
-
},
|
|
238
|
+
class MyRow(Data):
|
|
239
|
+
when: date = Field(title="Date", description="Trading date")
|
|
240
|
+
pct: float = Field(
|
|
241
|
+
title="Change",
|
|
242
|
+
json_schema_extra={"x-widget_config": {"formatterFn": "percent", "renderFn": "greenRed"}},
|
|
331
243
|
)
|
|
332
244
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
"""Widget description created by docstring."""
|
|
337
|
-
# Do something with the parameters and return the result of work.
|
|
338
|
-
return [MyData(column_1=datetime.date.today(), column_2="Hello!")]
|
|
245
|
+
@app.get("/data")
|
|
246
|
+
async def data() -> list[MyRow]:
|
|
247
|
+
return [MyRow(when=date.today(), pct=0.0125)]
|
|
339
248
|
```
|
|
340
249
|
|
|
341
|
-
|
|
342
250
|
### PDF Widget
|
|
343
251
|
|
|
344
252
|
To create a PDF widget, import the custom response model below and define it as a return type.
|
|
345
253
|
|
|
346
254
|
The model handles conversion of the document, from a bytes object, to a base64 encoded string.
|
|
347
255
|
|
|
348
|
-
|
|
349
256
|
```python
|
|
350
257
|
from openbb_platform_api.response_models import PdfResponseModel
|
|
351
258
|
|
|
@@ -402,7 +309,6 @@ async def open_pdf(
|
|
|
402
309
|
|
|
403
310
|
To define a chart widget, update the widget "type" and return the content from the `Figure.to_plotly_json()` method.
|
|
404
311
|
|
|
405
|
-
|
|
406
312
|
```python
|
|
407
313
|
@app.get(
|
|
408
314
|
"/hello_chart",
|
|
@@ -437,7 +343,6 @@ The entry in `widgets.json` will be automatically created if the conditions belo
|
|
|
437
343
|
- POST method takes 1 positional argument, a sub-class of Pydantic BaseModel.
|
|
438
344
|
- Create a model, like annotated table fields, defining all inputs to the form.
|
|
439
345
|
|
|
440
|
-
|
|
441
346
|
#### Example
|
|
442
347
|
|
|
443
348
|
The code below creates a widget with a form as the input, and an output table of all submitted forms, as processed through the `IntakeForm` model.
|
|
@@ -600,7 +505,6 @@ async def create_omni_widget(item: TestOmniWidgetQueryModel):
|
|
|
600
505
|
|
|
601
506
|

|
|
602
507
|
|
|
603
|
-
|
|
604
508
|
## Widget Config
|
|
605
509
|
|
|
606
510
|
Any value from the [`widgets.json`](https://docs.openbb.co/terminal/custom-backend/widgets-json-reference) structure can be passed into the `@app` decorator by including an `openapi_extra` dictionary with the key, `"widget_config"`.
|
|
@@ -662,7 +566,6 @@ If you would like to construct this file manually, create the file and define th
|
|
|
662
566
|
openbb-api --widgets-json /Users/some_user/path/to/widgets.json
|
|
663
567
|
```
|
|
664
568
|
|
|
665
|
-
|
|
666
569
|
### Location of `workspace_apps.json`
|
|
667
570
|
|
|
668
571
|
By default, the location is:
|
|
@@ -675,12 +578,8 @@ This can be changed by adding the path as an argument.
|
|
|
675
578
|
openbb-api --apps-json /Users/some_user/path/to/workspace_apps.json
|
|
676
579
|
```
|
|
677
580
|
|
|
678
|
-
The
|
|
679
|
-
|
|
680
|
-
To export the layout, right-click on the dashboard and select, "Export apps.json".
|
|
681
|
-
|
|
682
|
-
A JSON dictionary will be exported. Insert the contents of the export into "~/OpenBBUserData/workspace_apps.json" by pasting between the JSON list markers, [ ].
|
|
581
|
+
The browser will warn about the untrusted cert — accept once, or add `localhost.crt` to the OS trust store.
|
|
683
582
|
|
|
684
|
-
|
|
583
|
+
## License
|
|
685
584
|
|
|
686
|
-
|
|
585
|
+
Apache-2.0. © OpenBB.
|