diff --git a/openbb_terminal/account/account_controller.py b/openbb_terminal/account/account_controller.py
index 3e28aec91f14..eb27adf79c5a 100644
--- a/openbb_terminal/account/account_controller.py
+++ b/openbb_terminal/account/account_controller.py
@@ -53,7 +53,7 @@ def update_runtime_choices(self):
"""Update runtime choices"""
self.ROUTINE_FILES = self.get_routines()
if session and obbff.USE_PROMPT_TOOLKIT:
- choices: dict = {c: {} for c in self.controller_choices}
+ choices: dict = {c: {} for c in self.controller_choices} # type: ignore
choices["sync"] = {"--on": {}, "--off": {}}
choices["upload"]["--file"] = {c: {} for c in self.ROUTINE_FILES}
choices["upload"]["-f"] = choices["upload"]["--file"]
diff --git a/openbb_terminal/core/log/collection/log_sender.py b/openbb_terminal/core/log/collection/log_sender.py
index 11fef8556be7..4634ace84da8 100644
--- a/openbb_terminal/core/log/collection/log_sender.py
+++ b/openbb_terminal/core/log/collection/log_sender.py
@@ -68,7 +68,7 @@ def run(self):
identifier = app_settings.identifier
while True:
- item: QueueItem = queue.get()
+ item: QueueItem = queue.get() # type: ignore
file = item.path
last = item.last
diff --git a/openbb_terminal/economy/economy_controller.py b/openbb_terminal/economy/economy_controller.py
index d1bf1e4f77ae..e36f6640c58d 100644
--- a/openbb_terminal/economy/economy_controller.py
+++ b/openbb_terminal/economy/economy_controller.py
@@ -1666,7 +1666,7 @@ def call_qa(self, _):
QaController,
)
- data: Dict = {}
+ data: Dict = {} # type: ignore
for source, _ in self.DATASETS.items():
if not self.DATASETS[source].empty:
if len(self.DATASETS[source].columns) == 1:
diff --git a/openbb_terminal/forecast/forecast_controller.py b/openbb_terminal/forecast/forecast_controller.py
index 09225edaf85e..9ebc1071bd46 100644
--- a/openbb_terminal/forecast/forecast_controller.py
+++ b/openbb_terminal/forecast/forecast_controller.py
@@ -232,7 +232,7 @@ def update_runtime_choices(self):
# Load in any newly exported files
self.DATA_FILES = forecast_model.get_default_files()
if session and obbff.USE_PROMPT_TOOLKIT:
- choices: dict = self.choices_default
+ choices: dict = self.choices_default # type: ignore
self.choices = choices
self.completer = NestedCompleter.from_nested_dict(choices)
diff --git a/openbb_terminal/reports/reports_controller.py b/openbb_terminal/reports/reports_controller.py
index fd0f5355a02e..dbb6d83dc435 100644
--- a/openbb_terminal/reports/reports_controller.py
+++ b/openbb_terminal/reports/reports_controller.py
@@ -59,7 +59,7 @@ def update_choices(self):
)
if session and obbff.USE_PROMPT_TOOLKIT:
- self.choices: dict = {c: {} for c in self.controller_choices}
+ self.choices: dict = {c: {} for c in self.controller_choices} # type: ignore
self.choices["run"] = {
"--file": {c: None for c in reports_model.USER_REPORTS},
"-f": "--file",
diff --git a/openbb_terminal/sdk_core/sdk_helpers.py b/openbb_terminal/sdk_core/sdk_helpers.py
index 7fef5ee4b984..0d86bbc2fd3e 100644
--- a/openbb_terminal/sdk_core/sdk_helpers.py
+++ b/openbb_terminal/sdk_core/sdk_helpers.py
@@ -1,5 +1,6 @@
"""OpenBB Terminal SDK Helpers."""
import json
+from inspect import signature
from logging import Logger, getLogger
from typing import Any, Callable, Dict, Optional
@@ -15,6 +16,7 @@
OPTIMIZATION_TOOLKIT_ENABLED,
OPTIMIZATION_TOOLKIT_WARNING,
)
+from openbb_terminal.session.sdk_session import login
if not FORECASTING_TOOLKIT_ENABLED and not load_env_vars(
"OPENBB_DISABLE_FORECASTING_WARNING", strtobool, False
@@ -51,23 +53,49 @@ def class_repr(cls_dict: Dict[str, Any]) -> list:
]
-def helptext(func: Callable) -> Callable:
- """Wrapper to preserve the help text of the function."""
+class Operation:
+ def __init__(self, name: str, trail: str, func: Callable) -> None:
+ self._trail = trail
+ self._method = func
+ self._name = name
- def decorator(f: Callable) -> Callable:
for attr in [
"__doc__",
"__name__",
"__annotations__",
- "__module__",
"__defaults__",
"__kwdefaults__",
- "__dict__",
+ "__module__",
]:
- setattr(f, attr, getattr(func, attr))
- return f
+ setattr(self.__class__, attr, getattr(func, attr))
+ setattr(self, attr, getattr(func, attr))
+
+ self.__signature__ = signature(func)
+ self.__class__.__signature__ = signature(func)
+
+ def __call__(self, *args: Any, **kwargs: Any) -> Any:
+ method = self._method
+
+ # We make a copy of the kwargs to avoid modifying the original
+ log_kwargs = kwargs.copy()
+ log_kwargs["chart"] = "chart" in self._name
+
+ operation_logger = OperationLogger(
+ trail=self._trail, method_chosen=method, args=args, kwargs=log_kwargs
+ )
+ operation_logger.log_before_call()
+ method_result = method(*args, **kwargs)
+ operation_logger.log_after_call(method_result=method_result)
+
+ return method_result
+
+ def about(self):
+ # pylint: disable=C0415
+ import webbrowser
- return decorator
+ trail = "/".join(self._trail.split("."))
+ url = f"https://docs.openbb.co/sdk/reference/{trail}"
+ webbrowser.open(url)
class Category:
@@ -93,33 +121,27 @@ def __getattribute__(self, name: str):
"""We override the __getattribute__ method and wrap all callable
attributes with a wrapper that logs the call and the result.
"""
- if name.startswith("_"):
- return super().__getattribute__(name)
-
attr = super().__getattribute__(name)
- trail = f"{self.__class__._location_path}.{name}"
-
- if callable(attr):
+ if isinstance(attr, Operation) or name.startswith("__"):
+ return attr
- @helptext(attr)
- def wrapper(*args, **kwargs):
- method = attr
+ trail = f"{self.__class__._location_path}.{name}"
- # We make a copy of the kwargs to avoid modifying the original
- log_kwargs = kwargs.copy()
- log_kwargs["chart"] = "chart" in name
+ if callable(attr) and not isinstance(attr, Operation):
+ # We set the attribute to the wrapped function so that we don't
+ # have to wrap it when called again.
+ setattr(self, name, Operation(name=name, trail=trail, func=attr))
+ return getattr(self, name)
- operation_logger = OperationLogger(
- trail=trail, method_chosen=method, args=args, kwargs=log_kwargs
- )
- operation_logger.log_before_call()
- method_result = method(*args, **kwargs)
- operation_logger.log_after_call(method_result=method_result)
+ return attr
- return method_result
+ def about(self):
+ # pylint: disable=C0415
+ import webbrowser
- return wrapper
- return attr
+ trail = "/".join(self._location_path.split("."))
+ url = f"https://docs.openbb.co/sdk/reference/{trail}"
+ webbrowser.open(url)
class OperationLogger:
@@ -257,6 +279,9 @@ def log_after_call(
method_result=method_result,
method_chosen=self.__method_chosen,
)
+ self.__log_if_login(
+ method_chosen=self.__method_chosen,
+ )
self.__log_end(
logger=logger,
method_chosen=self.__method_chosen,
@@ -280,6 +305,17 @@ def __log_exception_if_any(
extra={"func_name_override": method_chosen.__name__},
)
+ @staticmethod
+ def __log_if_login(
+ method_chosen: Callable,
+ ):
+ if method_chosen.__name__ == login.__name__:
+ from openbb_terminal.core.log.generation.user_logger import ( # pylint: disable=import-outside-toplevel
+ log_user,
+ )
+
+ log_user(with_rollover=False)
+
@staticmethod
def __log_end(logger: Logger, method_chosen: Callable):
logger.info(
diff --git a/openbb_terminal/stocks/options/hedge/hedge_controller.py b/openbb_terminal/stocks/options/hedge/hedge_controller.py
index bd2faf4b0d9f..0ccd93d9b1e0 100644
--- a/openbb_terminal/stocks/options/hedge/hedge_controller.py
+++ b/openbb_terminal/stocks/options/hedge/hedge_controller.py
@@ -502,7 +502,7 @@ def call_sop(self, other_args):
for _, value in self.options.items():
if value:
- option_side: str = "Long" if value["sign"] == 1 else "Short"
+ option_side: str = "Long" if value["sign"] == 1 else "Short" # type: ignore
positions = positions.append(
[
[
diff --git a/openbb_terminal/terminal_controller.py b/openbb_terminal/terminal_controller.py
index 0b11ee2dbdd5..af8e86cd10ef 100644
--- a/openbb_terminal/terminal_controller.py
+++ b/openbb_terminal/terminal_controller.py
@@ -151,7 +151,7 @@ def update_runtime_choices(self):
self.ROUTINE_CHOICES["--h"] = None
if session and obbff.USE_PROMPT_TOOLKIT:
- choices: dict = {c: {} for c in self.controller_choices}
+ choices: dict = {c: {} for c in self.controller_choices} # type: ignore
choices["support"] = self.SUPPORT_CHOICES
choices["exe"] = self.ROUTINE_CHOICES
choices["news"] = self.NEWS_CHOICES
diff --git a/website/content/sdk/quickstart/pypi.md b/website/content/sdk/quickstart/pypi.md
index d07592c2d8ff..575b6b471da5 100644
--- a/website/content/sdk/quickstart/pypi.md
+++ b/website/content/sdk/quickstart/pypi.md
@@ -3,7 +3,7 @@
| OpenBB is committed to build the future of investment research by focusing on an open source infrastructure accessible to everyone, everywhere. |
|:--:|
-| |
+| ![OpenBBLogo](https://user-images.githubusercontent.com/25267873/218899768-1f0964b8-326c-4f35-af6f-ea0946ac970b.png) |
| Check our website at [openbb.co](www.openbb.co) |
@@ -41,10 +41,10 @@ ___
Access raw financial data from any data source that you are interested. The open source nature of this SDK makes it so that this is an ever-growing project and that everyone can contribute to.
-![image-20221025-092439 2](https://user-images.githubusercontent.com/25267873/218906336-cebd1fc8-7e7a-45bc-a5fc-641eb19c3e8c.png)
+![Stocks Load](https://user-images.githubusercontent.com/25267873/218906336-cebd1fc8-7e7a-45bc-a5fc-641eb19c3e8c.png)
#### GENERATE INSIGHTS 10X FASTER
For most of the functionalities, adding `_chart` to the function will allow you to visualize the output directly from a Jupyter Notebook. Not only speeding up the time it takes to create a plot for the data you are interested in, but making building custom reports much faster.
-
+![Economy Treasury Chart](https://user-images.githubusercontent.com/25267873/218906112-b2272d43-11fc-4ec1-9a8f-b2d8e2ed7dc1.png)