Files
OpenBB/cli/openbb_cli/dispatchers/_unpack.py
Danglewood 9a30186174 [V5] CLI 2.0 - Pluggable Backends, Non-TTY Default, HTTP Dispatcher, Spec Files + Codegen (#7433)
* stash some changes

* add more robust testing

* mypy

* point PR at V5

* introduce spec file

* codespell

* test fix

* fix workflow environment setup

* fix workflow environment setup

* fix workflow environment setup

* add pyyaml to dependencies

* split lint jobs

* fix workflow environment setup

* fix workflow environment setup

* workflow env setup

* workflow env setup

* clean up code comments

* add auth hook entrypoints

* codespell

* add codegen feature

* codespell

* move _unpack into dispatchers for consistency with codegen packages

* surface nested models in the response

* fix missing coverage in CI

* socrata updates

* test fix

* detect plotly output

* add --include and --exclude flags from generate-extension command

* cap test matrix at python 3.14

* no useless comments

* platform controller command description split

* merge URL overloads from path params

* exclude none and unset from model dump

---------

Co-authored-by: deeleeramone <>
Co-authored-by: Copilot <copilot@github.com>
2026-06-01 19:14:38 +03:00

48 lines
1.5 KiB
Python

"""Shared response unwrapping used by both the HTTP dispatcher and codegen."""
from __future__ import annotations
import json as _json
import re as _re
from typing import Any
_BARE_ASTERISK = _re.compile(r":\s*\*\s*(?=[,}\]])")
def safe_json_loads(text: str) -> Any:
"""Parse JSON text, sanitizing common upstream quirks first."""
try:
return _json.loads(text)
except ValueError:
sanitized = _BARE_ASTERISK.sub(": null", text)
return _json.loads(sanitized)
def unpack_response(
payload: Any,
) -> tuple[list[dict[str, Any]], dict[str, Any]]:
"""Split a raw API payload into (rows, metadata)."""
if isinstance(payload, list):
if len(payload) == 1:
return unpack_response(payload[0])
rows = [r for r in payload if isinstance(r, dict)]
if rows:
return rows, {}
return [{"value": r} for r in payload], {}
if not isinstance(payload, dict):
return [{"value": payload}], {}
list_keys = [k for k, v in payload.items() if isinstance(v, list)]
if len(list_keys) == 1:
key = list_keys[0]
items = payload[key]
rows = [r for r in items if isinstance(r, dict)]
if not rows and items:
rows = [{"value": r} for r in items]
metadata = {k: v for k, v in payload.items() if k != key}
return rows, metadata
if len(payload) == 1:
only_value = next(iter(payload.values()))
if isinstance(only_value, (list, dict)):
return unpack_response(only_value)
return [payload], {}