[Release] Patch Release openbb-platform-api With New Runtime Flags & Readme (#7045)

* patch release openbb-platform-api with new features and readme

* lint

* add PDF to TO_CAPS_STRINGS

* some duplicated thing

* grammar

* add a url to the intro text

* readme syntax linting

* more grammar
This commit is contained in:
Danglewood
2025-02-26 08:05:43 -08:00
committed by GitHub
parent 628e8893fb
commit 4492e32ffa
8 changed files with 463 additions and 194 deletions

View File

@@ -1,6 +1,6 @@
# OpenBB Platform API Meta Package
# OpenBB Platform API Launcher
This package is responsible for launching and configuring an OpenBB Platform environment, or FastAPI instance, to use as an OpenBB Workspace custom backend.
This package is responsible for launching and configuring an OpenBB Platform environment, or FastAPI instance, to use as an OpenBB Workspace [custom backend](https://docs.openbb.co/terminal/custom-backend).
## Installation
@@ -37,103 +37,20 @@ To run your application as an OpenBB Workspace custom backend, add the path to t
openbb-api --app /Users/some_user/path/to/main.py
```
#### Example Application
#### Arbitrary Instance Name
This script will create a "markdown" widget with the returned text.
Define the FastAPI instance as an arbitrary name with the `--name` argument.
```python
from openbb_platform_api.main import app
@app.get("/hello")
async def hello() -> str:
"""Widget Description Generated By Docstring"""
return "Hello, from OpenBB!"
```sh
openbb-api --app some_file.py --name my_app
```
Function arguments will populate as widget parameters.
#### Factory Flag
```python
from openbb_platform_api.main import app
from typing import Literal, Optional
If the FastAPI instance is served via a factory function, set the `--factory` flag.
@app.get("/hello")
async def hello(param1: Optional[str] = None, param2: Literal["Choice 1", "Choice 2"] = None, param3: bool = False) -> str:
"""Widget Description Generated By Docstring"""
if not param1 and not param2 and not param3:
return "Enter a parameter or make a choice!"
if param3:
return f"Param3 enabled!"
if param2:
return f"You selected: {param2}"
if param1:
return f"You entered: {param1}"
return "Nothing to return!"
```
Create a table widget by returning data shaped as a list of dictionaries (records)
```python
from openbb_platform_api.main import app
@app.get("/hello")
async def hello() -> list:
"""Widget Description Generated By Docstring"""
return [{"Column 1": "Hello", "Column 2": "from OpenBB!"}]
```
#### Widget Config
Any value from the [`widgets.json`](https://docs.openbb.co/terminal/custom-backend/widgets.json) structure can be passed into the `@app` decorator by including an `openapi_extra` dictionary with the key, `"widget_config"`.
```python
from openbb_platform_api.main import app
@app.get("/hello",
openapi_extra={
"widget_config": {
"data": {
"table": {
"columnsDefs": [
{"field": "Column 1", "headerName": "My Column", "headerTooltip": "Tooltip added!", "type": "text"}
]
}
}
}
}
)
async def hello() -> list:
"""Widget Description Generated By Docstring"""
return [{"Column 1": "Hello", "Column 2": "from OpenBB!"}]
```
Configurations for `widgets.json` supplied here will override any of the automatically generated content.
If the key does not exist, it will be created.
#### Auto-Generate ColumnsDefs
To generate ColumnsDefs for each field in the response data, return a list of Pydantic models with each column being assigned to Field.
Inherit the BaseModel from the `openbb-core` package by using the imports below.
Columns, by default, are presented in the order of insertion.
```python
from openbb_platform_api.main import app
from openbb_core.provider.abstract.data import Data # Inherit this instead of pydantic.BaseModel to represent 1 row of data.
from pydantic import Field
class MyData(Data):
"""MyData Response Model."""
column_1: str = Field(title="Column 1", description="Description for Column 1") # 'description' will add the column header tooltip to your widget.
column_2: str = Field(title="Column 2", description="Description for Column 2")
@app.get("/hello")
async def hello() -> list[MyData]:
"""Widget Description Generated By Docstring"""
return [MyData.model_validate({"column_1": "Hello", "column_2": "from OpenBB!"})]
```sh
openbb-api --app some_file.py:main --factory
```
## Keyword Arguments
@@ -143,6 +60,8 @@ The behavior of the script can be configured with the use of arguments and keywo
Launcher specific arguments:
--app Absolute path to the Python file with the target FastAPI instance. Default is the installed OpenBB Platform API.
--name Name of the FastAPI instance in the app file. Default is 'app'.
--factory Flag to indicate if the app name is a factory function. Default is 'false'.
--editable Flag to make widgets.json an editable file that can be modified during runtime. Default is 'false'.
--build If the file already exists, changes prompt action to overwrite/append/ignore. Only valid when --editable true.
--no-build Do not build the widgets.json file. Use this flag to load an existing widgets.json file without checking for updates.
@@ -151,6 +70,7 @@ Launcher specific arguments:
--no-filter Do not filter out widgets in widget_settings.json file.
--widgets-path Absolute path to the widgets.json file. Default is ~/envs/{env}/assets/widgets.json. Supplying this sets --editable true.
--templates-path Absolute path to the workspace_templates.json file. Default is ~/OpenBBUserData/workspace_templates.json.
--copilots-path Absolute path to the copilots.json file. Including this will add the /copilots endpoint to the API.
All other arguments will be passed to uvicorn. Here are the most common ones:
@@ -199,7 +119,345 @@ Contact the system administrator if you are using a work device and require addi
![This Connection Is Not Private](https://in.norton.com/content/dam/blogs/images/norton/am/this_connection_not_is_private.png)
### Location of `widgets.json`
## Example Application
Examples below will assume this code block is at the start of the file.
```python
from fastapi import FastAPI
app = FastAPI()
```
### Markdown Widget
This script will create a "markdown" widget with the returned text.
```python
@app.get("/hello")
async def hello() -> str:
"""Widget Description Generated By Docstring"""
return "Hello, from OpenBB!"
```
### Table Widget
Create a table widget by returning data shaped as a list of dictionaries (records)
```python
@app.get("/hello")
async def hello() -> list:
"""Widget Description Generated By Docstring"""
return [{"Column 1": "Hello", "Column 2": "from OpenBB!"}]
```
### Metric Widget
This widget displays a label, value, and optional delta.
To create a metric widget, import the custom response model below and define it as a return type.
```python
from openbb_platform_api.response_models import MetricResponseModel
@app.get("/hello_metric")
async def hello_metric() -> MetricResponseModel:
"""Widget description created by docstring."""
return MetricResponseModel(label="Good Vibes Score", value=100, delta="1%")
```
### Query Parameters
Function arguments will populate as widget parameters.
```python
from typing import Literal, Optional
@app.get("/hello")
async def hello(param1: Optional[str] = None, param2: Literal["Choice 1", "Choice 2"] = None, param3: bool = False) -> str:
"""Widget Description Generated By Docstring"""
if not param1 and not param2 and not param3:
return "Enter a parameter or make a choice!"
if param3:
return f"Param3 enabled!"
if param2:
return f"You selected: {param2}"
if param1:
return f"You entered: {param1}"
return "Nothing to return!"
```
### Easy Date Picker
Name the parameter "date", or include "_date" in the name, and type it as a string.
Additionally, a parameter type of `datetime.date` will work.
```python
import datetime
@app.get("/hello_date")
async def hello_date(date: str) -> list:
"""Widget description created by docstring."""
# Workspace returns the date as YYYY-MM-DD
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
@app.get("/hello_date_range")
async def hello_date_range(start: datetime.date, end: datetime.date) -> list:
"""Widget description created by docstring."""
# Workspace returns the date as YYYY-MM-DD
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
```
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.
```python
@app.get("/hello_params")
async def hello_params(
required_param: datetime.date,
param_1: str = "Default",
param_2: int = 0,
param_3: float = None,
param_4: Literal["Choice 1", "Choice 2", "Choice 3"] = "Choice 1",
param_5: bool = True,
) -> list:
"""Widget description created by docstring."""
# Handle the "choices" parameter inside the function to convert the displayed label to the desired one.
choices_dict = {"Choice 1": "do_one", "Choice 2": "do_two", "Choice 3": "do_three"}
choice = choices_dict.get(param_4, None)
# Do something with the parameters and return the result of work.
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
```
### Annotated Query Params
Adding helpful placeholder text and tooltips to parameters requires annotating them. This will also help code editors and improve the API documentation.
Additional settings, compatible with `widgets.json`, are defined in the `json_schema_extra` dictionary, under a key, `x-widget_config`
```python
from typing import Annotated
from fastapi import Query
```
The pattern for annotating a query parameter is:
```python
my_param: Annotated[str, Query(title="My Title", description="My custom hovertext with detailed information")] = None
```
```python
@app.get("/hello_annotated_params")
async def hello_annotated_params(
required_param: Annotated[
datetime.date, Query(description="The date is required.", title="Required Date")
],
not_required_param: Annotated[
Literal["Choice 1", "Choice 2", "Choice 3"],
Query(
description="Choose from a list of possible choices. The default is, 'Choice 1'",
title="Selector",
json_schema_extra={"x-widget_config": {"multiSelect": True}} # This lets you select multiple items from dropdown choices.
),
] = "Choice 1",
) -> list:
"""Widget description created by docstring."""
# Do something with the parameters and return the result of work.
return [{"Hello": "Row 1!"}, {"Hello": "Row 2!"}]
```
### Annotated Table Fields
The procedure for annotating the output is similar to the query parameters, and involves defining a response model.
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".
```python
from openbb_platform_api.response_models import Data
from pydantic import Field
```
Optional values should be defined, as `Optional[{type}]`, with a default value of `None`.
```python
class MyData(Data):
"""This is a custom Data model."""
# Add fields to the model.
column_1: datetime.date = Field(
description="The date column is a mandatory field.",
title="Some Date",
)
column_2: Optional[str] = Field(
default=None,
description="This is an optional string column.",
title="Some String",
)
column_3: int = Field(
default=-1,
description="This is an integer column.",
title="Some Integer",
)
column_4: float = Field(
default=10.25,
description="This is a float column.",
title="Some Float",
)
column_5: float = Field(
default=10.25,
description="This is a percent column.",
title="Some Percent",
json_schema_extra={"x-widget_config": {"formatterFn": "percent"}},
)
column_6: float = Field(
default=0.1025,
description="This is a normalized percent value adjusted for presentation.",
title="Some Normalized Percent",
json_schema_extra={
"x-widget_config": {
"formatterFn": "normalizedPercent",
"renderFn": "greenRed",
}
},
)
@app.get("/hello_data")
async def hello_data() -> list[MyData]:
"""Widget description created by docstring."""
# Do something with the parameters and return the result of work.
return [MyData(column_1=datetime.date.today(), column_2="Hello!")]
```
### PDF Widget
To create a PDF widget, import the custom response model below and define it as a return type.
The model handles conversion of the document, from a bytes object, to a base64 encoded string.
```python
from openbb_platform_api.response_models import PdfResponseModel
@app.get("/open_pdf")
async def open_pdf(
url: Annotated[
str,
Query(
description="URL, or local path, to the PDF document.",
title="URL or Path",
),
],
filename: Annotated[
Optional[str],
Query(
description="Filename to associate with the PDF internally.",
title="Fiilename",
),
] = "",
user_agent: Annotated[
Optional[str],
Query(description="A specific User-Agent string for the request.", title="User-Agent"),
] = None,
) -> PdfResponseModel:
"""Open a PDF document from a URL, or local file path."""
# pylint: disable=import-outside-toplevel
from pathlib import Path # noqa
from openbb_core.provider.utils.errors import OpenBBError
from openbb_core.provider.utils.helpers import get_requests_session
if "://" not in url:
file_path = Path(url)
if not file_path.is_file():
raise OpenBBError(f"The file - {url} - does not exist.")
with open(file_path, "rb") as file:
pdf = file.read()
else:
session = get_requests_session(headers={"User-Agent": user_agent})
response = session.get(url)
if response.status_code != 200:
raise OpenBBError(
f"Failed to open PDF from URL -> Code: {response.status_code} -> {response.reason}"
)
pdf = response.content
return PdfResponseModel(
filename = filename,
content = pdf,
)
```
### Custom Plotly Chart
To define a chart widget, update the widget "type" and return the content from the `Figure.to_plotly_json()` method.
```python
@app.get(
"/hello_chart",
openapi_extra={"widget_config": {"type": "chart"}},
)
async def hello_chart() -> dict:
"""Widget description created by docstring."""
from plotly.graph_objs import Bar, Layout, Figure
fig = Figure(
data=[Bar(x=["A", "B", "C"], y=[1, 2, 3])],
layout=Layout(title="Hello Chart!"),
)
return fig.to_plotly_json()
```
## Widget Config
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"`.
Configurations for `widgets.json` supplied here will override any of the automatically generated content. If the key does not exist, it will be created.
When inserting/updating an entry in a `Params` or `ColumnsDefs` array, the matching identifier is "paramName" and "field", respectively.
```python
@app.get(
"/hello_data",
openapi_extra={
"widget_config": {
"data": {
"table": {
"columnsDefs": [
{
"field": "column_1",
"headerName": "My Column",
"headerTooltip": "This hovertext wins!",
}
]
}
}
}
},
)
async def hello_data() -> list[MyData]:
"""Widget description created by docstring."""
# Do something with the parameters and return the result of work.
return [MyData(column_1=datetime.date.today(), column_2="Hello!")]
```
## Location of `widgets.json`
When `--editable` is not flagged, the file remains in memory until the server is stopped. It is regenerated every run.
The file can be served at any time by visiting the URL (host address will vary):
```sh
http://127.0.0.1:6900/widgets.json
```
When launched as `openbb-api --editiable`, a file will be stored to disk. By default, that location is:
@@ -220,7 +478,7 @@ openbb-api --widgets-path /Users/some_user/path/to/widgets.json
```
### Location of `templates.json`
### Location of `workspace_templates.json`
By default, the location is:
@@ -239,3 +497,5 @@ To export the layout, right-click on the dashboard and select, "Export Template"
A JSON dictionary will be exported. Insert the contents of the export into "~/OpenBBUserData/workspace_templates.json" by pasting between the JSON list markers, [ ].
If there are more than one, add a comma between each dictionary entry.
See the page [here](https://docs.openbb.co/terminal/custom-backend/advanced-controls/templates) for details on custom backend templates.

View File

@@ -3,7 +3,7 @@
from typing import Optional, Union
from openbb_core.provider.abstract.data import Data
from pydantic import ConfigDict, Field, model_serializer, model_validator
from pydantic import ConfigDict, Field, model_validator
class MetricResponseModel(Data):
@@ -33,6 +33,8 @@ class MetricResponseModel(Data):
"title": "Metric Widget Response Model",
"x-widget_config": {
"$.type": "metric",
"$.category": "Metric",
"$.searchCategory": "Metric",
},
},
)
@@ -81,11 +83,13 @@ class PdfResponseModel(Data):
model_config = ConfigDict(
extra="ignore",
json_schema_extra={
"title": "PDF Widget Response Model",
"x-widget_config": {
"$.type": "pdf",
"$.refetchInterval": False,
},
"$.category": "File",
"$.subCategory": "PDF",
"$.searchCategory": "File",
}
},
)
@@ -94,7 +98,7 @@ class PdfResponseModel(Data):
description="The filename of the PDF content.",
json_schema_extra={"x-widget_config": {"exclude": True}},
)
content: Optional[bytes] = Field(
content: Optional[Union[str, bytes]] = Field(
default=None,
description="The PDF content to display in the PDF widget.",
json_schema_extra={"x-widget_config": {"exclude": True}},
@@ -104,39 +108,42 @@ class PdfResponseModel(Data):
description="The URL reference to the PDF content.",
json_schema_extra={"x-widget_config": {"exclude": True}},
)
data_format: Optional[dict] = Field(
default=None,
description="Leave this field empty. This is populated by the model_validator.",
json_schema_extra={"x-widget_config": {"exclude": True}},
)
@model_validator(mode="before")
@model_validator(mode="after")
@classmethod
def validate_model(cls, values):
def validate_model(cls, values) -> "PdfResponseModel":
"""Validate the PDF content."""
if not values.get("content") and not values.get("url_reference"):
raise ValueError("Either 'content' or 'url_reference' must be provided.")
if values.get("url_reference") and "://" not in values.get("url_reference"):
raise ValueError("Invalid URL reference provided")
return values
@model_serializer
def model_serialize(self) -> dict:
"""Serialize the PDF content."""
# pylint: disable=import-outside-toplevel
import base64 # noqa
from io import BytesIO
file_reference = None
pdf = None
content = getattr(values, "content", None)
file_reference = getattr(values, "url_reference", None)
filename = getattr(values, "filename", "")
if self.content:
pdf = base64.b64encode(BytesIO(self.content).getvalue()).decode("utf-8")
elif self.url_reference:
file_reference = self.url_reference
if not content and not file_reference:
raise ValueError("Either 'content' or 'url_reference' must be provided.")
output = {
"data_format": {"data_type": "pdf", "filename": self.filename},
"content": pdf,
"url_reference": file_reference,
}
if file_reference and "://" not in file_reference:
raise ValueError("Invalid URL reference provided")
return {k: v for k, v in output.items() if v is not None}
if content:
pdf = (
base64.b64encode(BytesIO(content).getvalue()).decode("utf-8")
if isinstance(content, bytes)
else content
)
values.content = pdf
if file_reference:
values.url_reference = file_reference
elif hasattr(values, "url_reference"):
del values.url_reference
values.data_format = {"data_type": "pdf", "filename": filename}
return values

View File

@@ -374,6 +374,9 @@ def parse_args():
if _kwargs.get("copilots-path"):
_copilots_path = _kwargs.pop("copilots-path", None)
if not str(_copilots_path).endswith("copilots.json"):
_copilots_path = f"{_copilots_path}{'' if _copilots_path.endswith('/') else '/'}copilots.json"
if not str(_copilots_path).startswith("/"):
_copilots_path = str(cwd.joinpath(_copilots_path).resolve())

View File

@@ -54,6 +54,7 @@ TO_CAPS_STRINGS = [
"Isin",
"Figi",
"Cusip",
"Pdf",
]
@@ -241,7 +242,7 @@ def set_parameter_options(p: dict, p_schema: dict, providers: list[str]) -> dict
p["x-widget_config"] = widget_configs
else:
p["x-widget_config"] = p["x-widget_config"] = (
p["x-widget_config"] = (
widget_configs.get(provider, {}) if provider else widget_configs
)
@@ -597,8 +598,6 @@ def data_schema_to_columns_defs( # noqa: PLR0912 # pylint: disable=too-many-br
else "percent"
)
column_def["renderFn"] = "greenRed"
elif cell_data_type == "number":
del column_def["formatterFn"]
if k in ["cik", "isin", "figi", "cusip", "sedol", "symbol"]:
column_def["cellDataType"] = "text"

View File

@@ -381,7 +381,6 @@ def build_json( # noqa: PLR0912 # pylint: disable=too-many-branches
if key.startswith("$."):
var_key[key] = value
_ = data_config.pop(key)
break
widget_config["data"] = deep_merge_configs(
widget_config["data"],

View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
[[package]]
name = "aiohappyeyeballs"
@@ -7,7 +7,6 @@ description = "Happy Eyeballs for asyncio"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "aiohappyeyeballs-2.4.6-py3-none-any.whl", hash = "sha256:147ec992cf873d74f5062644332c539fcd42956dc69453fe5204195e560517e1"},
{file = "aiohappyeyeballs-2.4.6.tar.gz", hash = "sha256:9b05052f9042985d32ecbe4b59a77ae19c006a78f1344d7fdad69d28ded3d0b0"},
@@ -20,7 +19,6 @@ description = "Async http client/server framework (asyncio)"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:aa8a8caca81c0a3e765f19c6953416c58e2f4cc1b84829af01dd1c771bb2f91f"},
{file = "aiohttp-3.11.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84ede78acde96ca57f6cf8ccb8a13fbaf569f6011b9a52f870c662d4dc8cd854"},
@@ -116,7 +114,7 @@ propcache = ">=0.2.0"
yarl = ">=1.17.0,<2.0"
[package.extras]
speedups = ["Brotli", "aiodns (>=3.2.0)", "brotlicffi"]
speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (>=3.2.0) ; sys_platform == \"linux\" or sys_platform == \"darwin\"", "brotlicffi ; platform_python_implementation != \"CPython\""]
[[package]]
name = "aiosignal"
@@ -125,7 +123,6 @@ description = "aiosignal: a list of registered asynchronous callbacks"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5"},
{file = "aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54"},
@@ -141,7 +138,6 @@ description = "Reusable constraint types to use with typing.Annotated"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -154,7 +150,6 @@ description = "High level compatibility layer for multiple asynchronous event lo
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "anyio-4.8.0-py3-none-any.whl", hash = "sha256:b5011f270ab5eb0abf13385f851315585cc37ef330dd88e27ec3d34d651fd47a"},
{file = "anyio-4.8.0.tar.gz", hash = "sha256:1d9fe889df5212298c0c0723fa20479d1b94883a2df44bd3897aa91083316f7a"},
@@ -168,7 +163,7 @@ typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""}
[package.extras]
doc = ["Sphinx (>=7.4,<8.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx_rtd_theme"]
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1)", "uvloop (>=0.21)"]
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
trio = ["trio (>=0.26.1)"]
[[package]]
@@ -191,19 +186,18 @@ description = "Classes Without Boilerplate"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "attrs-25.1.0-py3-none-any.whl", hash = "sha256:c75a69e28a550a7e93789579c22aa26b0f5b83b75dc4e08fe092980051e1090a"},
{file = "attrs-25.1.0.tar.gz", hash = "sha256:1c97078a80c814273a76b2a298a932eb681c87415c11dee0a6921de7f1b02c3e"},
]
[package.extras]
benchmark = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
cov = ["cloudpickle", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
dev = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
benchmark = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-codspeed", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
cov = ["cloudpickle ; platform_python_implementation == \"CPython\"", "coverage[toml] (>=5.3)", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
dev = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pre-commit-uv", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
docs = ["cogapp", "furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier (<24.7)"]
tests = ["cloudpickle", "hypothesis", "mypy (>=1.11.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"]
tests-mypy = ["mypy (>=1.11.1)", "pytest-mypy-plugins"]
tests = ["cloudpickle ; platform_python_implementation == \"CPython\"", "hypothesis", "mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-xdist[psutil]"]
tests-mypy = ["mypy (>=1.11.1) ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\"", "pytest-mypy-plugins ; platform_python_implementation == \"CPython\" and python_version >= \"3.10\""]
[[package]]
name = "backoff"
@@ -212,7 +206,6 @@ description = "Function decoration for backoff and retry"
optional = false
python-versions = ">=3.7,<4.0"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"},
{file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"},
@@ -225,7 +218,6 @@ description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe"},
{file = "certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651"},
@@ -238,7 +230,6 @@ description = "The Real First Universal Charset Detector. Open, modern and activ
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"},
{file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"},
@@ -341,7 +332,6 @@ description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"},
{file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"},
@@ -357,7 +347,7 @@ description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
groups = ["main"]
markers = "python_version <= \"3.11\" and platform_system == \"Windows\" or python_version >= \"3.12\" and platform_system == \"Windows\""
markers = "platform_system == \"Windows\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -370,7 +360,6 @@ description = "Deep Difference and Search of any Python object/data. Recreate ob
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "deepdiff-8.2.0-py3-none-any.whl", hash = "sha256:5091f2cdfd372b1b9f6bfd8065ba323ae31118dc4e42594371b38c8bea3fd0a4"},
{file = "deepdiff-8.2.0.tar.gz", hash = "sha256:6ec78f65031485735545ffbe7a61e716c3c2d12ca6416886d5e9291fc76c46c3"},
@@ -406,7 +395,6 @@ description = "FastAPI framework, high performance, easy to learn, fast to code,
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "fastapi-0.115.8-py3-none-any.whl", hash = "sha256:753a96dd7e036b34eeef8babdfcfe3f28ff79648f86551eb36bfc1b0bf4a8cbf"},
{file = "fastapi-0.115.8.tar.gz", hash = "sha256:0ce9111231720190473e222cdf0f07f7206ad7e53ea02beb1d2dc36e2f0741e9"},
@@ -428,7 +416,6 @@ description = "A list-like structure which implements collections.abc.MutableSeq
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:5b6a66c18b5b9dd261ca98dffcb826a525334b2f29e7caa54e182255c5f6a65a"},
{file = "frozenlist-1.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d1b3eb7b05ea246510b43a7e53ed1653e55c2121019a97e60cad7efb881a97bb"},
@@ -531,7 +518,6 @@ description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -544,7 +530,6 @@ description = "HTML parser based on the WHATWG HTML specification"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "html5lib-1.1-py2.py3-none-any.whl", hash = "sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d"},
{file = "html5lib-1.1.tar.gz", hash = "sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f"},
@@ -555,10 +540,10 @@ six = ">=1.9"
webencodings = "*"
[package.extras]
all = ["chardet (>=2.2)", "genshi", "lxml"]
all = ["chardet (>=2.2)", "genshi", "lxml ; platform_python_implementation == \"CPython\""]
chardet = ["chardet (>=2.2)"]
genshi = ["genshi"]
lxml = ["lxml"]
lxml = ["lxml ; platform_python_implementation == \"CPython\""]
[[package]]
name = "idna"
@@ -567,7 +552,6 @@ description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
@@ -583,7 +567,6 @@ description = "Read metadata from Python packages"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "importlib_metadata-8.6.1-py3-none-any.whl", hash = "sha256:02a89390c1e15fdfdc0d7c6b25cb3e62650d0494005c97d6f148bf5b9787525e"},
{file = "importlib_metadata-8.6.1.tar.gz", hash = "sha256:310b41d755445d74569f993ccfc22838295d9fe005425094fad953d7f15c8580"},
@@ -593,12 +576,12 @@ files = [
zipp = ">=3.20"
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
perf = ["ipython"]
test = ["flufl.flake8", "importlib_resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
test = ["flufl.flake8", "importlib_resources (>=1.3) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"]
type = ["pytest-mypy"]
[[package]]
@@ -608,7 +591,6 @@ description = "An implementation of time.monotonic() for Python 2 & < 3.3"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "monotonic-1.6-py2.py3-none-any.whl", hash = "sha256:68687e19a14f11f26d140dd5c86f3dba4bf5df58003000ed467e0e2a69bca96c"},
{file = "monotonic-1.6.tar.gz", hash = "sha256:3a55207bcfed53ddd5c5bae174524062935efed17792e9de2ad0205ce9ad63f7"},
@@ -621,7 +603,6 @@ description = "multidict implementation"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "multidict-6.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3380252550e372e8511d49481bd836264c009adb826b23fefcc5dd3c69692f60"},
{file = "multidict-6.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:99f826cbf970077383d7de805c0681799491cb939c25450b9b5b3ced03ca99f1"},
@@ -783,7 +764,7 @@ description = "Fundamental package for array computing in Python"
optional = false
python-versions = ">=3.10"
groups = ["main"]
markers = "python_version == \"3.11\" or python_version >= \"3.12\""
markers = "python_version >= \"3.11\""
files = [
{file = "numpy-2.2.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7079129b64cb78bdc8d611d1fd7e8002c0a2565da6a47c4df8062349fee90e3e"},
{file = "numpy-2.2.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ec6c689c61df613b783aeb21f945c4cbe6c51c28cb70aae8430577ab39f163e"},
@@ -849,7 +830,6 @@ description = "OpenBB package with core functionality."
optional = false
python-versions = "<4.0,>=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "openbb_core-1.4.0-py3-none-any.whl", hash = "sha256:a8f7e63a4b0e642e0d68055ead1ce6ea94867094d4550b6c5de128c33069e3a1"},
{file = "openbb_core-1.4.0.tar.gz", hash = "sha256:50fa9746c461db392c927136bb2ade38cf130a28b1b101db0cb3802f1e03e3bf"},
@@ -879,7 +859,6 @@ description = "Orderly set"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "orderly_set-5.3.0-py3-none-any.whl", hash = "sha256:c2c0bfe604f5d3d9b24e8262a06feb612594f37aa3845650548befd7772945d1"},
{file = "orderly_set-5.3.0.tar.gz", hash = "sha256:80b3d8fdd3d39004d9aad389eaa0eab02c71f0a0511ba3a6d54a935a6c6a0acc"},
@@ -892,7 +871,6 @@ description = "Powerful data structures for data analysis, time series, and stat
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pandas-2.2.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1948ddde24197a0f7add2bdc4ca83bf2b1ef84a1bc8ccffd95eda17fd836ecb5"},
{file = "pandas-2.2.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:381175499d3802cde0eabbaf6324cce0c4f5d52ca6f8c377c29ad442f50f6348"},
@@ -980,7 +958,6 @@ description = "Integrate PostHog into any python application."
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "posthog-3.12.1-py2.py3-none-any.whl", hash = "sha256:f749bb4aa4610678c3ea71e0f491cfb2dce570196b9753a04260ff08e52dfb6d"},
{file = "posthog-3.12.1.tar.gz", hash = "sha256:319036f83436981b3bdc750b0ed067b5439c510ed601933f8fc043d0989c73c6"},
@@ -1006,7 +983,6 @@ description = "Accelerated property cache"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "propcache-0.2.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6b3f39a85d671436ee3d12c017f8fdea38509e4f25b28eb25877293c98c243f6"},
{file = "propcache-0.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d51fbe4285d5db5d92a929e3e21536ea3dd43732c5b177c7ef03f918dff9f2"},
@@ -1099,7 +1075,6 @@ description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584"},
{file = "pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236"},
@@ -1112,7 +1087,7 @@ typing-extensions = ">=4.12.2"
[package.extras]
email = ["email-validator (>=2.0.0)"]
timezone = ["tzdata"]
timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""]
[[package]]
name = "pydantic-core"
@@ -1121,7 +1096,6 @@ description = "Core functionality for Pydantic validation and serialization"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa"},
{file = "pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c"},
@@ -1235,7 +1209,6 @@ description = "JSON Web Token implementation in Python"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb"},
{file = "pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953"},
@@ -1254,7 +1227,6 @@ description = "Extensions to the standard Python datetime module"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
{file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
@@ -1270,7 +1242,6 @@ description = "Read key-value pairs from a .env file and set them as environment
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
@@ -1286,7 +1257,6 @@ description = "A streaming multipart parser for Python"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "python_multipart-0.0.18-py3-none-any.whl", hash = "sha256:efe91480f485f6a361427a541db4796f9e1591afc0fb8e7a4ba06bfbc6708996"},
{file = "python_multipart-0.0.18.tar.gz", hash = "sha256:7a68db60c8bfb82e460637fa4750727b45af1d5e2ed215593f917f64694d34fe"},
@@ -1299,7 +1269,6 @@ description = "World timezone definitions, modern and historical"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "pytz-2025.1-py2.py3-none-any.whl", hash = "sha256:89dd22dca55b46eac6eda23b2d72721bf1bdfef212645d81513ef5d03038de57"},
{file = "pytz-2025.1.tar.gz", hash = "sha256:c2db42be2a2518b28e65f9207c4d05e6ff547d1efa4086469ef855e4ab70178e"},
@@ -1312,7 +1281,6 @@ description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
@@ -1335,7 +1303,6 @@ description = "An extremely fast Python linter and code formatter, written in Ru
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "ruff-0.7.4-py3-none-linux_armv6l.whl", hash = "sha256:a4919925e7684a3f18e18243cd6bea7cfb8e968a6eaa8437971f681b7ec51478"},
{file = "ruff-0.7.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:cfb365c135b830778dda8c04fb7d4280ed0b984e1aec27f574445231e20d6c63"},
@@ -1364,7 +1331,6 @@ description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"},
{file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"},
@@ -1377,7 +1343,6 @@ description = "Sniff out which async library your code is running under"
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -1390,7 +1355,6 @@ description = "The little ASGI library that shines."
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "starlette-0.45.3-py3-none-any.whl", hash = "sha256:dfb6d332576f136ec740296c7e8bb8c8a7125044e7c6da30744718880cdd059d"},
{file = "starlette-0.45.3.tar.gz", hash = "sha256:2cbcba2a75806f8a41c722141486f37c28e30a0921c5f6fe4346cb0dcee1302f"},
@@ -1410,7 +1374,6 @@ description = "Backported and Experimental Type Hints for Python 3.8+"
optional = false
python-versions = ">=3.8"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -1423,7 +1386,6 @@ description = "Provider of IANA time zone data"
optional = false
python-versions = ">=2"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "tzdata-2025.1-py2.py3-none-any.whl", hash = "sha256:7e127113816800496f027041c570f50bcd464a020098a3b6b199517772303639"},
{file = "tzdata-2025.1.tar.gz", hash = "sha256:24894909e88cdb28bd1636c6887801df64cb485bd593f2fd83ef29075a81d694"},
@@ -1436,14 +1398,13 @@ description = "HTTP library with thread-safe connection pooling, file post, and
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
@@ -1455,7 +1416,6 @@ description = "UUID version 7, generating time-sorted UUIDs with 200ns time reso
optional = false
python-versions = ">=3.7"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "uuid7-0.1.0-py2.py3-none-any.whl", hash = "sha256:5e259bb63c8cb4aded5927ff41b444a80d0c7124e8a0ced7cf44efa1f5cccf61"},
{file = "uuid7-0.1.0.tar.gz", hash = "sha256:8c57aa32ee7456d3cc68c95c4530bc571646defac01895cfc73545449894a63c"},
@@ -1468,7 +1428,6 @@ description = "The lightning-fast ASGI server."
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4"},
{file = "uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9"},
@@ -1480,7 +1439,7 @@ h11 = ">=0.8"
typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""}
[package.extras]
standard = ["colorama (>=0.4)", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.4)"]
standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"]
[[package]]
name = "webencodings"
@@ -1489,7 +1448,6 @@ description = "Character encoding aliases for legacy web content"
optional = false
python-versions = "*"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"},
{file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"},
@@ -1502,7 +1460,6 @@ description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "websockets-14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e8179f95323b9ab1c11723e5d91a89403903f7b001828161b480a7810b334885"},
{file = "websockets-14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d8c3e2cdb38f31d8bd7d9d28908005f6fa9def3324edb9bf336d7e4266fd397"},
@@ -1582,7 +1539,6 @@ description = "Yet another URL library"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "yarl-1.18.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7df647e8edd71f000a5208fe6ff8c382a1de8edfbccdbbfe649d263de07d8c34"},
{file = "yarl-1.18.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c69697d3adff5aa4f874b19c0e4ed65180ceed6318ec856ebc423aa5850d84f7"},
@@ -1680,18 +1636,17 @@ description = "Backport of pathlib-compatible object wrapper for zip files"
optional = false
python-versions = ">=3.9"
groups = ["main"]
markers = "python_version <= \"3.11\" or python_version >= \"3.12\""
files = [
{file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"},
{file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"},
]
[package.extras]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"]
check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""]
cover = ["pytest-cov"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
enabler = ["pytest-enabler (>=2.2)"]
test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
test = ["big-O", "importlib-resources ; python_version < \"3.9\"", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"]
type = ["pytest-mypy"]
[metadata]

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "openbb-platform-api"
version = "1.1.2"
version = "1.1.3"
description = "OpenBB Platform API: Launch script and widgets builder for the OpenBB Platform API and Workspace Backend Connector."
authors = ["OpenBB <hello@openbb.co>"]
license = "AGPL-3.0-only"

View File

@@ -154,6 +154,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "Survey value.",
"cellDataType": "number"
@@ -312,6 +313,7 @@
},
{
"field": "consumer_sentiment",
"formatterFn": null,
"headerName": "Consumer Sentiment",
"headerTooltip": "Index of the results of the University of Michigan's monthly Survey of Consumers, which is used to estimate future spending and saving. (1966:Q1=100).",
"cellDataType": "number"
@@ -470,54 +472,63 @@
},
{
"field": "activity_index",
"formatterFn": null,
"headerName": "Activity Index",
"headerTooltip": "Activity Index.",
"cellDataType": "number"
},
{
"field": "one_year_outlook",
"formatterFn": null,
"headerName": "One Year Outlook",
"headerTooltip": "One Year Outlook Index.",
"cellDataType": "number"
},
{
"field": "manufacturing_activity",
"formatterFn": null,
"headerName": "Manufacturing Activity",
"headerTooltip": "Manufacturing Activity Index.",
"cellDataType": "number"
},
{
"field": "non_manufacturing_activity",
"formatterFn": null,
"headerName": "Non Manufacturing Activity",
"headerTooltip": "Non-Manufacturing Activity Index.",
"cellDataType": "number"
},
{
"field": "capital_expenditures_expectations",
"formatterFn": null,
"headerName": "Capital Expenditures Expectations",
"headerTooltip": "Capital Expenditures Expectations Index.",
"cellDataType": "number"
},
{
"field": "hiring_expectations",
"formatterFn": null,
"headerName": "Hiring Expectations",
"headerTooltip": "Hiring Expectations Index.",
"cellDataType": "number"
},
{
"field": "current_hiring",
"formatterFn": null,
"headerName": "Current Hiring",
"headerTooltip": "Current Hiring Index.",
"cellDataType": "number"
},
{
"field": "labor_costs",
"formatterFn": null,
"headerName": "Labor Costs",
"headerTooltip": "Labor Costs Index.",
"cellDataType": "number"
},
{
"field": "non_labor_costs",
"formatterFn": null,
"headerName": "Non Labor Costs",
"headerTooltip": "Non-Labor Costs Index.",
"cellDataType": "number"
@@ -743,6 +754,7 @@
},
{
"field": "diffusion_index",
"formatterFn": null,
"headerName": "Diffusion Index",
"headerTooltip": "Diffusion Index.",
"cellDataType": "number"
@@ -911,6 +923,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "",
"cellDataType": "number"
@@ -946,6 +959,7 @@
},
{
"field": "level",
"formatterFn": "int",
"headerName": "Level",
"headerTooltip": "The indentation level of the element.",
"cellDataType": "number"
@@ -1281,6 +1295,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "CPI index value or period change.",
"cellDataType": "number"
@@ -1556,30 +1571,35 @@
},
{
"field": "balance_total",
"formatterFn": null,
"headerName": "Balance Total",
"headerTooltip": "Current Account Total Balance (USD)",
"cellDataType": "number"
},
{
"field": "balance_total_services",
"formatterFn": null,
"headerName": "Balance Total Services",
"headerTooltip": "Current Account Total Services Balance (USD)",
"cellDataType": "number"
},
{
"field": "balance_total_secondary_income",
"formatterFn": null,
"headerName": "Balance Total Secondary Income",
"headerTooltip": "Current Account Total Secondary Income Balance (USD)",
"cellDataType": "number"
},
{
"field": "balance_total_goods",
"formatterFn": null,
"headerName": "Balance Total Goods",
"headerTooltip": "Current Account Total Goods Balance (USD)",
"cellDataType": "number"
},
{
"field": "balance_total_primary_income",
"formatterFn": null,
"headerName": "Balance Total Primary Income",
"headerTooltip": "Current Account Total Primary Income Balance (USD)",
"cellDataType": "number"
@@ -1602,30 +1622,35 @@
},
{
"field": "credits_total_services",
"formatterFn": null,
"headerName": "Credits Total Services",
"headerTooltip": "Current Account Credits Total Services (USD)",
"cellDataType": "number"
},
{
"field": "credits_total_goods",
"formatterFn": null,
"headerName": "Credits Total Goods",
"headerTooltip": "Current Account Credits Total Goods (USD)",
"cellDataType": "number"
},
{
"field": "credits_total_primary_income",
"formatterFn": null,
"headerName": "Credits Total Primary Income",
"headerTooltip": "Current Account Credits Total Primary Income (USD)",
"cellDataType": "number"
},
{
"field": "credits_total_secondary_income",
"formatterFn": null,
"headerName": "Credits Total Secondary Income",
"headerTooltip": "Current Account Credits Total Secondary Income (USD)",
"cellDataType": "number"
},
{
"field": "credits_total",
"formatterFn": null,
"headerName": "Credits Total",
"headerTooltip": "Current Account Credits Total (USD)",
"cellDataType": "number"
@@ -1648,30 +1673,35 @@
},
{
"field": "debits_total_services",
"formatterFn": null,
"headerName": "Debits Total Services",
"headerTooltip": "Current Account Debits Total Services (USD)",
"cellDataType": "number"
},
{
"field": "debits_total_goods",
"formatterFn": null,
"headerName": "Debits Total Goods",
"headerTooltip": "Current Account Debits Total Goods (USD)",
"cellDataType": "number"
},
{
"field": "debits_total_primary_income",
"formatterFn": null,
"headerName": "Debits Total Primary Income",
"headerTooltip": "Current Account Debits Total Primary Income (USD)",
"cellDataType": "number"
},
{
"field": "debits_total",
"formatterFn": null,
"headerName": "Debits Total",
"headerTooltip": "Current Account Debits Total (USD)",
"cellDataType": "number"
},
{
"field": "debits_total_secondary_income",
"formatterFn": null,
"headerName": "Debits Total Secondary Income",
"headerTooltip": "Current Account Debits Total Secondary Income (USD)",
"cellDataType": "number"
@@ -1813,6 +1843,7 @@
"columnsDefs": [
{
"field": "release_id",
"formatterFn": null,
"headerName": "Release ID",
"headerTooltip": "The release ID for queries.",
"cellDataType": "number"
@@ -1927,12 +1958,14 @@
},
{
"field": "popularity",
"formatterFn": null,
"headerName": "Popularity",
"headerTooltip": "Popularity of the series",
"cellDataType": "number"
},
{
"field": "group_popularity",
"formatterFn": null,
"headerName": "Group Popularity",
"headerTooltip": "Group popularity of the release",
"cellDataType": "number"
@@ -1946,6 +1979,7 @@
},
{
"field": "series_group",
"formatterFn": null,
"headerName": "Series Group",
"headerTooltip": "The series group ID of the series. This value is used to query for regional data.",
"cellDataType": "number"
@@ -2449,6 +2483,7 @@
},
{
"field": "level",
"formatterFn": null,
"headerName": "Level",
"headerTooltip": "The indentation level of the element.",
"cellDataType": "number"
@@ -2462,6 +2497,7 @@
},
{
"field": "line",
"formatterFn": null,
"headerName": "Line",
"headerTooltip": "The line number of the element.",
"cellDataType": "number"
@@ -2505,6 +2541,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "The reported value of the series.",
"cellDataType": "number"
@@ -2810,12 +2847,14 @@
},
{
"field": "code",
"formatterFn": null,
"headerName": "Code",
"headerTooltip": "The code of the region.",
"cellDataType": "number"
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "The obersvation value. The units are defined in the search results by series ID.",
"cellDataType": "number"
@@ -3025,6 +3064,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "Price, or change in price, per unit.",
"cellDataType": "number"
@@ -3133,6 +3173,7 @@
},
{
"field": "value",
"formatterFn": null,
"headerName": "Value",
"headerTooltip": "",
"cellDataType": "number"
@@ -3168,12 +3209,14 @@
},
{
"field": "level",
"formatterFn": "int",
"headerName": "Level",
"headerTooltip": "The indentation level of the element.",
"cellDataType": "number"
},
{
"field": "line",
"formatterFn": "int",
"headerName": "Line",
"headerTooltip": "The line number of the series in the table.",
"cellDataType": "number"
@@ -3230,6 +3273,7 @@
"columnsDefs": [
{
"field": "cik",
"formatterFn": null,
"headerName": "CIK",
"headerTooltip": "Central Index Key (CIK) for the requested entity.",
"cellDataType": "text"
@@ -3294,6 +3338,7 @@
},
{
"field": "cik_number",
"formatterFn": null,
"headerName": "CIK Number",
"headerTooltip": "Central Index Key (CIK)",
"cellDataType": "number"
@@ -3546,6 +3591,7 @@
"columnsDefs": [
{
"field": "sic_code",
"formatterFn": "int",
"headerName": "SIC Code",
"headerTooltip": "Sector Industrial Code (SIC)",
"cellDataType": "number"