Skip to content

Commit

Permalink
Merge branch 'docs/diataxis-refactor' of https://github.com/OpenBB-fi…
Browse files Browse the repository at this point in the history
…nance/OpenBBTerminal into docs/diataxis-refactor
  • Loading branch information
deeleeramone committed May 6, 2024
2 parents acf7611 + e471997 commit b7a5c1f
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 136 deletions.
37 changes: 25 additions & 12 deletions cli/openbb_cli/argparse_translator/obbject_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,43 @@
import json
from typing import Dict, List

from openbb_core.app.model.abstract.singleton import SingletonMeta
from openbb_core.app.model.obbject import OBBject


class Registry(metaclass=SingletonMeta):
class Registry:
"""Registry for OBBjects."""

obbjects: List[OBBject] = []
def __init__(self):
"""Initialize the registry."""
self._obbjects: List[OBBject] = []

@staticmethod
def _contains_obbject(uuid: str, obbjects: List[OBBject]) -> bool:
"""Check if obbject with uuid is in the registry."""
return any(obbject.id == uuid for obbject in obbjects)

@classmethod
def register(cls, obbject: OBBject):
def register(self, obbject: OBBject):
"""Designed to add an OBBject instance to the registry."""
if isinstance(obbject, OBBject) and not cls._contains_obbject(
obbject.id, cls.obbjects
if isinstance(obbject, OBBject) and not self._contains_obbject(
obbject.id, self._obbjects
):
cls.obbjects.append(obbject)
self._obbjects.append(obbject)

@classmethod
def get(cls, idx: int) -> OBBject:
def get(self, idx: int) -> OBBject:
"""Return the obbject at index idx."""
# the list should work as a stack
# i.e., the last element needs to be accessed by idx=0 and so on
reversed_list = list(reversed(cls.obbjects))
reversed_list = list(reversed(self._obbjects))
return reversed_list[idx]

def remove(self, idx: int = -1):
"""Remove the obbject at index idx, default is the last element."""
# the list should work as a stack
# i.e., the last element needs to be accessed by idx=0 and so on
reversed_list = list(reversed(self._obbjects))
del reversed_list[idx]
self._obbjects = list(reversed(reversed_list))

@property
def all(self) -> Dict[int, Dict]:
"""Return all obbjects in the registry"""
Expand Down Expand Up @@ -65,7 +73,7 @@ def _handle_data_repr(obbject: OBBject) -> str:
return data_repr

obbjects = {}
for i, obbject in enumerate(list(reversed(self.obbjects))):
for i, obbject in enumerate(list(reversed(self._obbjects))):
obbjects[i] = {
"route": obbject._route, # pylint: disable=protected-access
"provider": obbject.provider,
Expand All @@ -74,3 +82,8 @@ def _handle_data_repr(obbject: OBBject) -> str:
}

return obbjects

@property
def obbjects(self) -> List[OBBject]:
"""Return all obbjects in the registry"""
return self._obbjects
2 changes: 2 additions & 0 deletions cli/openbb_cli/assets/i18n/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ en:
settings/language: translation language
settings/n_rows: number of rows to show on non interactive tables
settings/n_cols: number of columns to show on non interactive tables
settings/obbject_msg: show obbject registry message after a new result is added
settings/obbject_res: define the maximum number of obbjects allowed in the registry
32 changes: 32 additions & 0 deletions cli/openbb_cli/controllers/base_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pathlib import Path
from typing import Any, Dict, List, Literal, Optional, Union

import pandas as pd
from openbb_cli.config import setup
from openbb_cli.config.completer import NestedCompleter
from openbb_cli.config.constants import SCRIPT_TAGS
Expand All @@ -20,6 +21,7 @@
get_flair_and_username,
parse_and_split_input,
print_guest_block_msg,
print_rich_table,
remove_file,
system_clear,
)
Expand Down Expand Up @@ -64,6 +66,7 @@ class BaseController(metaclass=ABCMeta):
"stop",
"hold",
"whoami",
"results",
]

CHOICES_COMMANDS: List[str] = []
Expand Down Expand Up @@ -119,6 +122,11 @@ def __init__(self, queue: Optional[List[str]] = None) -> None:
self.parser.exit_on_error = False # type: ignore
self.parser.add_argument("cmd", choices=self.controller_choices)

def update_completer(self, choices) -> None:
"""Update the completer with new choices."""
if session.prompt_session and session.settings.USE_PROMPT_TOOLKIT:
self.completer = NestedCompleter.from_nested_dict(choices)

def check_path(self) -> None:
"""Check if command path is valid."""
path = self.PATH
Expand Down Expand Up @@ -732,6 +740,30 @@ def call_whoami(self, other_args: List[str]) -> None:
else:
print_guest_block_msg()

def call_results(self, other_args: List[str]):
"""Process results command."""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="results",
description="Process results command. This command displays a registry of "
"'OBBjects' where all execution results are stored. "
"It is organized as a stack, with the most recent result at index 0.",
)
ns_parser = self.parse_simple_args(parser, other_args)
if ns_parser:
results = session.obbject_registry.all
if results:
df = pd.DataFrame.from_dict(results, orient="index")
print_rich_table(
df,
show_index=True,
index_name="stack index",
title="OBBject Results",
)
else:
session.console.print("[info]No results found.[/info]")

@staticmethod
def parse_simple_args(parser: argparse.ArgumentParser, other_args: List[str]):
"""Parse list of arguments into the supplied parser.
Expand Down
35 changes: 25 additions & 10 deletions cli/openbb_cli/controllers/base_platform_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@
from openbb_cli.argparse_translator.argparse_class_processor import (
ArgparseClassProcessor,
)
from openbb_cli.argparse_translator.obbject_registry import Registry
from openbb_cli.config.completer import NestedCompleter
from openbb_cli.config.menu_text import MenuText
from openbb_cli.controllers.base_controller import BaseController
from openbb_cli.controllers.utils import export_data, print_rich_table
Expand Down Expand Up @@ -69,26 +67,23 @@ def __init__(
self._link_obbject_to_data_processing_commands()
self._generate_commands()
self._generate_sub_controllers()

if session.prompt_session and session.settings.USE_PROMPT_TOOLKIT:
choices: dict = self.choices_default
self.completer = NestedCompleter.from_nested_dict(choices)
self.update_completer(self.choices_default)

def _link_obbject_to_data_processing_commands(self):
"""Link data processing commands to OBBject registry."""
for _, trl in self.translators.items():
for action in trl._parser._actions: # pylint: disable=protected-access
if action.dest == "data":
action.choices = range(len(Registry.obbjects))
action.choices = range(len(session.obbject_registry.obbjects))
action.type = int
action.nargs = None

def _intersect_data_processing_commands(self, ns_parser):
"""Intersect data processing commands and change the obbject id into an actual obbject."""
if hasattr(ns_parser, "data") and ns_parser.data in range(
len(Registry.obbjects)
len(session.obbject_registry.obbjects)
):
obbject = Registry.get(ns_parser.data)
obbject = session.obbject_registry.get(ns_parser.data)
setattr(ns_parser, "data", obbject.results)

return ns_parser
Expand Down Expand Up @@ -159,7 +154,22 @@ def method(self, other_args: List[str], translator=translator):
title = f"{self.PATH}{translator.func.__name__}"

if obbject:
Registry.register(obbject)
max_obbjects_exceeded = (
len(session.obbject_registry.obbjects)
>= session.settings.N_TO_KEEP_OBBJECT_REGISTRY
)
if max_obbjects_exceeded:
session.obbject_registry.remove()

session.obbject_registry.register(obbject)
# we need to force to re-link so that the new obbject
# is immediately available for data processing commands
self._link_obbject_to_data_processing_commands()
# also update the completer
self.update_completer(self.choices_default)

if session.settings.SHOW_MSG_OBBJECT_REGISTRY:
session.console.print("Added OBBject to registry.")

if hasattr(ns_parser, "chart") and ns_parser.chart:
obbject.show()
Expand Down Expand Up @@ -195,6 +205,11 @@ def method(self, other_args: List[str], translator=translator):
figure=fig,
)

if max_obbjects_exceeded:
session.console.print(
"[yellow]\nMaximum number of OBBjects reached. The oldest entry was removed.[yellow]"
)

except Exception as e:
session.console.print(f"[red]{e}[/]\n")
return
Expand Down
21 changes: 4 additions & 17 deletions cli/openbb_cli/controllers/cli_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@
import pandas as pd
import requests
from openbb import obb
from openbb_cli.argparse_translator.obbject_registry import Registry
from openbb_cli.config import constants
from openbb_cli.config.completer import NestedCompleter
from openbb_cli.config.constants import (
ASSETS_DIRECTORY,
ENV_FILE_SETTINGS,
Expand Down Expand Up @@ -217,7 +215,7 @@ def update_runtime_choices(self):
"--tag3": {c: None for c in constants.SCRIPT_TAGS},
}

self.completer = NestedCompleter.from_nested_dict(choices)
self.update_completer(choices)

def print_help(self):
"""Print help."""
Expand Down Expand Up @@ -303,11 +301,11 @@ def parse_input(self, an_input: str) -> List:

def call_settings(self, _):
"""Process feature flags command."""
from openbb_cli.controllers.feature_flags_controller import (
FeatureFlagsController,
from openbb_cli.controllers.settings_controller import (
SettingsController,
)

self.queue = self.load_class(FeatureFlagsController, self.queue)
self.queue = self.load_class(SettingsController, self.queue)

def call_exe(self, other_args: List[str]):
"""Process exe command."""
Expand Down Expand Up @@ -475,17 +473,6 @@ def call_exe(self, other_args: List[str]):
)
self.queue = self.queue[1:]

def call_results(self, _):
"""Process results command."""
results = Registry().all
if results:
df = pd.DataFrame.from_dict(results, orient="index")
print_rich_table(
df, show_index=True, index_name="stack index", title="OBBject Results"
)
else:
session.console.print("[info]No results found.[/info]")


def handle_job_cmds(jobs_cmds: Optional[List[str]]) -> Optional[List[str]]:
"""Handle job commands."""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import argparse
from typing import List, Optional

from openbb_cli.config.completer import NestedCompleter
from openbb_cli.config.constants import AVAILABLE_FLAIRS
from openbb_cli.config.menu_text import MenuText

Expand All @@ -16,7 +15,7 @@
session = Session()


class FeatureFlagsController(BaseController):
class SettingsController(BaseController):
"""Feature Flags Controller class."""

CHOICES_COMMANDS: List[str] = [
Expand All @@ -40,6 +39,8 @@ class FeatureFlagsController(BaseController):
"language",
"n_rows",
"n_cols",
"obbject_msg",
"obbject_res",
]
PATH = "/settings/"
CHOICES_GENERATION = True
Expand All @@ -48,9 +49,7 @@ def __init__(self, queue: Optional[List[str]] = None):
"""Initialize the Constructor."""
super().__init__(queue)

if session.prompt_session and session.settings.USE_PROMPT_TOOLKIT:
choices: dict = self.choices_default
self.completer = NestedCompleter.from_nested_dict(choices)
self.update_completer(self.choices_default)

def print_help(self):
"""Print help."""
Expand All @@ -68,6 +67,7 @@ def print_help(self):
mt.add_setting("tbhint", settings.TOOLBAR_HINT)
mt.add_setting("overwrite", settings.FILE_OVERWRITE)
mt.add_setting("version", settings.SHOW_VERSION)
mt.add_setting("obbject_msg", settings.SHOW_MSG_OBBJECT_REGISTRY)
mt.add_raw("\n")
mt.add_info("_settings_")
mt.add_raw("\n")
Expand All @@ -77,6 +77,7 @@ def print_help(self):
mt.add_cmd("language")
mt.add_cmd("n_rows")
mt.add_cmd("n_cols")
mt.add_cmd("obbject_res")

session.console.print(text=mt.menu_text, menu="Feature Flags")

Expand Down Expand Up @@ -134,6 +135,13 @@ def call_tbhint(self, _):
session.console.print("Will take effect when running CLI again.")
session.settings.set_item("TOOLBAR_HINT", not session.settings.TOOLBAR_HINT)

def call_obbject_msg(self, _):
"""Process obbject_msg command."""
session.settings.set_item(
"SHOW_MSG_OBBJECT_REGISTRY",
not session.settings.SHOW_MSG_OBBJECT_REGISTRY,
)

def call_console_style(self, other_args: List[str]) -> None:
"""Process cosole_style command."""
parser = argparse.ArgumentParser(
Expand Down Expand Up @@ -290,3 +298,30 @@ def call_n_cols(self, other_args: List[str]) -> None:
session.console.print(
f"Current number of columns: {session.settings.ALLOWED_NUMBER_OF_COLUMNS}"
)

def call_obbject_res(self, other_args: List[str]):
"""Process obbject_res command."""
parser = argparse.ArgumentParser(
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="obbject_res",
description="Maximum allowed number of results to keep in the OBBject Registry.",
add_help=False,
)
parser.add_argument(
"-n",
"--number",
dest="number",
action="store",
required=False,
type=int,
)
ns_parser = self.parse_simple_args(parser, other_args)

if ns_parser and ns_parser.number:
session.settings.set_item("N_TO_KEEP_OBBJECT_REGISTRY", ns_parser.number)

elif not other_args:
session.console.print(
f"Current maximum allowed number of results to keep in the OBBject registry:"
f" {session.settings.N_TO_KEEP_OBBJECT_REGISTRY}"
)
6 changes: 4 additions & 2 deletions cli/openbb_cli/models/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,21 @@ class Settings(BaseModel):
REMEMBER_CONTEXTS: bool = True
ENABLE_RICH_PANEL: bool = True
TOOLBAR_HINT: bool = True
SHOW_MSG_OBBJECT_REGISTRY: bool = False

# GENERAL
TIMEZONE: str = "America/New_York"
FLAIR: str = ":openbb"
USE_LANGUAGE: str = "en"
PREVIOUS_USE: bool = False
N_TO_KEEP_OBBJECT_REGISTRY: int = 10

# STYLE
RICH_STYLE: str = "dark"

# OUTPUT
ALLOWED_NUMBER_OF_ROWS: int = 366
ALLOWED_NUMBER_OF_COLUMNS: int = 15
ALLOWED_NUMBER_OF_ROWS: int = 20
ALLOWED_NUMBER_OF_COLUMNS: int = 5

# OPENBB
HUB_URL: str = "https://my.openbb.co"
Expand Down
Loading

0 comments on commit b7a5c1f

Please sign in to comment.