Skip to content

Commit

Permalink
SDK Added about() for methods and class, fixed pypi.md (#4273)
Browse files Browse the repository at this point in the history
* added log_if_login and about() for methods and class, fix pypi.md

* Update sdk_helpers.py

* mypy
  • Loading branch information
tehcoderer authored Feb 17, 2023
1 parent bbeaef4 commit 96af407
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 39 deletions.
2 changes: 1 addition & 1 deletion openbb_terminal/account/account_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/core/log/collection/log_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/economy/economy_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/forecast/forecast_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/reports/reports_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
94 changes: 65 additions & 29 deletions openbb_terminal/sdk_core/sdk_helpers.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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
Expand Down Expand Up @@ -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:
Expand All @@ -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:
Expand Down Expand Up @@ -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,
Expand All @@ -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(
Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/stocks/options/hedge/hedge_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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(
[
[
Expand Down
2 changes: 1 addition & 1 deletion openbb_terminal/terminal_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions website/content/sdk/quickstart/pypi.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
|:--:|
| <img width="1000" alt="Screenshot 2023-02-14 at 5 12 08 PM" src="https://user-images.githubusercontent.com/25267873/218899768-1f0964b8-326c-4f35-af6f-ea0946ac970b.png"> |
| ![OpenBBLogo](https://user-images.githubusercontent.com/25267873/218899768-1f0964b8-326c-4f35-af6f-ea0946ac970b.png) |
| Check our website at [openbb.co](www.openbb.co) |


Expand Down Expand Up @@ -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.

<img width="992" alt="Group 550" src="https://user-images.githubusercontent.com/25267873/218906112-b2272d43-11fc-4ec1-9a8f-b2d8e2ed7dc1.png">
![Economy Treasury Chart](https://user-images.githubusercontent.com/25267873/218906112-b2272d43-11fc-4ec1-9a8f-b2d8e2ed7dc1.png)

0 comments on commit 96af407

Please sign in to comment.