Files
Danglewood 869cfed125 [Release] openbb-v5.0.0 (#7741)
* merge branch develop with main

* bump desktop version

* fix the merge

* sync Cargo.lock to desktop 2.0.0

* fix cli conftest.py

---------

Co-authored-by: deeleeramone <>
2026-09-29 10:58:44 -07:00

117 lines
2.8 KiB
Python

"""Access to the v2 FRED API."""
from typing import Any
ROOT = "https://api.stlouisfed.org/fred/v2"
MAX_PAGES = 12
PAGE_LIMIT = 500000
def headers(api_key: str | None) -> dict:
"""Return the headers a v2 request carries.
Parameters
----------
api_key : str or None
The FRED API key.
Returns
-------
dict
The request headers, carrying the key as a bearer token.
"""
from openbb_fred.utils.api import headers as request_headers
return request_headers(api_key or "")
async def release_observations(
release_id: str | int,
api_key: str | None,
use_cache: bool = True,
) -> tuple[dict, dict]:
"""Read every series on a release, with its observations.
Parameters
----------
release_id : str or int
The FRED release id.
api_key : str or None
The FRED API key.
use_cache : bool
Whether to read and write the on-disk cache.
Returns
-------
tuple[dict, dict]
The release description, and each series keyed by its id.
Raises
------
OpenBBError
If the release is unknown or the key is not accepted.
"""
from openbb_core.app.model.abstract.error import OpenBBError
from openbb_fred.utils.rate_limiter import fred_get
request = headers(api_key)
release: dict = {}
series: dict[str, dict] = {}
cursor: str | None = None
for _ in range(MAX_PAGES):
url = (
f"{ROOT}/release/observations?release_id={release_id}"
f"&format=json&limit={PAGE_LIMIT}"
)
if cursor:
from urllib.parse import quote
url += f"&next_cursor={quote(cursor)}"
payload = await fred_get(url, use_cache=use_cache, headers=request)
if not isinstance(payload, dict):
break
if payload.get("code"):
raise OpenBBError(f"FRED rejected the request: {payload.get('message')}")
release = payload.get("release") or release
for entry in payload.get("series") or []:
held = series.setdefault(entry["series_id"], {**entry, "observations": []})
held["observations"].extend(entry.get("observations") or [])
cursor = payload.get("next_cursor")
if not payload.get("has_more") or not cursor:
break
if not series:
raise OpenBBError(f"No series are published for release {release_id}.")
return release, series
def published(observations: "list[dict]") -> dict[str, Any]:
"""Return the observations carrying a value, keyed by date.
Parameters
----------
observations : list[dict]
The date and value pairs the API returned.
Returns
-------
dict
The value observed on each date.
"""
return {
o["date"]: float(o["value"])
for o in observations
if o.get("value") not in (".", "", None)
}