Skip to content

Commit

Permalink
Allow to execute reports url from reports menu (#5385)
Browse files Browse the repository at this point in the history
* allow to execute reports url from reports menu

* lint for James

* ruff

* ruff

---------

Co-authored-by: James Maslek <jmaslek11@gmail.com>
  • Loading branch information
2 people authored and the-praxs committed Sep 4, 2023
1 parent b5bc4c7 commit 711803f
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 3 deletions.
1 change: 1 addition & 0 deletions openbb_terminal/miscellaneous/i18n/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1103,6 +1103,7 @@ en:
reports/_OpenBB_reports_: OpenBB reports
reports/_Custom_reports_: Custom reports
reports/run: Run a Jupyter notebook from OpenBBUserData/reports/custom reports
reports/exe: Execute a Jupyter notebook through a hyperlink using papermill
forecast/_disclaimer_: DISCLAIMER
forecast/_data_loc: Looking for data in
forecast/load: load a dataset from csv
Expand Down
115 changes: 113 additions & 2 deletions openbb_terminal/reports/reports_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
# pylint: disable=R1732, R0912
from typing import Any, Dict, List, Optional

import requests

from openbb_terminal.core.session.current_user import get_current_user
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
from openbb_terminal.decorators import log_start_end
from openbb_terminal.helper_funcs import parse_and_split_input
from openbb_terminal.menu import session
from openbb_terminal.parent_classes import BaseController
from openbb_terminal.reports import reports_model
Expand All @@ -34,6 +37,7 @@ class ReportController(BaseController):
"portfolio",
"run",
"load",
"exe",
]
PATH = "/reports/"

Expand Down Expand Up @@ -78,6 +82,16 @@ def update_choices(self):

self.completer = NestedCompleter.from_nested_dict(self.choices)

def parse_input(self, an_input: str) -> List:
"""Overwrite the BaseController parse_input for `askobb` and 'exe'
This will allow us to search for something like "P/E" ratio
"""
raw_url = r"(exe (--url |-u )?(https?://)?raw\.githubusercontent\.(com)/.*)"
github_url = r"(exe (--url |-u )?(https?://)?github\.(com)/.*)"
custom_filters = [raw_url, github_url]
return parse_and_split_input(an_input=an_input, custom_filters=custom_filters)

def print_help(self):
"""Print help."""

Expand All @@ -88,7 +102,6 @@ def print_help(self):
self.update_choices()

mt = MenuText("reports/")
mt.add_info("_reports_")
mt.add_raw("\n")
mt.add_info("_OpenBB_reports_")
MAX_LEN_NAME = max(len(name) for name in self.REPORTS) + 2
Expand All @@ -110,7 +123,8 @@ def print_help(self):
mt.add_raw("\n")
mt.add_info("_Custom_reports_")
mt.add_cmd("run")
console.print(text=mt.menu_text, menu="Reports - WORK IN PROGRESS")
mt.add_cmd("exe")
console.print(text=mt.menu_text, menu="Reports")

@log_start_end(log=logger)
def call_etf(self, other_args: List[str]):
Expand Down Expand Up @@ -264,3 +278,100 @@ def call_run(self, other_args: List[str]):
console.print(
f"[red]Notebook '{ns_parser.file}' not found![/red]\n"
)

def call_exe(self, other_args: List[str]):
"""Process exe command"""
parser = argparse.ArgumentParser(
add_help=False,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
prog="exe",
description="Run a notebook from a url that contains the ipynb contents",
)
parser.add_argument(
"-u",
"--url",
dest="url",
required="-h" not in other_args,
help="The url of the file to be loaded",
)
parser.add_argument(
"-p",
"--parameters",
nargs="+",
dest="parameters",
help="Report parameters with format 'name:value'.",
)

# If first argument is a url, insert the -u flag
if other_args[0].startswith("http"):
other_args.insert(0, "--url")

ns_parser = self.parse_known_args_and_warn(parser, other_args)

if ns_parser:
# Validate parameter inputs
parameters_dict = {}
if ns_parser.parameters:
for p in ns_parser.parameters:
if ":" in p:
item = p.split(":")
if item[1]:
parameters_dict[item[0]] = item[1]
else:
console.print(
f"[red]Bad format '{p}': empty value.[/red]\nExecuting with defaults.\n"
)
else:
console.print(
f"[red]Bad format '{p}': use format 'name:value'.[/red]\nExecuting with defaults.\n"
)

if "raw.githubusercontent" in ns_parser.url:
url = ns_parser.url
else:
url = ns_parser.url.replace(
"github.com", "raw.githubusercontent.com"
).replace("/blob", "")

if url:
try:
# Send an HTTP GET request to fetch the raw notebook
response = requests.get(url, timeout=20)

if response.status_code == 200:
temporary_folder = os.path.join(
get_current_user().preferences.USER_REPORTS_DIRECTORY,
"temporary",
)

# Does the temp folder exist? if not create it
if not os.path.exists(temporary_folder):
os.makedirs(temporary_folder)

# Local file path where you want to save the notebook
local_file_path = os.path.join(
temporary_folder,
url.split(".com/")[1].replace(
"/", "_"
), # .replace(".ipynb", "")
)

# Save the template notebook locally
with open(local_file_path, "wb") as notebook_file:
notebook_file.write(response.content)

# To confirm that the notebook is saved locally
if os.path.exists(local_file_path):
reports_model.render_report(
input_path=local_file_path, args_dict=parameters_dict
)
else:
console.print(f"[red]Notebook '{url}' not found![/red]\n")

else:
console.print(
f"Failed to fetch notebook from {url}. Status code: {response.status_code}"
)

except Exception as e:
console.print(f"An error occurred: {str(e)}")
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
Build and run your custom reports or try one of our templates:

OpenBB reports:
crypto <symbol>
Expand All @@ -11,4 +10,5 @@ OpenBB reports:

Custom reports:
run Run a Jupyter notebook from OpenBBUserData/reports/custom reports
exe Execute a Jupyter notebook through a hyperlink using papermill

0 comments on commit 711803f

Please sign in to comment.