Files
OpenBB/cli/openbb_cli/outputs/tsv.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

62 lines
1.9 KiB
Python

"""TSV output adapter — line-oriented, ANSI-free, safe for shell pipelines."""
from __future__ import annotations
import sys
from typing import Any
import pandas as pd
def _coerce_results(results: Any) -> pd.DataFrame | None:
"""Coerce the ``results`` payload of an OBBject into a DataFrame."""
if isinstance(results, pd.DataFrame):
return results
if isinstance(results, list):
return pd.DataFrame(results)
if isinstance(results, dict):
return pd.DataFrame([results])
return None
def _to_dataframe(data: Any) -> pd.DataFrame | None:
"""Best-effort coerce arbitrary CLI payloads into a DataFrame."""
if hasattr(data, "model_dump"):
results = data.model_dump(exclude_unset=True, exclude_none=True).get("results")
return _coerce_results(results) if results is not None else None
if isinstance(data, pd.DataFrame):
return data
if isinstance(data, pd.Series):
return data.to_frame()
if isinstance(data, dict):
return pd.DataFrame.from_dict(data, orient="columns")
if isinstance(data, (list, tuple)):
return pd.DataFrame(list(data))
return None
class TsvOutput:
"""TSV output adapter — emits the complete DataFrame as TSV to stdout."""
def display(
self,
data: Any,
title: str = "",
export: bool = False,
chart: bool = False,
) -> None:
"""Print the data as TSV. No styling, no truncation."""
if export:
return
if chart and hasattr(data, "chart") and data.chart is not None:
return
df = _to_dataframe(data)
if df is not None:
df.to_csv(sys.stdout, sep="\t", index=False)
sys.stdout.flush()
return
if hasattr(data, "model_dump"):
return
sys.stdout.write(f"{data!r}\n")
sys.stdout.flush()