[V5] openbb-charting: Refactor for V5 and Decouple (#7545)

* refactor charting for v5 patterns and decouple entirely

* coveragerc

* lint and tests

* fix tests

* configure dev group with openbb-technical

* ty

* fix cli test

* remove 3.15 from test matrix - dependencies are unstable

---------

Co-authored-by: deeleeramone <>
This commit is contained in:
Danglewood
2026-07-01 09:37:01 -07:00
committed by GitHub
parent 3fd14d7068
commit f6867c2b18
85 changed files with 11846 additions and 5678 deletions

View File

@@ -4,6 +4,7 @@ from collections.abc import Callable, Iterable, Mapping
from re import Pattern
from typing import (
Any,
cast,
)
from prompt_toolkit.completion import CompleteEvent, Completer, Completion
@@ -65,8 +66,7 @@ class WordCompleter(Completer):
) -> Iterable[Completion]:
"""Get completions."""
words = self.words
if callable(words):
words = words() # ty: ignore[call-top-callable]
word_list = cast("list[str]", words if isinstance(words, list) else words())
if self.sentence:
word_before_cursor = document.text_before_cursor
@@ -97,7 +97,7 @@ class WordCompleter(Completer):
return word_before_cursor in word
return word.startswith(word_before_cursor)
for a in words:
for a in word_list:
if word_matches(a):
display = self.display_dict.get(a, a)
display_meta = self.meta_dict.get(a, "")

View File

@@ -269,7 +269,7 @@ class CLIController(BaseController):
bound_method = MethodType(method_call_command, self)
bound_method = update_wrapper(
partial(bound_method, router=router),
method_call_command, # ty: ignore[invalid-argument-type]
method_call_command,
)
setattr(self, f"call_{router}", bound_method)

View File

@@ -7,13 +7,14 @@ import random
import re
import shutil
import sqlite3
import subprocess
import sys
from contextlib import contextmanager
from datetime import (
datetime,
)
from pathlib import Path
from typing import TYPE_CHECKING, Optional
from typing import Any
from zoneinfo import ZoneInfo, available_timezones
import numpy as np
@@ -27,11 +28,6 @@ from rich.table import Table
from openbb_cli.config.constants import AVAILABLE_FLAIRS, ENV_FILE_SETTINGS
from openbb_cli.session import Session
if TYPE_CHECKING:
from openbb_charting.core.openbb_figure import ( # ty: ignore[unresolved-import]
OpenBBFigure,
)
class SQLiteTable:
"""Lazy-loading wrapper for SQLite tables."""
@@ -857,7 +853,7 @@ def export_data( # noqa: PLR0912
func_name: str,
df: pd.DataFrame = pd.DataFrame(),
sheet_name: str | None = None,
figure: Optional["OpenBBFigure"] = None,
figure: Any = None,
margin: bool = True,
) -> None:
"""Export data to a file.
@@ -874,7 +870,7 @@ def export_data( # noqa: PLR0912
Dataframe of data to save.
sheet_name : str | None
The name of the sheet to save in excel file.
figure : OpenBBFigure | None
figure : Any
Figure object to save as image file.
margin : bool
Automatically adjust subplot parameters to give specified padding.
@@ -997,7 +993,9 @@ def export_data( # noqa: PLR0912
def system_clear():
"""Clear screen."""
os.system("cls||clear") # noqa: S605, S607
subprocess.run( # noqa: S602
"cls" if os.name == "nt" else "clear", shell=True, check=False
)
def request(
@@ -1070,7 +1068,7 @@ def handle_obbject_display(
):
"""Handle the display of an OBBject."""
df: pd.DataFrame = pd.DataFrame()
fig: OpenBBFigure | None = None
fig: Any = None
if isinstance(getattr(obbject, "results", None), SQLiteTable):
sqlite_tbl: SQLiteTable = obbject.results # ty: ignore[invalid-assignment]

View File

@@ -137,14 +137,36 @@ class Session(metaclass=SingletonMeta):
except Exception:
return None
@staticmethod
def _resolve_backend_class() -> Any:
"""Resolve the charting backend class, honoring overrides and the engine.
Prefers a backend registered under the ``openbb_charting_backend``
entry-point group, otherwise asks the resolved charting engine for its
built-in backend, so the CLI never depends on ``openbb_charting`` by name.
"""
from openbb_core.app.charting import (
ChartingManager,
get_charting_backend_class,
)
backend_class = get_charting_backend_class()
if backend_class is not None:
return backend_class
engine = ChartingManager.get_charting_class()
getter = getattr(engine, "get_backend_class", None) if engine else None
return getter() if callable(getter) else None
def _build_backend(self) -> Any:
try:
from openbb_charting.core.backend import ( # ty: ignore[unresolved-import]
Backend,
)
from openbb_core.app.model.charts.charting_settings import ChartingSettings
return Backend(
backend_class = self._resolve_backend_class()
if backend_class is None:
return None
return backend_class(
ChartingSettings(
system_settings=self._obb.system,
user_settings=self._obb.user,