diff options
-rw-r--r-- | cli/openbb_cli/config/completer.py | 24 | ||||
-rw-r--r-- | cli/openbb_cli/config/constants.py | 2 | ||||
-rw-r--r-- | cli/openbb_cli/config/menu_text.py | 194 | ||||
-rw-r--r-- | cli/openbb_cli/controllers/cli_controller.py | 2 | ||||
-rw-r--r-- | cli/openbb_cli/models/settings.py | 18 | ||||
-rw-r--r-- | cli/openbb_cli/session.py | 4 | ||||
-rw-r--r-- | cli/pyproject.toml | 1 |
7 files changed, 79 insertions, 166 deletions
diff --git a/cli/openbb_cli/config/completer.py b/cli/openbb_cli/config/completer.py index f084c821478..9cc50a9b7eb 100644 --- a/cli/openbb_cli/config/completer.py +++ b/cli/openbb_cli/config/completer.py @@ -16,6 +16,7 @@ from typing import ( from prompt_toolkit.completion import CompleteEvent, Completer, Completion from prompt_toolkit.document import Document from prompt_toolkit.formatted_text import AnyFormattedText +from prompt_toolkit.history import FileHistory NestedDict = Mapping[str, Union[Any, Set[str], None, Completer]] @@ -401,3 +402,26 @@ class NestedCompleter(Completer): # This is a WordCompleter yield from completer.get_completions(document, complete_event) + + +class CustomFileHistory(FileHistory): + """Filtered file history.""" + + def sanitize_input(self, string: str) -> str: + """Sanitize sensitive information from the input string by parsing arguments.""" + keywords = ["--password", "--email", "--pat"] + string_list = string.split(" ") + + for kw in keywords: + if kw in string_list: + index = string_list.index(kw) + if len(string_list) > index + 1: + string_list[index + 1] = "********" + + result = " ".join(string_list) + return result + + def store_string(self, string: str) -> None: + """Store string in history.""" + string = self.sanitize_input(string) + super().store_string(string) diff --git a/cli/openbb_cli/config/constants.py b/cli/openbb_cli/config/constants.py index c44150324f3..b5b8867a243 100644 --- a/cli/openbb_cli/config/constants.py +++ b/cli/openbb_cli/config/constants.py @@ -9,8 +9,6 @@ SRC_DIRECTORY = Path(__file__).parent.parent SETTINGS_DIRECTORY = HOME_DIRECTORY / ".openbb_platform" ASSETS_DIRECTORY = SRC_DIRECTORY / "assets" STYLES_DIRECTORY = ASSETS_DIRECTORY / "styles" -ENV_FILE_REPOSITORY = REPOSITORY_DIRECTORY / ".env" -ENV_FILE_PROJECT = REPOSITORY_DIRECTORY / "openbb_cli" / ".env" ENV_FILE_SETTINGS = SETTINGS_DIRECTORY / ".cli.env" HIST_FILE_PROMPT = SETTINGS_DIRECTORY / ".cli.his" I18N_FILE = ASSETS_DIRECTORY / "i18n" diff --git a/cli/openbb_cli/config/menu_text.py b/cli/openbb_cli/config/menu_text.py index d9bdc59656c..56e2034998c 100644 --- a/cli/openbb_cli/config/menu_text.py +++ b/cli/openbb_cli/config/menu_text.py @@ -26,28 +26,6 @@ RICH_TAGS = [ "[/help]", ] -USE_COLOR = True - - -def get_ordered_providers(command_path: str) -> List: - """Return the preferred provider for the given command. - - Parameters - ---------- - command_path: str - The command to find the provider for. E.g. "/equity/price/historical - - Returns - ------- - List - The list of providers for the given command. - """ - command_reference = obb.reference.get("paths", {}).get(command_path, {}) # type: ignore - if command_reference: - providers = list(command_reference["parameters"].keys()) - return [provider for provider in providers if provider != "standard"] - return [] - class MenuText: """Create menu text with rich colors to be displayed by CLI.""" @@ -58,82 +36,33 @@ class MenuText: SECTION_SPACING = 4 def __init__(self, path: str = ""): - """Initialize menu help. - - Parameters - ---------- - path : str - path to the menu that is being created - column_sources : int - column width from which to start displaying sources - """ + """Initialize menu help.""" self.menu_text = "" self.menu_path = path self.warnings: List[Dict[str, str]] = [] - def add_raw(self, raw_text: str): - """Append raw text (no translation) to a menu. - - Parameters - ---------- - raw_text : str - raw text to be appended to the menu - """ - self.menu_text += raw_text - - def add_custom(self, key: str): - """Append custom text (after translation from key) to a menu. - - Parameters - ---------- - key : str - key to get translated text and add to the menu - """ - self.menu_text += f"{i18n.t(self.menu_path + key)}" - - def add_info(self, key_info: str): - """Append info text (after translation from key) to a menu. - - Parameters - ---------- - key_info : str - key to get translated text and add to the menu as info - """ - self.menu_text += f"[info]{i18n.t(self.menu_path + key_info)}:[/info]\n" - - def add_param(self, key_param: str, value: str, col_align: int = 0): - """Append info text (after translation from key) to a menu. - - Parameters - ---------- - key_param : str - key to get translated text and add to the menu as parameter - value : str - value to display in front of the parameter - col_align : int - column alignment for the value. This allows for a better UX experience. - """ - parameter_translated = i18n.t(self.menu_path + key_param) - space = ( - (col_align - len(parameter_translated)) * " " - if col_align > len(parameter_translated) - else "" - ) - self.menu_text += f"[param]{parameter_translated}{space}:[/param] {value}\n" - - def _format_cmd_name(self, name: str) -> str: - """Adjust the length of the command if it is too long. + @staticmethod + def _get_providers(command_path: str) -> List: + """Return the preferred provider for the given command. Parameters ---------- - name : str - command to be formatted + command_path: str + The command to find the provider for. E.g. "/equity/price/historical Returns ------- - str - formatted command + List + The list of providers for the given command. """ + command_reference = obb.reference.get("paths", {}).get(command_path, {}) # type: ignore + if command_reference: + providers = list(command_reference["parameters"].keys()) + return [provider for provider in providers if provider != "standard"] + return [] + + def _format_cmd_name(self, name: str) -> str: + """Truncate command name length if it is too long.""" if len(name) > self.CMD_NAME_LENGTH: new_name = name[ : self.CMD_NAME_LENGTH @@ -164,22 +93,7 @@ class MenuText: def _format_cmd_description( self, name: str, description: str, trim: bool = True ) -> str: - """Handle the command description. - - Parameters - ---------- - name : str - command to be adjusted - description : str - description of the command - trim : bool - If true, the description will be trimmed to the maximum length - - Returns - ------- - str - adjusted command description - """ + """Truncate command description length if it is too long.""" if not description: description = i18n.t(self.menu_path + name) if description == self.menu_path + name: @@ -190,21 +104,33 @@ class MenuText: else description ) - def add_cmd(self, name: str, description: str = "", disable: bool = False): - """Append command text (after translation from key) to a menu. + def add_raw(self, text: str): + """Append raw text (without translation).""" + self.menu_text += text - Parameters - ---------- - name : str - key command to be executed by user. It is also used as a key to get description of command. - description : str - description of the command - disable : bool - If disable is true, the command line is greyed out. - """ + def add_custom(self, name: str): + """Append custom text (after translation).""" + self.menu_text += f"{i18n.t(self.menu_path + name)}" + + def add_info(self, text: str): + """Append information text (after translation).""" + self.menu_text += f"[info]{i18n.t(self.menu_path + text)}:[/info]\n" + + def add_param(self, name: str, value: str, col_align: int = 0): + """Append parameter (after translation).""" + parameter_translated = i18n.t(self.menu_path + name) + space = ( + (col_align - len(parameter_translated)) * " " + if col_align > len(parameter_translated) + else "" + ) + self.menu_text += f"[param]{parameter_translated}{space}:[/param] {value}\n" + + def add_cmd(self, name: str, description: str = "", disable: bool = False): + """Append command text (after translation).""" formatted_name = self._format_cmd_name(name) name_padding = (self.CMD_NAME_LENGTH - len(formatted_name)) * " " - providers = get_ordered_providers(f"{self.menu_path}{formatted_name}") + providers = self._get_providers(f"{self.menu_path}{name}") formatted_description = self._format_cmd_description( formatted_name, description, @@ -231,43 +157,21 @@ class MenuText: description: str = "", disable: bool = False, ): - """Append menu text (after translation from key) to a menu. - - Parameters - ---------- - name : str - key menu to be executed by user. It is also used as a key to get description of menu. - disable : bool - If disable is true, the menu line is greyed out. - """ + """Append menu text (after translation).""" spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " " - if description: - menu = f"{name}{spacing}{description}" - else: + if not description: description = i18n.t(self.menu_path + name) if description == self.menu_path + name: description = "" - menu = f"{name}{spacing}{description}" - if disable: - self.menu_text += f"[unvl]> {menu}[/unvl]\n" - else: - self.menu_text += f"[menu]> {menu}[/menu]\n" + menu = f"{name}{spacing}{description}" + tag = "unvl" if disable else "menu" + self.menu_text += f"[{tag}]> {menu}[/{tag}]\n" def add_setting(self, name: str, status: bool = True): - """Append menu text (after translation from key) to a menu. - - Parameters - ---------- - name : str - key setting to be set by user. It is also used as a key to get description of the setting. - status : bool - status of the current setting. If true the line will be green, otherwise red. - """ + """Append menu text (after translation).""" spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " " indentation = self.SECTION_SPACING * " " - if status: - self.menu_text += f"[green]{indentation}{name}{spacing}{i18n.t(self.menu_path + name)}[/green]\n" - else: - self.menu_text += f"[red]{indentation}{name}{spacing}{i18n.t(self.menu_path + name)}[/red]\n" + color = "green" if status else "red" + self.menu_text += f"[{color}]{indentation}{name}{spacing}{i18n.t(self.menu_path + name)}[/{color}]\n" diff --git a/cli/openbb_cli/controllers/cli_controller.py b/cli/openbb_cli/controllers/cli_controller.py index 8c79ae6f842..e82a5dbdfc0 100644 --- a/cli/openbb_cli/controllers/cli_controller.py +++ b/cli/openbb_cli/controllers/cli_controller.py @@ -128,6 +128,8 @@ class CLIController(BaseController): """Call command.""" mdl = getattr(obb, router) df = pd.DataFrame.from_dict(mdl.model_dump(), orient="index") + if isinstance(df.columns, pd.RangeIndex): + df.columns = [str(i) for i in df.columns] return print_rich_table(df, show_index=True) for router, value in PLATFORM_ROUTERS.items(): diff --git a/cli/openbb_cli/models/settings.py b/cli/openbb_cli/models/settings.py index f83bca01ab3..754b122034c 100644 --- a/cli/openbb_cli/models/settings.py +++ b/cli/openbb_cli/models/settings.py @@ -3,11 +3,7 @@ from typing import Any from dotenv import dotenv_values, set_key -from openbb_cli.config.constants import ( - ENV_FILE_PROJECT, - ENV_FILE_REPOSITORY, - ENV_FILE_SETTINGS, -) +from openbb_cli.config.constants import ENV_FILE_SETTINGS from pydantic import BaseModel, ConfigDict, model_validator @@ -62,16 +58,8 @@ class Settings(BaseModel): @model_validator(mode="before") @classmethod def from_env(cls, values: dict) -> dict: - """Load .env files. - - Loads the dotenv files in the following order: - 1. Repository .env file - 2. Package .env file - 3. User .env file - """ + """Load settings from .env.""" settings = {} - settings.update(dotenv_values(ENV_FILE_REPOSITORY)) - settings.update(dotenv_values(ENV_FILE_PROJECT)) settings.update(dotenv_values(ENV_FILE_SETTINGS)) settings.update(values) filtered = {k.replace("OPENBB_", ""): v for k, v in settings.items()} @@ -79,7 +67,5 @@ class Settings(BaseModel): def set_item(self, key: str, value: Any) -> None: """Set an item in the model and save to .env.""" - # TODO: Check if this is ok, we are just saving into the settings .env - # Same behavior as before... setattr(self, key, value) set_key(str(ENV_FILE_SETTINGS), "OPENBB_" + key, str(value)) diff --git a/cli/openbb_cli/session.py b/cli/openbb_cli/session.py index 96b63f10da9..ef63fd6e7f0 100644 --- a/cli/openbb_cli/session.py +++ b/cli/openbb_cli/session.py @@ -8,8 +8,8 @@ from openbb import obb from openbb_core.app.model.abstract.singleton import SingletonMeta from openbb_core.app.model.user_settings import UserSettings as User from prompt_toolkit import PromptSession -from prompt_toolkit.history import FileHistory +from openbb_cli.config.completer import CustomFileHistory from openbb_cli.config.console import Console from openbb_cli.config.constants import HIST_FILE_PROMPT from openbb_cli.config.style import Style @@ -62,7 +62,7 @@ class Session(metaclass=SingletonMeta): try: if sys.stdin.isatty(): prompt_session: Optional[PromptSession] = PromptSession( - history=FileHistory(str(HIST_FILE_PROMPT)) + history=CustomFileHistory(str(HIST_FILE_PROMPT)) ) else: prompt_session = None diff --git a/cli/pyproject.toml b/cli/pyproject.toml index 3ef0d94a897..93d8ab34a93 100644 --- a/cli/pyproject.toml +++ b/cli/pyproject.toml @@ -5,7 +5,6 @@ description = "Investment Research for Everyone, Anywhere." license = "MIT" authors = ["OpenBB <hello@openbb.co>"] packages = [{ include = "openbb_cli" }] -include = ["cli/.env"] readme = "README.md" homepage = "https://openbb.co" repository = "https://github.com/OpenBB-finance/OpenBBTerminal" |