mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-28 21:12:16 +00:00
* fix(docs): added margin between sections * fix: about command * fix: about command to match new docs * sdk aout * fix: fix homepage * fix: features -> reference on generate; about on homepage * fix: juan magic * update on merge workflows Co-authored-by: James Maslek <jmaslek11@gmail.com> Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com> Co-authored-by: Diogo Sousa <montezdesousa@gmail.com> Co-authored-by: teh_coderer <me@tehcoderer.com>
296 lines
8.2 KiB
Python
296 lines
8.2 KiB
Python
import json
|
|
from importlib import import_module
|
|
from logging import getLogger, Logger
|
|
from typing import Any, Callable, Dict, List, Optional
|
|
|
|
from inspect import signature
|
|
|
|
import openbb_terminal.config_terminal as cfg
|
|
|
|
from openbb_terminal.core.library.metadata import Metadata
|
|
from openbb_terminal.core.library.trail_map import TrailMap
|
|
|
|
# pylint: disable=import-outside-toplevel
|
|
|
|
|
|
class MetadataBuilder:
|
|
def __init__(
|
|
self,
|
|
method: Callable,
|
|
trail: str,
|
|
trail_map: TrailMap,
|
|
) -> None:
|
|
self.__method = method
|
|
self.__trail = trail
|
|
self.__trail_map = trail_map
|
|
|
|
@staticmethod
|
|
def build_docstring(
|
|
method: Callable,
|
|
trail: str,
|
|
trail_map: TrailMap,
|
|
) -> str:
|
|
doc = ""
|
|
|
|
view_trail = f"{trail}_chart"
|
|
if trail_map.get_view_function(view_trail):
|
|
doc += f"Use '{view_trail}' to access the view.\n"
|
|
|
|
if method.__doc__:
|
|
doc += method.__doc__
|
|
|
|
return doc
|
|
|
|
def build(self) -> Metadata:
|
|
method = self.__method
|
|
trail = self.__trail
|
|
trail_map = self.__trail_map
|
|
|
|
dir_list: List[str] = []
|
|
docstring = self.build_docstring(
|
|
method=method,
|
|
trail=trail,
|
|
trail_map=trail_map,
|
|
)
|
|
metadata = Metadata(dir_list=dir_list, docstring=docstring)
|
|
|
|
return metadata
|
|
|
|
|
|
class Operation:
|
|
@staticmethod
|
|
def __get_method(method_path: str) -> Callable:
|
|
module_path, function_name = method_path.rsplit(".", 1)
|
|
module = import_module(module_path)
|
|
func = getattr(module, function_name)
|
|
|
|
return func
|
|
|
|
def __init__(
|
|
self,
|
|
trail: str,
|
|
trail_map: Optional[TrailMap] = None,
|
|
metadata: Optional[Metadata] = None,
|
|
) -> None:
|
|
trail_map = trail_map or TrailMap()
|
|
|
|
method_path = trail_map.get_model_or_view(trail=trail)
|
|
method = self.__get_method(method_path=method_path)
|
|
metadata = (
|
|
metadata
|
|
or MetadataBuilder(method=method, trail=trail, trail_map=trail_map).build()
|
|
)
|
|
|
|
self._trail = trail
|
|
self._trail_map = trail_map
|
|
self._method = method
|
|
self.__doc__ = metadata.docstring
|
|
self.__signature__ = signature(method)
|
|
|
|
def __call__(self, *args: Any, **kwargs: Any) -> Any:
|
|
method = self._method
|
|
|
|
operation_logger = OperationLogger(
|
|
trail=self._trail,
|
|
method_chosen=method,
|
|
args=args,
|
|
kwargs=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):
|
|
import webbrowser
|
|
|
|
trail = self._trail
|
|
url = "https://docs.openbb.co/sdk/reference/"
|
|
url += "/".join(trail.split("."))
|
|
webbrowser.open(url)
|
|
|
|
|
|
class OperationLogger:
|
|
|
|
last_method: Dict[Any, Any] = {}
|
|
|
|
def __init__(
|
|
self,
|
|
trail: str,
|
|
method_chosen: Callable,
|
|
args: Any,
|
|
kwargs: Any,
|
|
logger: Optional[Logger] = None,
|
|
) -> None:
|
|
self.__trail = trail
|
|
self.__method_chosen = method_chosen
|
|
self.__logger = logger or getLogger(self.__method_chosen.__module__)
|
|
self.__args = args
|
|
self.__kwargs = kwargs
|
|
|
|
def log_before_call(
|
|
self,
|
|
):
|
|
if self.__check_logging_conditions():
|
|
logger = self.__logger
|
|
self.__log_start(logger=logger, method_chosen=self.__method_chosen)
|
|
self.__log_method_info(
|
|
logger=logger,
|
|
trail=self.__trail,
|
|
method_chosen=self.__method_chosen,
|
|
args=self.__args,
|
|
kwargs=self.__kwargs,
|
|
)
|
|
|
|
@staticmethod
|
|
def __log_start(logger: Logger, method_chosen: Callable):
|
|
logger.info(
|
|
"START",
|
|
extra={"func_name_override": method_chosen.__name__},
|
|
)
|
|
|
|
def __log_method_info(
|
|
self,
|
|
logger: Logger,
|
|
trail: str,
|
|
method_chosen: Callable,
|
|
args: Any,
|
|
kwargs: Any,
|
|
):
|
|
merged_args = self.__merge_function_args(method_chosen, args, kwargs)
|
|
merged_args = self.__remove_key_and_log_state(
|
|
method_chosen.__module__, merged_args
|
|
)
|
|
|
|
logging_info: Dict[str, Any] = {}
|
|
logging_info["INPUT"] = {
|
|
key: str(value)[:100] for key, value in merged_args.items()
|
|
}
|
|
logging_info["VIRTUAL_PATH"] = trail
|
|
logging_info["CHART"] = "chart" in kwargs and kwargs["chart"] is True
|
|
|
|
logger.info(
|
|
f"{json.dumps(logging_info)}",
|
|
extra={"func_name_override": method_chosen.__name__},
|
|
)
|
|
|
|
@staticmethod
|
|
def __merge_function_args(func: Callable, args: tuple, kwargs: dict) -> dict:
|
|
"""
|
|
Merge user input args and kwargs with signature defaults into a dictionary.
|
|
|
|
Parameters
|
|
----------
|
|
|
|
func : Callable
|
|
Function to get the args from
|
|
args : tuple
|
|
Positional args
|
|
kwargs : dict
|
|
Keyword args
|
|
|
|
Returns
|
|
----------
|
|
dict
|
|
Merged user args and signature defaults
|
|
"""
|
|
import inspect # pylint: disable=C0415
|
|
|
|
sig = inspect.signature(func)
|
|
sig_args = {
|
|
param.name: param.default
|
|
for param in sig.parameters.values()
|
|
if param.default is not inspect.Parameter.empty
|
|
}
|
|
# merge args with sig_args
|
|
sig_args.update(dict(zip(sig.parameters, args)))
|
|
# add kwargs elements to sig_args
|
|
sig_args.update(kwargs)
|
|
return sig_args
|
|
|
|
@staticmethod
|
|
def __remove_key_and_log_state(func_module: str, function_args: dict) -> dict:
|
|
"""
|
|
Remove API key from the function args and log state of keys.
|
|
|
|
Parameters
|
|
----------
|
|
func_module : str
|
|
Module of the function
|
|
function_args : dict
|
|
Function args
|
|
|
|
Returns
|
|
----------
|
|
dict
|
|
Function args with API key removed
|
|
"""
|
|
|
|
if func_module == "openbb_terminal.keys_model":
|
|
|
|
from openbb_terminal.core.log.generation.settings_logger import ( # pylint: disable=C0415
|
|
log_keys,
|
|
)
|
|
|
|
# remove key if defined
|
|
function_args.pop("key", None)
|
|
log_keys()
|
|
return function_args
|
|
|
|
def log_after_call(
|
|
self,
|
|
method_result: Any,
|
|
):
|
|
if self.__check_logging_conditions():
|
|
logger = self.__logger
|
|
self.__log_exception_if_any(
|
|
logger=logger,
|
|
method_result=method_result,
|
|
method_chosen=self.__method_chosen,
|
|
)
|
|
self.__log_end(
|
|
logger=logger,
|
|
method_chosen=self.__method_chosen,
|
|
)
|
|
OperationLogger.last_method = {
|
|
f"{self.__method_chosen.__module__}.{self.__method_chosen.__name__}": {
|
|
"args": str(self.__args)[:100],
|
|
"kwargs": str(self.__kwargs)[:100],
|
|
}
|
|
}
|
|
|
|
@staticmethod
|
|
def __log_exception_if_any(
|
|
logger: Logger,
|
|
method_chosen: Callable,
|
|
method_result: Any,
|
|
):
|
|
if isinstance(method_result, Exception):
|
|
logger.exception(
|
|
f"Exception: {method_result}",
|
|
extra={"func_name_override": method_chosen.__name__},
|
|
)
|
|
|
|
@staticmethod
|
|
def __log_end(logger: Logger, method_chosen: Callable):
|
|
logger.info(
|
|
"END",
|
|
extra={"func_name_override": method_chosen.__name__},
|
|
)
|
|
|
|
def __check_logging_conditions(self) -> bool:
|
|
return not cfg.LOGGING_SUPPRESS and not self.__check_last_method()
|
|
|
|
def __check_last_method(self) -> bool:
|
|
current_method = {
|
|
f"{self.__method_chosen.__module__}.{self.__method_chosen.__name__}": {
|
|
"args": str(self.__args)[:100],
|
|
"kwargs": str(self.__kwargs)[:100],
|
|
}
|
|
}
|
|
return OperationLogger.last_method == current_method
|