mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-05-07 22:40:49 +08:00
* remove python 3.9 support and code * black * more cli lint * more linting * more lint * fix for tests * docstring grammar police * add lock to to build function to avoid async import race conditions * grammar police * lots more linting * relock
165 lines
5.3 KiB
Python
165 lines
5.3 KiB
Python
"""Rich Module."""
|
|
|
|
__docformat__ = "numpy"
|
|
|
|
|
|
from openbb import obb
|
|
|
|
# https://rich.readthedocs.io/en/stable/appendix/colors.html#appendix-colors
|
|
# https://rich.readthedocs.io/en/latest/highlighting.html#custom-highlighters
|
|
|
|
|
|
RICH_TAGS = [
|
|
"[menu]",
|
|
"[/menu]",
|
|
"[cmds]",
|
|
"[/cmds]",
|
|
"[info]",
|
|
"[/info]",
|
|
"[param]",
|
|
"[/param]",
|
|
"[src]",
|
|
"[/src]",
|
|
"[help]",
|
|
"[/help]",
|
|
]
|
|
|
|
|
|
class MenuText:
|
|
"""Create menu text with rich colors to be displayed by CLI."""
|
|
|
|
CMD_NAME_LENGTH = 23
|
|
CMD_DESCRIPTION_LENGTH = 65
|
|
CMD_PROVIDERS_LENGTH = 23
|
|
SECTION_SPACING = 4
|
|
|
|
def __init__(self, path: str = ""):
|
|
"""Initialize menu help."""
|
|
self.menu_text = ""
|
|
self.menu_path = path
|
|
self.warnings: list[dict[str, str]] = []
|
|
|
|
@staticmethod
|
|
def _get_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 []
|
|
|
|
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]
|
|
|
|
if "_" in name:
|
|
name_split = name.split("_")
|
|
|
|
new_name = (
|
|
"_".join(name_split[:2]) if len(name_split) > 2 else name_split[0]
|
|
)
|
|
|
|
if len(new_name) > self.CMD_NAME_LENGTH:
|
|
new_name = new_name[: self.CMD_NAME_LENGTH]
|
|
|
|
if new_name != name:
|
|
self.warnings.append(
|
|
{
|
|
"warning": "Command name too long",
|
|
"actual command": f"`{name}`",
|
|
"displayed command": f"`{new_name}`",
|
|
}
|
|
)
|
|
name = new_name
|
|
|
|
return name
|
|
|
|
def _format_cmd_description(
|
|
self, name: str, description: str, trim: bool = True
|
|
) -> str:
|
|
"""Truncate command description length if it is too long."""
|
|
if not description or description == f"{self.menu_path}{name}":
|
|
description = ""
|
|
return (
|
|
description[: self.CMD_DESCRIPTION_LENGTH - 3] + "..."
|
|
if len(description) > self.CMD_DESCRIPTION_LENGTH and trim
|
|
else description
|
|
)
|
|
|
|
def add_raw(self, text: str, left_spacing: bool = False):
|
|
"""Append raw text (without translation)."""
|
|
if left_spacing:
|
|
self.menu_text += f"{self.SECTION_SPACING * ' '}{text}\n"
|
|
else:
|
|
self.menu_text += text
|
|
|
|
def add_info(self, text: str):
|
|
"""Append information text (after translation)."""
|
|
self.menu_text += f"[info]{text}:[/info]\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 = self._get_providers(f"{self.menu_path}{name}")
|
|
formatted_description = self._format_cmd_description(
|
|
formatted_name,
|
|
description,
|
|
bool(providers),
|
|
)
|
|
description_padding = (
|
|
self.CMD_DESCRIPTION_LENGTH - len(formatted_description)
|
|
) * " "
|
|
spacing = self.SECTION_SPACING * " "
|
|
description_padding = (
|
|
self.CMD_DESCRIPTION_LENGTH - len(formatted_description)
|
|
) * " "
|
|
cmd = f"{spacing}{formatted_name + name_padding}{spacing}{formatted_description + description_padding}"
|
|
cmd = f"[unvl]{cmd}[/unvl]" if disable else f"[cmds]{cmd}[/cmds]"
|
|
|
|
if providers:
|
|
cmd += rf"{spacing}[src]\[{', '.join(providers)}][/src]"
|
|
|
|
self.menu_text += cmd + "\n"
|
|
|
|
def add_menu(
|
|
self,
|
|
name: str,
|
|
description: str = "",
|
|
disable: bool = False,
|
|
):
|
|
"""Append menu text (after translation)."""
|
|
spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " "
|
|
|
|
if not description or description == f"{self.menu_path}{name}":
|
|
description = ""
|
|
|
|
if len(description) > self.CMD_DESCRIPTION_LENGTH:
|
|
description = description[: self.CMD_DESCRIPTION_LENGTH - 3] + "..."
|
|
|
|
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, description: str = ""):
|
|
"""Append menu text (after translation)."""
|
|
spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " "
|
|
indentation = self.SECTION_SPACING * " "
|
|
color = "green" if status else "red"
|
|
|
|
self.menu_text += (
|
|
f"[{color}]{indentation}{name}{spacing}{description}[/{color}]\n"
|
|
)
|