openbb-cli 1.0.2__tar.gz → 1.0.4__tar.gz
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.
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/PKG-INFO +2 -3
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/obbject_registry.py +42 -9
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/reference_processor.py +5 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/utils.py +8 -3
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/cli.py +9 -1
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/base_controller.py +89 -32
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/base_platform_controller.py +69 -28
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/choices.py +17 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/cli_controller.py +9 -16
- openbb_cli-1.0.4/openbb_cli/controllers/settings_controller.py +142 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/utils.py +53 -47
- openbb_cli-1.0.4/openbb_cli/models/settings.py +167 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/session.py +0 -3
- openbb_cli-1.0.4/openbb_cli/utils/utils.py +34 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/pyproject.toml +2 -3
- openbb_cli-1.0.2/openbb_cli/controllers/settings_controller.py +0 -373
- openbb_cli-1.0.2/openbb_cli/models/settings.py +0 -76
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/README.md +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/__init__.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/__init__.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/argparse_argument.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/argparse_class_processor.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/argparse_translator/argparse_translator.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/routines/routine_example.openbb +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/Consolas.ttf +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/dark.mpfstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/dark.mplrc.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/dark.mplstyle +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/dark.pltstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/dark.richstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/light.mpfstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/light.mplrc.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/light.mplstyle +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/light.pltstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/light.richstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/default/tables.pltstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/assets/styles/user/openbb.richstyle.json +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/__init__.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/completer.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/console.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/constants.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/menu_text.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/setup.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/config/style.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/hub_service.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/platform_controller_factory.py +0 -0
- {openbb_cli-1.0.2 → openbb_cli-1.0.4}/openbb_cli/controllers/script_parser.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: openbb-cli
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.4
|
|
4
4
|
Summary: Investment Research for Everyone, Anywhere.
|
|
5
5
|
Home-page: https://openbb.co
|
|
6
6
|
License: AGPL-3.0-only
|
|
@@ -12,8 +12,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.9
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.10
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
-
Requires-Dist: openbb
|
|
16
|
-
Requires-Dist: openbb[all] (>=4.2.1,<5.0.0)
|
|
15
|
+
Requires-Dist: openbb[all] (>=4.2.3,<5.0.0)
|
|
17
16
|
Requires-Dist: openpyxl (>=3.1.2,<4.0.0)
|
|
18
17
|
Requires-Dist: prompt-toolkit (>=3.0.16,<4.0.0)
|
|
19
18
|
Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Registry for OBBjects."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Dict, List
|
|
4
|
+
from typing import Dict, List, Optional, Union
|
|
5
5
|
|
|
6
6
|
from openbb_core.app.model.obbject import OBBject
|
|
7
7
|
|
|
@@ -29,11 +29,32 @@ class Registry:
|
|
|
29
29
|
return True
|
|
30
30
|
return False
|
|
31
31
|
|
|
32
|
-
def get(self,
|
|
32
|
+
def get(self, arg: Union[int, str]) -> Optional[OBBject]:
|
|
33
|
+
"""Return the obbject with index or key."""
|
|
34
|
+
if isinstance(arg, int):
|
|
35
|
+
return self._get_by_index(arg)
|
|
36
|
+
if isinstance(arg, str):
|
|
37
|
+
return self._get_by_key(arg)
|
|
38
|
+
|
|
39
|
+
raise ValueError("Couldn't get the `OBBject` with the provided argument.")
|
|
40
|
+
|
|
41
|
+
def _get_by_key(self, key: str) -> Optional[OBBject]:
|
|
42
|
+
"""Return the obbject with key."""
|
|
43
|
+
for obbject in self._obbjects:
|
|
44
|
+
if obbject.extra.get("register_key", "") == key:
|
|
45
|
+
return obbject
|
|
46
|
+
return None
|
|
47
|
+
|
|
48
|
+
def _get_by_index(self, idx: int) -> Optional[OBBject]:
|
|
33
49
|
"""Return the obbject at index idx."""
|
|
34
50
|
# the list should work as a stack
|
|
35
51
|
# i.e., the last element needs to be accessed by idx=0 and so on
|
|
36
52
|
reversed_list = list(reversed(self._obbjects))
|
|
53
|
+
|
|
54
|
+
# check if the index is out of bounds
|
|
55
|
+
if idx >= len(reversed_list):
|
|
56
|
+
return None
|
|
57
|
+
|
|
37
58
|
return reversed_list[idx]
|
|
38
59
|
|
|
39
60
|
def remove(self, idx: int = -1):
|
|
@@ -46,22 +67,24 @@ class Registry:
|
|
|
46
67
|
|
|
47
68
|
@property
|
|
48
69
|
def all(self) -> Dict[int, Dict]:
|
|
49
|
-
"""Return all obbjects in the registry"""
|
|
70
|
+
"""Return all obbjects in the registry."""
|
|
50
71
|
|
|
51
72
|
def _handle_standard_params(obbject: OBBject) -> str:
|
|
52
|
-
"""Handle standard params for obbjects"""
|
|
73
|
+
"""Handle standard params for obbjects."""
|
|
53
74
|
standard_params_json = ""
|
|
54
|
-
std_params =
|
|
55
|
-
|
|
75
|
+
std_params = getattr(
|
|
76
|
+
obbject, "_standard_params", {}
|
|
77
|
+
) # pylint: disable=protected-access
|
|
78
|
+
if std_params:
|
|
56
79
|
standard_params = {
|
|
57
|
-
k: str(v)[:30] for k, v in std_params.
|
|
80
|
+
k: str(v)[:30] for k, v in std_params.items() if v and k != "data"
|
|
58
81
|
}
|
|
59
82
|
standard_params_json = json.dumps(standard_params)
|
|
60
83
|
|
|
61
84
|
return standard_params_json
|
|
62
85
|
|
|
63
86
|
def _handle_data_repr(obbject: OBBject) -> str:
|
|
64
|
-
"""Handle data representation for obbjects"""
|
|
87
|
+
"""Handle data representation for obbjects."""
|
|
65
88
|
data_repr = ""
|
|
66
89
|
if hasattr(obbject, "results") and obbject.results:
|
|
67
90
|
data_schema = (
|
|
@@ -84,11 +107,21 @@ class Registry:
|
|
|
84
107
|
"standard params": _handle_standard_params(obbject),
|
|
85
108
|
"data": _handle_data_repr(obbject),
|
|
86
109
|
"command": obbject.extra.get("command", ""),
|
|
110
|
+
"key": obbject.extra.get("register_key", ""),
|
|
87
111
|
}
|
|
88
112
|
|
|
89
113
|
return obbjects
|
|
90
114
|
|
|
91
115
|
@property
|
|
92
116
|
def obbjects(self) -> List[OBBject]:
|
|
93
|
-
"""Return all obbjects in the registry"""
|
|
117
|
+
"""Return all obbjects in the registry."""
|
|
94
118
|
return self._obbjects
|
|
119
|
+
|
|
120
|
+
@property
|
|
121
|
+
def obbject_keys(self) -> List[str]:
|
|
122
|
+
"""Return all obbject keys in the registry."""
|
|
123
|
+
return [
|
|
124
|
+
obbject.extra["register_key"]
|
|
125
|
+
for obbject in self._obbjects
|
|
126
|
+
if "register_key" in obbject.extra
|
|
127
|
+
]
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
"""Module for the ReferenceToArgumentsProcessor class."""
|
|
2
2
|
|
|
3
|
+
# `ForwardRef`needs to be imported because the usage of `eval()`,
|
|
4
|
+
# which creates a ForwardRef
|
|
5
|
+
# which would raise a not defined error if it's not imported here.
|
|
6
|
+
# pylint: disable=unused-import
|
|
3
7
|
from typing import (
|
|
4
8
|
Any,
|
|
5
9
|
Dict,
|
|
10
|
+
ForwardRef, # noqa: F401
|
|
6
11
|
List,
|
|
7
12
|
Literal,
|
|
8
13
|
Optional,
|
|
@@ -59,9 +59,14 @@ def get_argument_optional_choices(parser: ArgumentParser, argument_name: str) ->
|
|
|
59
59
|
"""Get the optional_choices attribute of an argument from an ArgumentParser."""
|
|
60
60
|
for action in parser._actions: # pylint: disable=protected-access
|
|
61
61
|
opts = action.option_strings
|
|
62
|
-
if (
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
if (
|
|
63
|
+
(opts and opts[0] == argument_name)
|
|
64
|
+
or action.dest == argument_name
|
|
65
|
+
and hasattr(action, "optional_choices")
|
|
66
|
+
):
|
|
67
|
+
return (
|
|
68
|
+
action.optional_choices # type: ignore[attr-defined] # this is a custom attribute
|
|
69
|
+
)
|
|
65
70
|
return False
|
|
66
71
|
|
|
67
72
|
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
4
|
|
|
5
|
+
from openbb_cli.utils.utils import change_logging_sub_app, reset_logging_sub_app
|
|
6
|
+
|
|
5
7
|
|
|
6
8
|
def main():
|
|
7
9
|
"""Use the main entry point for the OpenBB Platform CLI."""
|
|
@@ -20,4 +22,10 @@ def main():
|
|
|
20
22
|
|
|
21
23
|
|
|
22
24
|
if __name__ == "__main__":
|
|
23
|
-
|
|
25
|
+
initial_logging_sub_app = change_logging_sub_app()
|
|
26
|
+
try:
|
|
27
|
+
main()
|
|
28
|
+
except Exception:
|
|
29
|
+
pass
|
|
30
|
+
finally:
|
|
31
|
+
reset_logging_sub_app(initial_logging_sub_app)
|
|
@@ -24,6 +24,7 @@ from openbb_cli.controllers.utils import (
|
|
|
24
24
|
print_rich_table,
|
|
25
25
|
remove_file,
|
|
26
26
|
system_clear,
|
|
27
|
+
validate_register_key,
|
|
27
28
|
)
|
|
28
29
|
from openbb_cli.session import Session
|
|
29
30
|
from prompt_toolkit.formatted_text import HTML
|
|
@@ -138,27 +139,10 @@ class BaseController(metaclass=ABCMeta):
|
|
|
138
139
|
|
|
139
140
|
def load_class(self, class_ins, *args, **kwargs):
|
|
140
141
|
"""Check for an existing instance of the controller before creating a new one."""
|
|
141
|
-
settings = session.settings
|
|
142
142
|
self.save_class()
|
|
143
143
|
arguments = len(args) + len(kwargs)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
# Advantage: If the user changes something on one controller and then goes to the
|
|
147
|
-
# controller below, it will create such class from scratch bringing all new variables
|
|
148
|
-
# in and considering latest changes.
|
|
149
|
-
# Disadvantage: If the user goes on a controller below and we have been there before
|
|
150
|
-
# it will not load that previous class, but create a new one from scratch.
|
|
151
|
-
# SCENARIO: If the user is in stocks and does load AAPL/ta the TA menu will get AAPL,
|
|
152
|
-
# and if then the user goes back to the stocks menu using .. that menu will have AAPL
|
|
153
|
-
# Now, if "arguments == 1" condition exists, if the user does "load TSLA" and then
|
|
154
|
-
# goes into "TA", the "TSLA" ticker will appear. If that condition doesn't exist
|
|
155
|
-
# the previous class will be loaded and even if the user changes the ticker on
|
|
156
|
-
# the stocks context it will not impact the one of TA menu - unless changes are done.
|
|
157
|
-
if (
|
|
158
|
-
class_ins.PATH in controllers
|
|
159
|
-
and arguments == 1
|
|
160
|
-
and settings.REMEMBER_CONTEXTS
|
|
161
|
-
):
|
|
144
|
+
|
|
145
|
+
if class_ins.PATH in controllers and arguments == 1:
|
|
162
146
|
old_class = controllers[class_ins.PATH]
|
|
163
147
|
old_class.queue = self.queue
|
|
164
148
|
return old_class.menu()
|
|
@@ -166,8 +150,7 @@ class BaseController(metaclass=ABCMeta):
|
|
|
166
150
|
|
|
167
151
|
def save_class(self) -> None:
|
|
168
152
|
"""Save the current instance of the class to be loaded later."""
|
|
169
|
-
|
|
170
|
-
controllers[self.PATH] = self
|
|
153
|
+
controllers[self.PATH] = self
|
|
171
154
|
|
|
172
155
|
def custom_reset(self) -> List[str]:
|
|
173
156
|
"""Implement custom reset.
|
|
@@ -646,19 +629,77 @@ class BaseController(metaclass=ABCMeta):
|
|
|
646
629
|
"'OBBjects' where all execution results are stored. "
|
|
647
630
|
"It is organized as a stack, with the most recent result at index 0.",
|
|
648
631
|
)
|
|
632
|
+
parser.add_argument("--index", dest="index", help="Index of the result.")
|
|
633
|
+
parser.add_argument("--key", dest="key", help="Key of the result.")
|
|
634
|
+
parser.add_argument(
|
|
635
|
+
"--chart", action="store_true", dest="chart", help="Display chart."
|
|
636
|
+
)
|
|
637
|
+
parser.add_argument(
|
|
638
|
+
"--export", dest="export", help="Export data.", nargs="+", default=None
|
|
639
|
+
)
|
|
640
|
+
|
|
649
641
|
ns_parser = self.parse_simple_args(parser, other_args)
|
|
650
642
|
if ns_parser:
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
643
|
+
if not ns_parser.index and not ns_parser.key:
|
|
644
|
+
results = session.obbject_registry.all
|
|
645
|
+
if results:
|
|
646
|
+
df = pd.DataFrame.from_dict(results, orient="index")
|
|
647
|
+
print_rich_table(
|
|
648
|
+
df,
|
|
649
|
+
show_index=True,
|
|
650
|
+
index_name="stack index",
|
|
651
|
+
title="OBBject Results",
|
|
652
|
+
)
|
|
653
|
+
else:
|
|
654
|
+
session.console.print("[info]No results found.[/info]")
|
|
655
|
+
elif ns_parser.index:
|
|
656
|
+
try:
|
|
657
|
+
index = int(ns_parser.index)
|
|
658
|
+
obbject = session.obbject_registry.get(index)
|
|
659
|
+
if obbject:
|
|
660
|
+
if ns_parser.chart and obbject.chart:
|
|
661
|
+
obbject.show()
|
|
662
|
+
else:
|
|
663
|
+
title = obbject.extra.get("command", "")
|
|
664
|
+
df = obbject.to_dataframe()
|
|
665
|
+
print_rich_table(
|
|
666
|
+
df=df,
|
|
667
|
+
show_index=True,
|
|
668
|
+
title=title,
|
|
669
|
+
export=ns_parser.export,
|
|
670
|
+
)
|
|
671
|
+
if ns_parser.chart and not obbject.chart:
|
|
672
|
+
session.console.print(
|
|
673
|
+
"[info]No chart available.[/info]"
|
|
674
|
+
)
|
|
675
|
+
else:
|
|
676
|
+
session.console.print(
|
|
677
|
+
f"[info]No result found at index {index}.[/info]"
|
|
678
|
+
)
|
|
679
|
+
except ValueError:
|
|
680
|
+
session.console.print(
|
|
681
|
+
f"[red]Index must be an integer, not '{ns_parser.index}'.[/red]"
|
|
682
|
+
)
|
|
683
|
+
elif ns_parser.key:
|
|
684
|
+
obbject = session.obbject_registry.get(ns_parser.key)
|
|
685
|
+
if obbject:
|
|
686
|
+
if ns_parser.chart and obbject.chart:
|
|
687
|
+
obbject.show()
|
|
688
|
+
else:
|
|
689
|
+
title = obbject.extra.get("command", "")
|
|
690
|
+
df = obbject.to_dataframe()
|
|
691
|
+
print_rich_table(
|
|
692
|
+
df=df,
|
|
693
|
+
show_index=True,
|
|
694
|
+
title=title,
|
|
695
|
+
export=ns_parser.export,
|
|
696
|
+
)
|
|
697
|
+
if ns_parser.chart and not obbject.chart:
|
|
698
|
+
session.console.print("[info]No chart available.[/info]")
|
|
699
|
+
else:
|
|
700
|
+
session.console.print(
|
|
701
|
+
f"[info]No result found with key '{ns_parser.key}'.[/info]"
|
|
702
|
+
)
|
|
662
703
|
|
|
663
704
|
@staticmethod
|
|
664
705
|
def parse_simple_args(parser: argparse.ArgumentParser, other_args: List[str]):
|
|
@@ -792,6 +833,22 @@ class BaseController(metaclass=ABCMeta):
|
|
|
792
833
|
help="Number of entries to show in data.",
|
|
793
834
|
type=check_positive,
|
|
794
835
|
)
|
|
836
|
+
|
|
837
|
+
parser.add_argument(
|
|
838
|
+
"--register_obbject",
|
|
839
|
+
dest="register_obbject",
|
|
840
|
+
action="store_false",
|
|
841
|
+
default=True,
|
|
842
|
+
help="Flag to store data in the OBBject registry, True by default.",
|
|
843
|
+
)
|
|
844
|
+
parser.add_argument(
|
|
845
|
+
"--register_key",
|
|
846
|
+
dest="register_key",
|
|
847
|
+
default="",
|
|
848
|
+
help="Key to reference data in the OBBject registry.",
|
|
849
|
+
type=validate_register_key,
|
|
850
|
+
)
|
|
851
|
+
|
|
795
852
|
if session.settings.USE_CLEAR_AFTER_CMD:
|
|
796
853
|
system_clear()
|
|
797
854
|
|
|
@@ -75,20 +75,31 @@ class PlatformController(BaseController):
|
|
|
75
75
|
for _, trl in self.translators.items():
|
|
76
76
|
for action in trl._parser._actions: # pylint: disable=protected-access
|
|
77
77
|
if action.dest == "data":
|
|
78
|
+
# Generate choices by combining indexed and key-based choices
|
|
78
79
|
action.choices = [
|
|
79
80
|
"OBB" + str(i)
|
|
80
81
|
for i in range(len(session.obbject_registry.obbjects))
|
|
82
|
+
] + [
|
|
83
|
+
obbject.extra["register_key"]
|
|
84
|
+
for obbject in session.obbject_registry.obbjects
|
|
85
|
+
if "register_key" in obbject.extra
|
|
81
86
|
]
|
|
87
|
+
|
|
82
88
|
action.type = str
|
|
83
89
|
action.nargs = None
|
|
84
90
|
|
|
85
91
|
def _intersect_data_processing_commands(self, ns_parser):
|
|
86
92
|
"""Intersect data processing commands and change the obbject id into an actual obbject."""
|
|
87
93
|
if hasattr(ns_parser, "data"):
|
|
88
|
-
|
|
89
|
-
|
|
94
|
+
if "OBB" in ns_parser.data:
|
|
95
|
+
ns_parser.data = int(ns_parser.data.replace("OBB", ""))
|
|
96
|
+
|
|
97
|
+
if (ns_parser.data in range(len(session.obbject_registry.obbjects))) or (
|
|
98
|
+
ns_parser.data in session.obbject_registry.obbject_keys
|
|
99
|
+
):
|
|
90
100
|
obbject = session.obbject_registry.get(ns_parser.data)
|
|
91
|
-
|
|
101
|
+
if obbject and isinstance(obbject, OBBject):
|
|
102
|
+
setattr(ns_parser, "data", obbject.results)
|
|
92
103
|
|
|
93
104
|
return ns_parser
|
|
94
105
|
|
|
@@ -151,6 +162,11 @@ class PlatformController(BaseController):
|
|
|
151
162
|
):
|
|
152
163
|
try:
|
|
153
164
|
ns_parser = self._intersect_data_processing_commands(ns_parser)
|
|
165
|
+
export = hasattr(ns_parser, "export") and ns_parser.export
|
|
166
|
+
store_obbject = (
|
|
167
|
+
hasattr(ns_parser, "register_obbject")
|
|
168
|
+
and ns_parser.register_obbject
|
|
169
|
+
)
|
|
154
170
|
|
|
155
171
|
obbject = translator.execute_func(parsed_args=ns_parser)
|
|
156
172
|
df: pd.DataFrame = pd.DataFrame()
|
|
@@ -159,7 +175,11 @@ class PlatformController(BaseController):
|
|
|
159
175
|
|
|
160
176
|
if obbject:
|
|
161
177
|
if isinstance(obbject, OBBject):
|
|
162
|
-
if
|
|
178
|
+
if (
|
|
179
|
+
session.max_obbjects_exceeded()
|
|
180
|
+
and obbject.results
|
|
181
|
+
and store_obbject
|
|
182
|
+
):
|
|
163
183
|
session.obbject_registry.remove()
|
|
164
184
|
session.console.print(
|
|
165
185
|
"[yellow]Maximum number of OBBjects reached. The oldest entry was removed.[yellow]"
|
|
@@ -167,48 +187,69 @@ class PlatformController(BaseController):
|
|
|
167
187
|
|
|
168
188
|
# use the obbject to store the command so we can display it later on results
|
|
169
189
|
obbject.extra["command"] = f"{title} {' '.join(other_args)}"
|
|
170
|
-
|
|
171
|
-
register_result = session.obbject_registry.register(obbject)
|
|
172
|
-
|
|
173
|
-
# we need to force to re-link so that the new obbject
|
|
174
|
-
# is immediately available for data processing commands
|
|
175
|
-
self._link_obbject_to_data_processing_commands()
|
|
176
|
-
# also update the completer
|
|
177
|
-
self.update_completer(self.choices_default)
|
|
178
|
-
|
|
190
|
+
# if there is a registry key in the parser, store to the obbject
|
|
179
191
|
if (
|
|
180
|
-
|
|
181
|
-
and
|
|
192
|
+
hasattr(ns_parser, "register_key")
|
|
193
|
+
and ns_parser.register_key
|
|
182
194
|
):
|
|
183
|
-
|
|
184
|
-
|
|
195
|
+
if (
|
|
196
|
+
ns_parser.register_key
|
|
197
|
+
not in session.obbject_registry.obbject_keys
|
|
198
|
+
):
|
|
199
|
+
obbject.extra["register_key"] = str(
|
|
200
|
+
ns_parser.register_key
|
|
201
|
+
)
|
|
202
|
+
else:
|
|
203
|
+
session.console.print(
|
|
204
|
+
f"[yellow]Key `{ns_parser.register_key}` already exists in the registry."
|
|
205
|
+
"The `OBBject` was kept without the key.[/yellow]"
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
if store_obbject:
|
|
209
|
+
# store the obbject in the registry
|
|
210
|
+
register_result = session.obbject_registry.register(
|
|
211
|
+
obbject
|
|
185
212
|
)
|
|
186
213
|
|
|
187
|
-
|
|
188
|
-
|
|
214
|
+
# we need to force to re-link so that the new obbject
|
|
215
|
+
# is immediately available for data processing commands
|
|
216
|
+
self._link_obbject_to_data_processing_commands()
|
|
217
|
+
# also update the completer
|
|
218
|
+
self.update_completer(self.choices_default)
|
|
219
|
+
|
|
220
|
+
if (
|
|
221
|
+
session.settings.SHOW_MSG_OBBJECT_REGISTRY
|
|
222
|
+
and register_result
|
|
223
|
+
):
|
|
224
|
+
session.console.print(
|
|
225
|
+
"Added `OBBject` to cached results."
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
# making the dataframe available either for printing or exporting
|
|
189
229
|
df = obbject.to_dataframe()
|
|
190
230
|
|
|
191
231
|
if hasattr(ns_parser, "chart") and ns_parser.chart:
|
|
192
|
-
obbject.show()
|
|
193
232
|
fig = obbject.chart.fig if obbject.chart else None
|
|
233
|
+
if not export:
|
|
234
|
+
obbject.show()
|
|
194
235
|
else:
|
|
195
236
|
if isinstance(df.columns, pd.RangeIndex):
|
|
196
237
|
df.columns = [str(i) for i in df.columns]
|
|
197
238
|
|
|
198
|
-
print_rich_table(
|
|
239
|
+
print_rich_table(
|
|
240
|
+
df=df, show_index=True, title=title, export=export
|
|
241
|
+
)
|
|
199
242
|
|
|
200
243
|
elif isinstance(obbject, dict):
|
|
201
244
|
df = pd.DataFrame.from_dict(obbject, orient="columns")
|
|
202
|
-
print_rich_table(
|
|
245
|
+
print_rich_table(
|
|
246
|
+
df=df, show_index=True, title=title, export=export
|
|
247
|
+
)
|
|
203
248
|
|
|
204
249
|
elif not isinstance(obbject, OBBject):
|
|
205
250
|
session.console.print(obbject)
|
|
206
251
|
|
|
207
|
-
if
|
|
208
|
-
hasattr(ns_parser, "export")
|
|
209
|
-
and ns_parser.export
|
|
210
|
-
and not df.empty
|
|
211
|
-
):
|
|
252
|
+
if export and not df.empty:
|
|
212
253
|
sheet_name = getattr(ns_parser, "sheet_name", None)
|
|
213
254
|
if sheet_name and isinstance(sheet_name, list):
|
|
214
255
|
sheet_name = sheet_name[0]
|
|
@@ -221,7 +262,7 @@ class PlatformController(BaseController):
|
|
|
221
262
|
sheet_name=sheet_name,
|
|
222
263
|
figure=fig,
|
|
223
264
|
)
|
|
224
|
-
elif
|
|
265
|
+
elif export and df.empty:
|
|
225
266
|
session.console.print("[yellow]No data to export.[/yellow]")
|
|
226
267
|
|
|
227
268
|
except Exception as e:
|
|
@@ -10,6 +10,7 @@ from unittest.mock import patch
|
|
|
10
10
|
from openbb_cli.controllers.utils import (
|
|
11
11
|
check_file_type_saved,
|
|
12
12
|
check_positive,
|
|
13
|
+
validate_register_key,
|
|
13
14
|
)
|
|
14
15
|
from openbb_cli.session import Session
|
|
15
16
|
|
|
@@ -93,6 +94,21 @@ def __mock_parse_known_args_and_warn(
|
|
|
93
94
|
type=check_positive,
|
|
94
95
|
)
|
|
95
96
|
|
|
97
|
+
parser.add_argument(
|
|
98
|
+
"--register_obbject",
|
|
99
|
+
dest="register_obbject",
|
|
100
|
+
action="store_false",
|
|
101
|
+
default=True,
|
|
102
|
+
help="Flag to store data in the OBBject registry, True by default.",
|
|
103
|
+
)
|
|
104
|
+
parser.add_argument(
|
|
105
|
+
"--register_key",
|
|
106
|
+
dest="register_key",
|
|
107
|
+
default="",
|
|
108
|
+
help="Key to reference data in the OBBject registry.",
|
|
109
|
+
type=validate_register_key,
|
|
110
|
+
)
|
|
111
|
+
|
|
96
112
|
|
|
97
113
|
def __mock_parse_simple_args(parser: ArgumentParser, other_args: List[str]) -> None:
|
|
98
114
|
"""Add arguments.
|
|
@@ -274,6 +290,7 @@ def _get_argument_parser(
|
|
|
274
290
|
" - parse_known_args_and_warn\n"
|
|
275
291
|
)
|
|
276
292
|
|
|
293
|
+
# pylint: disable=possibly-used-before-assignment
|
|
277
294
|
return argument_parser
|
|
278
295
|
|
|
279
296
|
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import argparse
|
|
5
5
|
import contextlib
|
|
6
6
|
import difflib
|
|
7
|
-
import logging
|
|
8
7
|
import os
|
|
9
8
|
import re
|
|
10
9
|
import sys
|
|
@@ -59,8 +58,6 @@ DATA_PROCESSING_ROUTERS = ["technical", "quantitative", "econometrics"]
|
|
|
59
58
|
# pylint: disable=too-many-public-methods,import-outside-toplevel, too-many-function-args
|
|
60
59
|
# pylint: disable=too-many-branches,no-member,C0302,too-many-return-statements, inconsistent-return-statements
|
|
61
60
|
|
|
62
|
-
logger = logging.getLogger(__name__)
|
|
63
|
-
|
|
64
61
|
env_file = str(ENV_FILE_SETTINGS)
|
|
65
62
|
session = Session()
|
|
66
63
|
|
|
@@ -205,7 +202,14 @@ class CLIController(BaseController):
|
|
|
205
202
|
"-h": "--help",
|
|
206
203
|
}
|
|
207
204
|
choices["stop"] = {"--help": None, "-h": "--help"}
|
|
208
|
-
choices["results"] = {
|
|
205
|
+
choices["results"] = {
|
|
206
|
+
"--help": None,
|
|
207
|
+
"-h": "--help",
|
|
208
|
+
"--export": None,
|
|
209
|
+
"--index": None,
|
|
210
|
+
"--key": None,
|
|
211
|
+
"--chart": None,
|
|
212
|
+
}
|
|
209
213
|
|
|
210
214
|
self.update_completer(choices)
|
|
211
215
|
|
|
@@ -291,7 +295,7 @@ class CLIController(BaseController):
|
|
|
291
295
|
: session.settings.N_TO_DISPLAY_OBBJECT_REGISTRY
|
|
292
296
|
]:
|
|
293
297
|
mt.add_raw(
|
|
294
|
-
f"[yellow]OBB{key}[/yellow]: {value['command']}",
|
|
298
|
+
f"[yellow]OBB{key}[/yellow]: {value['command']}", # type: ignore[index]
|
|
295
299
|
left_spacing=True,
|
|
296
300
|
)
|
|
297
301
|
|
|
@@ -497,11 +501,6 @@ class CLIController(BaseController):
|
|
|
497
501
|
|
|
498
502
|
def handle_job_cmds(jobs_cmds: Optional[List[str]]) -> Optional[List[str]]:
|
|
499
503
|
"""Handle job commands."""
|
|
500
|
-
# If the path selected does not start from the user root,
|
|
501
|
-
# give relative location from root
|
|
502
|
-
if jobs_cmds is not None and jobs_cmds:
|
|
503
|
-
logger.info("INPUT: %s", "/".join(jobs_cmds))
|
|
504
|
-
|
|
505
504
|
export_path = ""
|
|
506
505
|
if jobs_cmds and "export" in jobs_cmds[0]:
|
|
507
506
|
commands = jobs_cmds[0].split("/")
|
|
@@ -619,10 +618,6 @@ def run_cli(jobs_cmds: Optional[List[str]] = None, test_mode=False):
|
|
|
619
618
|
break
|
|
620
619
|
|
|
621
620
|
except SystemExit:
|
|
622
|
-
logger.exception(
|
|
623
|
-
"The command '%s' doesn't exist on the / menu.",
|
|
624
|
-
an_input,
|
|
625
|
-
)
|
|
626
621
|
session.console.print(
|
|
627
622
|
f"[red]The command '{an_input}' doesn't exist on the / menu.[/red]\n",
|
|
628
623
|
)
|
|
@@ -769,7 +764,6 @@ def replace_dynamic(match: re.Match, special_arguments: Dict[str, str]) -> str:
|
|
|
769
764
|
str
|
|
770
765
|
The new string
|
|
771
766
|
"""
|
|
772
|
-
|
|
773
767
|
cleaned = match[0].replace("{", "").replace("}", "").replace("$", "")
|
|
774
768
|
key, default = cleaned.split("=")
|
|
775
769
|
dict_value = special_arguments.get(key, default)
|
|
@@ -939,7 +933,6 @@ def launch(
|
|
|
939
933
|
debug: bool = False, dev: bool = False, queue: Optional[List[str]] = None
|
|
940
934
|
) -> None:
|
|
941
935
|
"""Launch CLI."""
|
|
942
|
-
|
|
943
936
|
if queue:
|
|
944
937
|
main(debug, dev, queue, module="")
|
|
945
938
|
else:
|