openbb-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. openbb_cli/__init__.py +1 -0
  2. openbb_cli/argparse_translator/__init__.py +0 -0
  3. openbb_cli/argparse_translator/argparse_class_processor.py +148 -0
  4. openbb_cli/argparse_translator/argparse_translator.py +627 -0
  5. openbb_cli/argparse_translator/obbject_registry.py +94 -0
  6. openbb_cli/assets/routines/routine_example.openbb +21 -0
  7. openbb_cli/assets/styles/default/Consolas.ttf +0 -0
  8. openbb_cli/assets/styles/default/dark.mpfstyle.json +47 -0
  9. openbb_cli/assets/styles/default/dark.mplrc.json +7 -0
  10. openbb_cli/assets/styles/default/dark.mplstyle +96 -0
  11. openbb_cli/assets/styles/default/dark.pltstyle.json +132 -0
  12. openbb_cli/assets/styles/default/dark.richstyle.json +9 -0
  13. openbb_cli/assets/styles/default/light.mpfstyle.json +47 -0
  14. openbb_cli/assets/styles/default/light.mplrc.json +7 -0
  15. openbb_cli/assets/styles/default/light.mplstyle +95 -0
  16. openbb_cli/assets/styles/default/light.pltstyle.json +871 -0
  17. openbb_cli/assets/styles/default/light.richstyle.json +9 -0
  18. openbb_cli/assets/styles/default/tables.pltstyle.json +102 -0
  19. openbb_cli/assets/styles/user/openbb.richstyle.json +9 -0
  20. openbb_cli/cli.py +20 -0
  21. openbb_cli/config/__init__.py +1 -0
  22. openbb_cli/config/completer.py +427 -0
  23. openbb_cli/config/console.py +93 -0
  24. openbb_cli/config/constants.py +80 -0
  25. openbb_cli/config/menu_text.py +165 -0
  26. openbb_cli/config/setup.py +11 -0
  27. openbb_cli/config/style.py +108 -0
  28. openbb_cli/controllers/base_controller.py +941 -0
  29. openbb_cli/controllers/base_platform_controller.py +349 -0
  30. openbb_cli/controllers/choices.py +324 -0
  31. openbb_cli/controllers/cli_controller.py +946 -0
  32. openbb_cli/controllers/hub_service.py +107 -0
  33. openbb_cli/controllers/platform_controller_factory.py +58 -0
  34. openbb_cli/controllers/script_parser.py +488 -0
  35. openbb_cli/controllers/settings_controller.py +373 -0
  36. openbb_cli/controllers/utils.py +967 -0
  37. openbb_cli/models/settings.py +73 -0
  38. openbb_cli/session.py +92 -0
  39. openbb_cli-1.0.0.dist-info/METADATA +91 -0
  40. openbb_cli-1.0.0.dist-info/RECORD +42 -0
  41. openbb_cli-1.0.0.dist-info/WHEEL +4 -0
  42. openbb_cli-1.0.0.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,80 @@
1
+ """Constants module."""
2
+
3
+ from pathlib import Path
4
+
5
+ # Paths
6
+ HOME_DIRECTORY = Path.home()
7
+ REPOSITORY_DIRECTORY = Path(__file__).parent.parent.parent.parent
8
+ SRC_DIRECTORY = Path(__file__).parent.parent
9
+ SETTINGS_DIRECTORY = HOME_DIRECTORY / ".openbb_platform"
10
+ ASSETS_DIRECTORY = SRC_DIRECTORY / "assets"
11
+ STYLES_DIRECTORY = ASSETS_DIRECTORY / "styles"
12
+ ENV_FILE_SETTINGS = SETTINGS_DIRECTORY / ".cli.env"
13
+ HIST_FILE_PROMPT = SETTINGS_DIRECTORY / ".cli.his"
14
+
15
+
16
+ DEFAULT_ROUTINES_URL = "https://openbb-cms.directus.app/items/Routines"
17
+ TIMEOUT = 30
18
+ CONNECTION_ERROR_MSG = "[red]Connection error.[/red]"
19
+ CONNECTION_TIMEOUT_MSG = "[red]Connection timeout.[/red]"
20
+ SCRIPT_TAGS = [
21
+ "stocks",
22
+ "crypto",
23
+ "etf",
24
+ "economy",
25
+ "forex",
26
+ "fixed income",
27
+ "alternative",
28
+ "funds",
29
+ "bonds",
30
+ "macro",
31
+ "mutual funds",
32
+ "equities",
33
+ "options",
34
+ "dark pool",
35
+ "shorts",
36
+ "insider",
37
+ "behavioral analysis",
38
+ "fundamental analysis",
39
+ "technical analysis",
40
+ "quantitative analysis",
41
+ "forecasting",
42
+ "government",
43
+ "comparison",
44
+ "nft",
45
+ "on chain",
46
+ "off chain",
47
+ "screener",
48
+ "report",
49
+ "overview",
50
+ "rates",
51
+ "econometrics",
52
+ "portfolio",
53
+ "real estate",
54
+ ]
55
+ AVAILABLE_FLAIRS = {
56
+ ":openbb": "(🦋)",
57
+ ":bug": "(🐛)",
58
+ ":rocket": "(🚀)",
59
+ ":diamond": "(💎)",
60
+ ":stars": "(✨)",
61
+ ":baseball": "(⚾)",
62
+ ":boat": "(⛵)",
63
+ ":phone": "(☎)",
64
+ ":mercury": "(☿)",
65
+ ":hidden": "",
66
+ ":sun": "(☼)",
67
+ ":moon": "(🌕)",
68
+ ":nuke": "(☢)",
69
+ ":hazard": "(☣)",
70
+ ":tunder": "(☈)",
71
+ ":king": "(♔)",
72
+ ":queen": "(♕)",
73
+ ":knight": "(♘)",
74
+ ":recycle": "(♻)",
75
+ ":scales": "(⚖)",
76
+ ":ball": "(⚽)",
77
+ ":golf": "(⛳)",
78
+ ":peace": "(☮)",
79
+ ":yy": "(☯)",
80
+ }
@@ -0,0 +1,165 @@
1
+ """Rich Module."""
2
+
3
+ __docformat__ = "numpy"
4
+
5
+ from typing import Dict, List
6
+
7
+ from openbb import obb
8
+
9
+ # https://rich.readthedocs.io/en/stable/appendix/colors.html#appendix-colors
10
+ # https://rich.readthedocs.io/en/latest/highlighting.html#custom-highlighters
11
+
12
+
13
+ RICH_TAGS = [
14
+ "[menu]",
15
+ "[/menu]",
16
+ "[cmds]",
17
+ "[/cmds]",
18
+ "[info]",
19
+ "[/info]",
20
+ "[param]",
21
+ "[/param]",
22
+ "[src]",
23
+ "[/src]",
24
+ "[help]",
25
+ "[/help]",
26
+ ]
27
+
28
+
29
+ class MenuText:
30
+ """Create menu text with rich colors to be displayed by CLI."""
31
+
32
+ CMD_NAME_LENGTH = 23
33
+ CMD_DESCRIPTION_LENGTH = 65
34
+ CMD_PROVIDERS_LENGTH = 23
35
+ SECTION_SPACING = 4
36
+
37
+ def __init__(self, path: str = ""):
38
+ """Initialize menu help."""
39
+ self.menu_text = ""
40
+ self.menu_path = path
41
+ self.warnings: List[Dict[str, str]] = []
42
+
43
+ @staticmethod
44
+ def _get_providers(command_path: str) -> List:
45
+ """Return the preferred provider for the given command.
46
+
47
+ Parameters
48
+ ----------
49
+ command_path: str
50
+ The command to find the provider for. E.g. "/equity/price/historical
51
+
52
+ Returns
53
+ -------
54
+ List
55
+ The list of providers for the given command.
56
+ """
57
+ command_reference = obb.reference.get("paths", {}).get(command_path, {}) # type: ignore
58
+ if command_reference:
59
+ providers = list(command_reference["parameters"].keys())
60
+ return [provider for provider in providers if provider != "standard"]
61
+ return []
62
+
63
+ def _format_cmd_name(self, name: str) -> str:
64
+ """Truncate command name length if it is too long."""
65
+ if len(name) > self.CMD_NAME_LENGTH:
66
+ new_name = name[: self.CMD_NAME_LENGTH]
67
+
68
+ if "_" in name:
69
+ name_split = name.split("_")
70
+
71
+ new_name = (
72
+ "_".join(name_split[:2]) if len(name_split) > 2 else name_split[0]
73
+ )
74
+
75
+ if len(new_name) > self.CMD_NAME_LENGTH:
76
+ new_name = new_name[: self.CMD_NAME_LENGTH]
77
+
78
+ if new_name != name:
79
+ self.warnings.append(
80
+ {
81
+ "warning": "Command name too long",
82
+ "command": name,
83
+ "trimmed_command": new_name,
84
+ }
85
+ )
86
+ name = new_name
87
+
88
+ return name
89
+
90
+ def _format_cmd_description(
91
+ self, name: str, description: str, trim: bool = True
92
+ ) -> str:
93
+ """Truncate command description length if it is too long."""
94
+ if not description or description == f"{self.menu_path}{name}":
95
+ description = ""
96
+ return (
97
+ description[: self.CMD_DESCRIPTION_LENGTH - 3] + "..."
98
+ if len(description) > self.CMD_DESCRIPTION_LENGTH and trim
99
+ else description
100
+ )
101
+
102
+ def add_raw(self, text: str, left_spacing: bool = False):
103
+ """Append raw text (without translation)."""
104
+ if left_spacing:
105
+ self.menu_text += f"{self.SECTION_SPACING * ' '}{text}\n"
106
+ else:
107
+ self.menu_text += text
108
+
109
+ def add_info(self, text: str):
110
+ """Append information text (after translation)."""
111
+ self.menu_text += f"[info]{text}:[/info]\n"
112
+
113
+ def add_cmd(self, name: str, description: str = "", disable: bool = False):
114
+ """Append command text (after translation)."""
115
+ formatted_name = self._format_cmd_name(name)
116
+ name_padding = (self.CMD_NAME_LENGTH - len(formatted_name)) * " "
117
+ providers = self._get_providers(f"{self.menu_path}{name}")
118
+ formatted_description = self._format_cmd_description(
119
+ formatted_name,
120
+ description,
121
+ bool(providers),
122
+ )
123
+ description_padding = (
124
+ self.CMD_DESCRIPTION_LENGTH - len(formatted_description)
125
+ ) * " "
126
+ spacing = self.SECTION_SPACING * " "
127
+ description_padding = (
128
+ self.CMD_DESCRIPTION_LENGTH - len(formatted_description)
129
+ ) * " "
130
+ cmd = f"{spacing}{formatted_name + name_padding}{spacing}{formatted_description+description_padding}"
131
+ cmd = f"[unvl]{cmd}[/unvl]" if disable else f"[cmds]{cmd}[/cmds]"
132
+
133
+ if providers:
134
+ cmd += rf"{spacing}[src]\[{', '.join(providers)}][/src]"
135
+
136
+ self.menu_text += cmd + "\n"
137
+
138
+ def add_menu(
139
+ self,
140
+ name: str,
141
+ description: str = "",
142
+ disable: bool = False,
143
+ ):
144
+ """Append menu text (after translation)."""
145
+ spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " "
146
+
147
+ if not description or description == f"{self.menu_path}{name}":
148
+ description = ""
149
+
150
+ if len(description) > self.CMD_DESCRIPTION_LENGTH:
151
+ description = description[: self.CMD_DESCRIPTION_LENGTH - 3] + "..."
152
+
153
+ menu = f"{name}{spacing}{description}"
154
+ tag = "unvl" if disable else "menu"
155
+ self.menu_text += f"[{tag}]> {menu}[/{tag}]\n"
156
+
157
+ def add_setting(self, name: str, status: bool = True, description: str = ""):
158
+ """Append menu text (after translation)."""
159
+ spacing = (self.CMD_NAME_LENGTH - len(name) + self.SECTION_SPACING) * " "
160
+ indentation = self.SECTION_SPACING * " "
161
+ color = "green" if status else "red"
162
+
163
+ self.menu_text += (
164
+ f"[{color}]{indentation}{name}{spacing}{description}[/{color}]\n"
165
+ )
@@ -0,0 +1,11 @@
1
+ """Configuration for the CLI."""
2
+
3
+ from pathlib import Path
4
+
5
+ from openbb_cli.config.constants import ENV_FILE_SETTINGS, SETTINGS_DIRECTORY
6
+
7
+
8
+ def bootstrap():
9
+ """Setup pre-launch configurations for the CLI."""
10
+ SETTINGS_DIRECTORY.mkdir(parents=True, exist_ok=True)
11
+ Path(ENV_FILE_SETTINGS).touch(exist_ok=True)
@@ -0,0 +1,108 @@
1
+ """Chart and style helpers for Plotly."""
2
+
3
+ # pylint: disable=C0302,R0902,W3301
4
+ import json
5
+ from pathlib import Path
6
+ from typing import Any, Dict, List, Optional
7
+
8
+ from rich.console import Console
9
+
10
+ from openbb_cli.config.constants import STYLES_DIRECTORY
11
+
12
+ console = Console()
13
+
14
+
15
+ class Style:
16
+ """The class that helps with handling of style configurations.
17
+
18
+ It serves styles for 2 libraries. For `Plotly` this class serves absolute paths
19
+ to the .pltstyle files. For `Plotly` and `Rich` this class serves custom
20
+ styles as python dictionaries.
21
+ """
22
+
23
+ STYLES_REPO = STYLES_DIRECTORY
24
+
25
+ console_styles_available: Dict[str, Path] = {}
26
+ console_style: Dict[str, Any] = {}
27
+
28
+ line_color: str = ""
29
+ up_color: str = ""
30
+ down_color: str = ""
31
+ up_colorway: List[str] = []
32
+ down_colorway: List[str] = []
33
+ up_color_transparent: str = ""
34
+ down_color_transparent: str = ""
35
+
36
+ line_width: float = 1.5
37
+
38
+ def __init__(
39
+ self,
40
+ style: Optional[str] = "",
41
+ directory: Optional[Path] = None,
42
+ ):
43
+ """Initialize the class."""
44
+ self._load(directory)
45
+ self.apply(style, directory)
46
+
47
+ def apply(
48
+ self, style: Optional[str] = None, directory: Optional[Path] = None
49
+ ) -> None:
50
+ """Apply the style to the console."""
51
+ if style:
52
+ if style in self.console_styles_available:
53
+ json_path: Optional[Path] = self.console_styles_available[style]
54
+ else:
55
+ self._load(directory)
56
+ if style in self.console_styles_available:
57
+ json_path = self.console_styles_available[style]
58
+ else:
59
+ console.print(f"\nInvalid console style '{style}', using default.")
60
+ json_path = self.console_styles_available.get("dark", None)
61
+
62
+ if json_path:
63
+ self.console_style = self._from_json(json_path)
64
+ else:
65
+ console.print("Error loading default.")
66
+
67
+ def _from_directory(self, folder: Optional[Path]) -> None:
68
+ """Load custom styles from folder.
69
+
70
+ Parses the styles/default and styles/user folders and loads style files.
71
+ To be recognized files need to follow a naming convention:
72
+ *.pltstyle - plotly stylesheets
73
+ *.richstyle.json - rich stylesheets
74
+
75
+ Parameters
76
+ ----------
77
+ folder : str
78
+ Path to the folder containing the stylesheets
79
+ """
80
+ if not folder or not folder.exists():
81
+ return
82
+
83
+ for attr, ext in zip(
84
+ ["console_styles_available"],
85
+ [".richstyle.json"],
86
+ ):
87
+ for file in folder.rglob(f"*{ext}"):
88
+ getattr(self, attr)[file.name.replace(ext, "")] = file
89
+
90
+ def _load(self, directory: Optional[Path] = None) -> None:
91
+ """Load custom styles from default and user folders."""
92
+ self._from_directory(self.STYLES_REPO)
93
+ self._from_directory(directory)
94
+
95
+ def _from_json(self, file: Path) -> Dict[str, Any]:
96
+ """Load style from json file."""
97
+ with open(file) as f:
98
+ json_style: dict = json.load(f)
99
+ for key, value in json_style.items():
100
+ json_style[key] = value.replace(
101
+ " ", ""
102
+ ) # remove whitespaces so Rich can parse it
103
+ return json_style
104
+
105
+ @property
106
+ def available_styles(self) -> List[str]:
107
+ """Return available styles."""
108
+ return list(self.console_styles_available.keys())