mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Merge pull request #5312 from OpenBB-finance/hotfix/macro-routines-to-hub
Fix routines creation from the Terminal to Hub
This commit is contained in:
4
README.md
vendored
4
README.md
vendored
@@ -135,7 +135,9 @@ Any of our social media platforms: [openbb.co/links](https://openbb.co/links)
|
||||
|
||||
## 6. Star History
|
||||
|
||||
This is a proxy of our growth and that we are just getting started. But for more metrics important to us check [openbb.co/open](https://openbb.co/open).
|
||||
This is a proxy of our growth and that we are just getting started.
|
||||
|
||||
But for more metrics important to us check [openbb.co/open](https://openbb.co/open).
|
||||
|
||||
[](https://star-history.com/#openbb-finance/OpenBBTerminal&Date)
|
||||
|
||||
|
||||
@@ -255,6 +255,7 @@ class AccountController(BaseController):
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
page=ns_parser.page,
|
||||
size=ns_parser.size,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
df, page, pages = get_personal_routines_info(response)
|
||||
if not df.empty:
|
||||
@@ -356,6 +357,7 @@ class AccountController(BaseController):
|
||||
"routine": routine,
|
||||
"tags": tags,
|
||||
"public": ns_parser.public,
|
||||
"base_url": Hub.BackendEnvironment.BASE_URL,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
|
||||
@@ -412,6 +414,7 @@ class AccountController(BaseController):
|
||||
response = Hub.download_routine(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
uuid=self.REMOTE_CHOICES[name],
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
data = [response.json(), "personal"]
|
||||
@@ -499,6 +502,7 @@ class AccountController(BaseController):
|
||||
response = Hub.delete_routine(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
uuid=self.REMOTE_CHOICES[name],
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
)
|
||||
if (
|
||||
response
|
||||
@@ -551,6 +555,7 @@ class AccountController(BaseController):
|
||||
|
||||
response = Hub.generate_personal_access_token(
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
days=ns_parser.days,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
|
||||
@@ -18,7 +18,7 @@ from openbb_terminal.rich_config import console
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
BASE_URL = "https://api.ultimainsights.ai/v1"
|
||||
ULTIMA_BASE_URL = "https://api.ultimainsights.ai/v1"
|
||||
NO_API_KEY = "REPLACE_ME"
|
||||
|
||||
|
||||
@@ -69,10 +69,10 @@ def get_news(term: str = "", sort: str = "articlePublishedDate") -> pd.DataFrame
|
||||
if term in supported_terms():
|
||||
if auth_header:
|
||||
data = request(
|
||||
f"{BASE_URL}/getNewsArticles/{term}", headers=auth_header
|
||||
f"{ULTIMA_BASE_URL}/getNewsArticles/{term}", headers=auth_header
|
||||
)
|
||||
else:
|
||||
data = request(f"{BASE_URL}/getNewsArticles/{term}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getNewsArticles/{term}")
|
||||
else:
|
||||
console.print(
|
||||
"[red]Ticker not supported. Unable to retrieve data\n[/red]"
|
||||
@@ -150,7 +150,7 @@ def supported_terms() -> list:
|
||||
# https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error/73270162#73270162
|
||||
os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
|
||||
os.environ["SSL_CERT_FILE"] = certifi.where()
|
||||
data = request(f"{BASE_URL}/supportedTickers")
|
||||
data = request(f"{ULTIMA_BASE_URL}/supportedTickers")
|
||||
return list(data.json())
|
||||
|
||||
|
||||
@@ -176,7 +176,7 @@ def get_company_info(ticker: str) -> dict:
|
||||
os.environ["SSL_CERT_FILE"] = certifi.where()
|
||||
|
||||
if ticker in supported_terms():
|
||||
data = request(f"{BASE_URL}/getCompanyInfo/{ticker}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getCompanyInfo/{ticker}")
|
||||
return data.json()
|
||||
console.print("[red]Ticker not supported. Unable to retrieve data\n[/red]")
|
||||
return {}
|
||||
@@ -213,9 +213,11 @@ def get_top_headlines(ticker: str) -> dict:
|
||||
|
||||
if ticker in supported_terms():
|
||||
if auth_header:
|
||||
data = request(f"{BASE_URL}/getTopHeadlines/{ticker}", headers=auth_header)
|
||||
data = request(
|
||||
f"{ULTIMA_BASE_URL}/getTopHeadlines/{ticker}", headers=auth_header
|
||||
)
|
||||
else:
|
||||
data = request(f"{BASE_URL}/getTopHeadlines/{ticker}")
|
||||
data = request(f"{ULTIMA_BASE_URL}/getTopHeadlines/{ticker}")
|
||||
if (
|
||||
hasattr(data, "status") and data.status_code == 429
|
||||
): # If data request failed
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
from argparse import ArgumentParser
|
||||
from contextlib import contextmanager
|
||||
from inspect import isfunction, unwrap
|
||||
from os import environ
|
||||
from types import MethodType
|
||||
from typing import Callable, List
|
||||
from unittest.mock import patch
|
||||
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.helper_funcs import check_file_type_saved, check_positive
|
||||
from openbb_terminal.rich_config import get_ordered_list_sources
|
||||
|
||||
@@ -211,7 +211,7 @@ def __patch_controller_functions(controller):
|
||||
),
|
||||
]
|
||||
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
rich.start()
|
||||
patched_function_list = []
|
||||
for patcher in patcher_list:
|
||||
@@ -219,7 +219,7 @@ def __patch_controller_functions(controller):
|
||||
|
||||
yield patched_function_list
|
||||
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
rich.stop()
|
||||
for patcher in patcher_list:
|
||||
patcher.stop()
|
||||
@@ -317,7 +317,7 @@ def build_controller_choice_map(controller) -> dict:
|
||||
argument_parser=argument_parser
|
||||
)
|
||||
except Exception as exception:
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() == "true":
|
||||
if get_current_system().DEBUG_MODE:
|
||||
raise Exception(
|
||||
f"On command : `{command}`.\n{str(exception)}"
|
||||
) from exception
|
||||
|
||||
@@ -54,6 +54,7 @@ class SystemModel(BaseModel):
|
||||
# Others
|
||||
TEST_MODE: bool = False
|
||||
DEBUG_MODE: bool = False
|
||||
DEV_BACKEND: bool = False
|
||||
ENABLE_AUTHENTICATION: bool = True
|
||||
HEADLESS: bool = False
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@ import plotly.graph_objects as go
|
||||
from packaging import version
|
||||
from reportlab.graphics import renderPDF
|
||||
|
||||
# pylint: disable=C0415
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
|
||||
# pylint: disable=C0411,C0412,C0415
|
||||
try:
|
||||
from pywry import PyWry
|
||||
except ImportError as e:
|
||||
@@ -441,8 +443,10 @@ class Backend(PyWry):
|
||||
self.check_backend()
|
||||
endpoint = {True: "login", False: "logout"}[login]
|
||||
|
||||
json_url = f"{BackendEnvironment.HUB_URL}{endpoint}?pywry=true"
|
||||
|
||||
outgoing = dict(
|
||||
json_data=dict(url=f"https://my.openbb.co/{endpoint}?pywry=true"),
|
||||
json_data=dict(url=json_url),
|
||||
**self.get_kwargs(endpoint.title()),
|
||||
width=900,
|
||||
height=800,
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
BASE_URL = "https://payments.openbb.co/"
|
||||
# BASE_URL = "http://127.0.0.1:8000/"
|
||||
class HubEnvironment:
|
||||
# BASE_URL = "http://127.0.0.1:8000/"
|
||||
BASE_URL = "https://payments.openbb.co/"
|
||||
HUB_URL = "https://my.openbb.co/"
|
||||
|
||||
HUB_URL = "https://my.openbb.co/"
|
||||
REGISTER_URL = HUB_URL + "register"
|
||||
SUPPORT_URL = HUB_URL + "app/terminal/support"
|
||||
SOURCES_URL = HUB_URL + "app/terminal/data-sources"
|
||||
KEYS_URL = HUB_URL + "app/terminal/api-keys"
|
||||
COLORS_URL = HUB_URL + "app/terminal/theme"
|
||||
CHARTS_TABLES_URL = HUB_URL + "app/terminal/theme/charts-tables"
|
||||
def __new__(cls, *args, **kwargs): # pylint: disable=W0613
|
||||
"""Create a singleton instance of the backend."""
|
||||
if not hasattr(cls, "instance"):
|
||||
cls.instance = super().__new__(cls) # pylint: disable=E1120
|
||||
return cls.instance
|
||||
|
||||
|
||||
BackendEnvironment = HubEnvironment()
|
||||
|
||||
DEFAULT_ROUTINES_URL = "https://openbb-cms.directus.app/items/Routines"
|
||||
|
||||
|
||||
@@ -7,18 +7,22 @@ import requests
|
||||
from jose import jwt
|
||||
|
||||
from openbb_terminal.core.session.constants import (
|
||||
BASE_URL,
|
||||
CONNECTION_ERROR_MSG,
|
||||
CONNECTION_TIMEOUT_MSG,
|
||||
DEFAULT_ROUTINES_URL,
|
||||
TIMEOUT,
|
||||
BackendEnvironment,
|
||||
)
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.current_user import get_current_user
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
|
||||
def create_session(
|
||||
email: str, password: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
email: str,
|
||||
password: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Create a session.
|
||||
|
||||
@@ -71,7 +75,7 @@ def check_token_expiration(token: str):
|
||||
|
||||
|
||||
def create_session_from_token(
|
||||
token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
token: str, base_url: str = BackendEnvironment.BASE_URL, timeout: int = TIMEOUT
|
||||
):
|
||||
"""Create a session from token.
|
||||
|
||||
@@ -108,7 +112,10 @@ def create_session_from_token(
|
||||
|
||||
|
||||
def delete_session(
|
||||
auth_header: str, token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
token: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Delete the session.
|
||||
|
||||
@@ -190,7 +197,7 @@ def get_session(email: str, password: str) -> dict:
|
||||
dict
|
||||
The session info.
|
||||
"""
|
||||
response = create_session(email, password)
|
||||
response = create_session(email, password, base_url=BackendEnvironment.BASE_URL)
|
||||
if response is None:
|
||||
return {}
|
||||
return process_session_response(response)
|
||||
@@ -209,14 +216,14 @@ def get_session_from_token(token: str) -> dict:
|
||||
dict
|
||||
The session info.
|
||||
"""
|
||||
response = create_session_from_token(token)
|
||||
response = create_session_from_token(token, base_url=BackendEnvironment.BASE_URL)
|
||||
if response is None:
|
||||
return {}
|
||||
return process_session_response(response)
|
||||
|
||||
|
||||
def fetch_user_configs(
|
||||
session: dict, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
session: dict, base_url: str = BackendEnvironment.BASE_URL, timeout: int = TIMEOUT
|
||||
) -> Optional[requests.Response]:
|
||||
"""Fetch user configurations.
|
||||
|
||||
@@ -258,7 +265,10 @@ def fetch_user_configs(
|
||||
|
||||
|
||||
def clear_user_configs(
|
||||
config: str, auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
config: str,
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Clear user configurations to the server.
|
||||
|
||||
@@ -307,7 +317,7 @@ def upload_user_field(
|
||||
key: str,
|
||||
value: Any,
|
||||
auth_header: str,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
silent: bool = False,
|
||||
) -> Optional[requests.Response]:
|
||||
@@ -365,7 +375,7 @@ def upload_config(
|
||||
value: str,
|
||||
type_: Literal["settings", "terminal_style"],
|
||||
auth_header: str,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Patch user configurations to the server.
|
||||
@@ -429,7 +439,7 @@ def upload_routine(
|
||||
override: bool = False,
|
||||
tags: str = "",
|
||||
public: bool = False,
|
||||
base_url: str = BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Send a routine to the server.
|
||||
@@ -467,7 +477,6 @@ def upload_routine(
|
||||
"version": get_current_system().VERSION,
|
||||
"public": public,
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
headers={"Authorization": auth_header},
|
||||
@@ -476,7 +485,21 @@ def upload_routine(
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
console.print("[green]Successfully uploaded your routine.[/green]")
|
||||
username = get_current_user().profile.username
|
||||
console.print("[green]Successfully uploaded your routine.[/]")
|
||||
|
||||
run_env = BackendEnvironment.HUB_URL.rstrip("/")
|
||||
|
||||
if public:
|
||||
console.print(
|
||||
f"\n[yellow]Share or edit it at {run_env}/u/{username}/routine/{name.replace(' ', '-')}[/]"
|
||||
)
|
||||
else:
|
||||
console.print(f"\n[yellow]Go to {run_env} to edit this script,[/]")
|
||||
console.print(
|
||||
f"[yellow]or even make it public so you can access it at "
|
||||
f"{run_env}/u/{username}/routine/{name.replace(' ', '-')}[/]"
|
||||
)
|
||||
elif response.status_code != 409: # 409: routine already exists
|
||||
console.print(
|
||||
"[red]" + response.json().get("detail", "Unknown error.") + "[/red]"
|
||||
@@ -496,7 +519,7 @@ def upload_routine(
|
||||
def download_routine(
|
||||
auth_header: str,
|
||||
uuid: UUID,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Download a routine from the server.
|
||||
@@ -520,7 +543,7 @@ def download_routine(
|
||||
try:
|
||||
response = requests.get(
|
||||
headers={"Authorization": auth_header},
|
||||
url=base_url + "terminal/script/" + uuid,
|
||||
url=base_url + "terminal/script/" + uuid, # type: ignore
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 404:
|
||||
@@ -542,7 +565,7 @@ def download_routine(
|
||||
def delete_routine(
|
||||
auth_header: str,
|
||||
uuid: UUID,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""Delete a routine from the server.
|
||||
@@ -566,7 +589,7 @@ def delete_routine(
|
||||
try:
|
||||
response = requests.delete(
|
||||
headers={"Authorization": auth_header},
|
||||
url=base_url + "terminal/script/" + uuid,
|
||||
url=base_url + "terminal/script/" + uuid, # type: ignore
|
||||
timeout=timeout,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
@@ -592,7 +615,7 @@ def list_routines(
|
||||
fields: Optional[List[str]] = None,
|
||||
page: int = 1,
|
||||
size: int = 10,
|
||||
base_url=BASE_URL,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
silent: bool = False,
|
||||
) -> Optional[requests.Response]:
|
||||
@@ -683,7 +706,10 @@ def get_default_routines(
|
||||
|
||||
|
||||
def generate_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT, days: int = 30
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
days: int = 30,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Generate an OpenBB Personal Access Token.
|
||||
@@ -732,7 +758,9 @@ def generate_personal_access_token(
|
||||
|
||||
|
||||
def get_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Show the user's OpenBB Personal Access Token.
|
||||
@@ -777,7 +805,9 @@ def get_personal_access_token(
|
||||
|
||||
|
||||
def revoke_personal_access_token(
|
||||
auth_header: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
auth_header: str,
|
||||
base_url: str = BackendEnvironment.BASE_URL,
|
||||
timeout: int = TIMEOUT,
|
||||
) -> Optional[requests.Response]:
|
||||
"""
|
||||
Delete the user's OpenBB Personal Access Token.
|
||||
|
||||
@@ -51,6 +51,7 @@ def download_routines(auth_header: str, silent: bool = False) -> list:
|
||||
fields=["name", "script"],
|
||||
page=1,
|
||||
size=100,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
silent=silent,
|
||||
)
|
||||
if response and response.status_code == 200:
|
||||
|
||||
@@ -5,11 +5,11 @@ from prompt_toolkit import PromptSession
|
||||
import openbb_terminal.core.session.local_model as Local
|
||||
from openbb_terminal.core.config.paths import PACKAGE_DIRECTORY
|
||||
from openbb_terminal.core.plots.backend import plots_backend
|
||||
from openbb_terminal.core.session.constants import (
|
||||
REGISTER_URL,
|
||||
SUPPORT_URL,
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_system import (
|
||||
get_current_system,
|
||||
set_system_variable,
|
||||
)
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.session_model import (
|
||||
LoginStatus,
|
||||
create_session,
|
||||
@@ -24,8 +24,12 @@ def display_welcome_message(links: bool = True) -> None:
|
||||
with open(PACKAGE_DIRECTORY / "core" / "session" / "banner.txt") as f:
|
||||
console.print(f"[menu]{f.read()}[/menu]\n")
|
||||
if links:
|
||||
console.print(f"Register : [cmds]{REGISTER_URL}[/cmds]")
|
||||
console.print(f"Support : [cmds]{SUPPORT_URL}[/cmds]")
|
||||
console.print(
|
||||
f"Register : [cmds]{BackendEnvironment.HUB_URL + 'register'}[/cmds]"
|
||||
)
|
||||
console.print(
|
||||
f"Support : [cmds]{BackendEnvironment.HUB_URL + 'app/terminal/support'}[/cmds]"
|
||||
)
|
||||
|
||||
|
||||
def get_user_input() -> Tuple[str, str, bool]:
|
||||
@@ -135,13 +139,15 @@ def prompt_cli(welcome: bool = True):
|
||||
|
||||
|
||||
# pylint: disable=inconsistent-return-statements
|
||||
def launch_terminal(debug: bool = False, queue: Optional[List[str]] = None):
|
||||
def launch_terminal(
|
||||
debug: bool = False, dev: bool = False, queue: Optional[List[str]] = None
|
||||
):
|
||||
"""Launch terminal"""
|
||||
# pylint: disable=import-outside-toplevel
|
||||
from openbb_terminal import terminal_controller
|
||||
|
||||
if queue:
|
||||
return terminal_controller.main(debug, queue, module="")
|
||||
return terminal_controller.main(debug, dev, queue, module="")
|
||||
|
||||
terminal_controller.parse_args_and_run()
|
||||
|
||||
@@ -170,8 +176,13 @@ def main(
|
||||
welcome: bool = True,
|
||||
prompt: bool = True,
|
||||
queue: Optional[List[str]] = None,
|
||||
dev: bool = False,
|
||||
):
|
||||
"""Main function"""
|
||||
if dev:
|
||||
set_system_variable("DEV_BACKEND", True)
|
||||
BackendEnvironment.BASE_URL = "https://payments.openbb.dev/"
|
||||
BackendEnvironment.HUB_URL = "https://my.openbb.dev/"
|
||||
|
||||
local_session = Local.get_session() if session is None else session
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ def login(session: Dict, remember: bool = False) -> LoginStatus:
|
||||
preferences=get_current_user().preferences,
|
||||
sources=SourcesModel(),
|
||||
)
|
||||
response = Hub.fetch_user_configs(session)
|
||||
response = Hub.fetch_user_configs(session, Hub.BackendEnvironment.BASE_URL)
|
||||
if response is not None:
|
||||
if response.status_code == 200:
|
||||
configs = json.loads(response.content)
|
||||
@@ -159,6 +159,7 @@ def update_backend_sources(auth_header, configs, silent: bool = True):
|
||||
key="features_sources",
|
||||
value=updated_sources,
|
||||
auth_header=auth_header,
|
||||
base_url=Hub.BackendEnvironment.BASE_URL,
|
||||
silent=silent,
|
||||
)
|
||||
except Exception:
|
||||
@@ -190,7 +191,7 @@ def logout(
|
||||
|
||||
success = True
|
||||
|
||||
r = Hub.delete_session(auth_header, token)
|
||||
r = Hub.delete_session(auth_header, token, base_url=Hub.BackendEnvironment.BASE_URL)
|
||||
if not r or r.status_code != 200:
|
||||
success = False
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ class EconometricsController(BaseController):
|
||||
}
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["load"] = {
|
||||
"--file": {c: {} for c in self.DATA_FILES},
|
||||
"-f": "--file",
|
||||
|
||||
@@ -83,7 +83,7 @@ class QaController(StockBaseController):
|
||||
self.resolution = "" # For the views
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["pick"] = {c: {} for c in self.options}
|
||||
choices["unitroot"] = {
|
||||
"--fuller_reg": {c: {} for c in self.FULLER_REG},
|
||||
|
||||
@@ -66,7 +66,7 @@ class FeatureFlagsController(BaseController):
|
||||
super().__init__(queue)
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def print_help(self):
|
||||
|
||||
@@ -8,7 +8,7 @@ import logging
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
from openbb_terminal import keys_model, keys_view
|
||||
from openbb_terminal.core.session.constants import KEYS_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_user import get_current_user, is_local
|
||||
from openbb_terminal.core.session.env_handler import get_reading_order
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
@@ -75,7 +75,11 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
"""
|
||||
reading_order = get_reading_order()
|
||||
hierarchy = "\n ".join(list(map(str, reversed(reading_order))))
|
||||
return hierarchy if is_local() else f"{KEYS_URL}\n {hierarchy}"
|
||||
return (
|
||||
hierarchy
|
||||
if is_local()
|
||||
else f"{BackendEnvironment.HUB_URL + 'app/terminal/api-keys'}\n {hierarchy}"
|
||||
)
|
||||
|
||||
def print_help(self, update_status: bool = True, reevaluate: bool = True):
|
||||
"""Print help"""
|
||||
|
||||
@@ -29,8 +29,8 @@ from openbb_terminal.account.show_prompt import get_show_prompt
|
||||
from openbb_terminal.core.completer.choices import build_controller_choice_map
|
||||
from openbb_terminal.core.config.paths import HIST_FILE_PATH
|
||||
from openbb_terminal.core.session import hub_model as Hub
|
||||
from openbb_terminal.core.session.constants import SCRIPT_TAGS
|
||||
from openbb_terminal.core.session.current_user import get_current_user, is_local
|
||||
from openbb_terminal.core.session.routines_handler import read_routine
|
||||
from openbb_terminal.cryptocurrency import cryptocurrency_helpers
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
@@ -85,6 +85,7 @@ SUPPORT_TYPE = ["bug", "suggestion", "question", "generic"]
|
||||
|
||||
# TODO: We should try to avoid these global variables
|
||||
RECORD_SESSION = False
|
||||
RECORD_SESSION_LOCAL_ONLY = False
|
||||
SESSION_RECORDED = list()
|
||||
SESSION_RECORDED_NAME = ""
|
||||
SESSION_RECORDED_DESCRIPTION = ""
|
||||
@@ -111,7 +112,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
"reset",
|
||||
"support",
|
||||
"wiki",
|
||||
"record",
|
||||
"stop",
|
||||
"screenshot",
|
||||
"askobb",
|
||||
@@ -892,8 +892,9 @@ class BaseController(metaclass=ABCMeta):
|
||||
action="store",
|
||||
dest="name",
|
||||
type=str,
|
||||
default=datetime.now().strftime("%Y%m%d_%H%M%S_routine.openbb"),
|
||||
help="Routine file name to be saved.",
|
||||
default="",
|
||||
help="Routine title name to be saved - only use characters, digits and whitespaces.",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
@@ -901,15 +902,30 @@ class BaseController(metaclass=ABCMeta):
|
||||
type=str,
|
||||
dest="description",
|
||||
help="The description of the routine",
|
||||
default=f"Routine recorded at {datetime.now().strftime('%H:%M')} from the OpenBB Terminal",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tag1",
|
||||
type=str,
|
||||
dest="tag1",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--tags",
|
||||
"--tag2",
|
||||
type=str,
|
||||
dest="tags",
|
||||
help="The tags of the routine",
|
||||
dest="tag2",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--tag3",
|
||||
type=str,
|
||||
dest="tag3",
|
||||
help=f"The tag associated with the routine. Select from: {', '.join(SCRIPT_TAGS)}",
|
||||
default="",
|
||||
nargs="+",
|
||||
)
|
||||
@@ -921,32 +937,108 @@ class BaseController(metaclass=ABCMeta):
|
||||
help="Whether the routine should be public or not",
|
||||
default=False,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--local",
|
||||
dest="local",
|
||||
action="store_true",
|
||||
help="Only save the routine locally - this is necessary if you are running terminal in guest mode.",
|
||||
default=False,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-n")
|
||||
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
|
||||
if ns_parser:
|
||||
if not ns_parser.name:
|
||||
console.print(
|
||||
"[red]Set a routine title by using the '-n' flag. E.g. 'record -n Morning routine'[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag1 = (
|
||||
" ".join(ns_parser.tag1)
|
||||
if isinstance(ns_parser.tag1, list)
|
||||
else ns_parser.tag1
|
||||
)
|
||||
if tag1 and tag1 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag1' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag2 = (
|
||||
" ".join(ns_parser.tag2)
|
||||
if isinstance(ns_parser.tag2, list)
|
||||
else ns_parser.tag2
|
||||
)
|
||||
if tag2 and tag2 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag2' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
tag3 = (
|
||||
" ".join(ns_parser.tag3)
|
||||
if isinstance(ns_parser.tag3, list)
|
||||
else ns_parser.tag3
|
||||
)
|
||||
if tag3 and tag3 not in SCRIPT_TAGS:
|
||||
console.print(
|
||||
f"[red]The parameter 'tag3' needs to be one of the following {', '.join(SCRIPT_TAGS)}[/red]"
|
||||
)
|
||||
return
|
||||
|
||||
if is_local() and not ns_parser.local:
|
||||
console.print(
|
||||
"[red]Recording session to the OpenBB Hub is not supported in guest mode.[/red]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Sign to OpenBB Hub to register: http://openbb.co[/yellow]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Otherwise set the flag '-l' to save the file locally.[/yellow]"
|
||||
)
|
||||
return
|
||||
|
||||
# Check if title has a valid format
|
||||
title = " ".join(ns_parser.name) if ns_parser.name else ""
|
||||
# To this day, the reason why /^[a-zA-Z0-9\s]+$/ does not work is unknown
|
||||
pattern = re.compile(r"^[a-zA-Z0-9\s]+(?:[a-zA-Z0-9\s]+)*$")
|
||||
if not pattern.match(title):
|
||||
console.print(
|
||||
f"[red]Title '{title}' has invalid format. Please use only digits, characters and whitespaces.[/]"
|
||||
)
|
||||
return
|
||||
|
||||
global RECORD_SESSION
|
||||
global RECORD_SESSION_LOCAL_ONLY
|
||||
global SESSION_RECORDED_NAME
|
||||
global SESSION_RECORDED_DESCRIPTION
|
||||
global SESSION_RECORDED_TAGS
|
||||
global SESSION_RECORDED_PUBLIC
|
||||
|
||||
SESSION_RECORDED_NAME = (
|
||||
ns_parser.name
|
||||
if ".openbb" in ns_parser.name
|
||||
else ns_parser.name + ".openbb"
|
||||
RECORD_SESSION = True
|
||||
RECORD_SESSION_LOCAL_ONLY = ns_parser.local
|
||||
SESSION_RECORDED_NAME = title
|
||||
SESSION_RECORDED_DESCRIPTION = (
|
||||
" ".join(ns_parser.description)
|
||||
if isinstance(ns_parser.description, list)
|
||||
else ns_parser.description
|
||||
)
|
||||
SESSION_RECORDED_TAGS = tag1 if tag1 else ""
|
||||
SESSION_RECORDED_TAGS += "," + tag2 if tag2 else ""
|
||||
SESSION_RECORDED_TAGS += "," + tag3 if tag3 else ""
|
||||
|
||||
SESSION_RECORDED_DESCRIPTION = " ".join(ns_parser.description)
|
||||
SESSION_RECORDED_TAGS = " ".join(ns_parser.tags) if ns_parser.tags else ""
|
||||
SESSION_RECORDED_PUBLIC = ns_parser.public
|
||||
|
||||
console.print(
|
||||
"[green]The session is successfully being recorded."
|
||||
+ " Remember to 'stop' before exiting terminal!\n[/green]"
|
||||
f"[green]The routine '{title}' is successfully being recorded.[/green]"
|
||||
)
|
||||
console.print(
|
||||
"\n[yellow]Remember to run 'stop' command when you are done!\n[/yellow]"
|
||||
)
|
||||
RECORD_SESSION = True
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_stop(self, _) -> None:
|
||||
@@ -956,57 +1048,102 @@ class BaseController(metaclass=ABCMeta):
|
||||
|
||||
if not RECORD_SESSION:
|
||||
console.print(
|
||||
"[red]There is no session being recorded. Start one using 'record'[/red]\n"
|
||||
"[red]There is no session being recorded. Start one using the command 'record'[/red]\n"
|
||||
)
|
||||
elif not SESSION_RECORDED:
|
||||
elif len(SESSION_RECORDED) < 5:
|
||||
console.print(
|
||||
"[red]There is no session to be saved. Run at least 1 command after starting 'record'[/red]\n"
|
||||
"[red]Run at least 4 commands before stopping recording a session.[/red]\n"
|
||||
)
|
||||
else:
|
||||
current_user = get_current_user()
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY, SESSION_RECORDED_NAME
|
||||
)
|
||||
|
||||
if os.path.isfile(routine_file):
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
datetime.now().strftime("%Y%m%d_%H%M%S_") + SESSION_RECORDED_NAME,
|
||||
# Check if the user just wants to store routine locally
|
||||
# This works regardless of whether they are logged in or not
|
||||
if RECORD_SESSION_LOCAL_ONLY:
|
||||
# Whitespaces are replaced by underscores and an .openbb extension is added
|
||||
title_for_local_storage = (
|
||||
SESSION_RECORDED_NAME.replace(" ", "_") + ".openbb"
|
||||
)
|
||||
|
||||
# Writing to file
|
||||
with open(routine_file, "w") as file1:
|
||||
# Writing data to a file
|
||||
file1.writelines([c + "\n\n" for c in SESSION_RECORDED[:-1]])
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
title_for_local_storage,
|
||||
)
|
||||
|
||||
console.print(
|
||||
f"[green]Your routine has been recorded and saved here: {routine_file}[/green]\n"
|
||||
)
|
||||
|
||||
if not is_local():
|
||||
routine = read_routine(file_name=routine_file)
|
||||
if routine is not None:
|
||||
name = SESSION_RECORDED_NAME.split(sep=".openbb", maxsplit=-1)[0]
|
||||
kwargs = {
|
||||
"auth_header": current_user.profile.get_auth_header(),
|
||||
"name": name,
|
||||
"description": SESSION_RECORDED_DESCRIPTION,
|
||||
"routine": routine,
|
||||
"tags": SESSION_RECORDED_TAGS,
|
||||
"public": SESSION_RECORDED_PUBLIC,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
if response is not None and response.status_code == 409:
|
||||
i = console.input(
|
||||
"A routine with the same name already exists, "
|
||||
"do you want to replace it? (y/n): "
|
||||
)
|
||||
# If file already exists, add a timestamp to the name
|
||||
if os.path.isfile(routine_file):
|
||||
i = console.input(
|
||||
"A local routine with the same name already exists, "
|
||||
"do you want to override it? (y/n): "
|
||||
)
|
||||
console.print("")
|
||||
while i.lower() not in ["y", "yes", "n", "no"]:
|
||||
i = console.input("Select 'y' or 'n' to proceed: ")
|
||||
console.print("")
|
||||
if i.lower() in ["y", "yes"]:
|
||||
kwargs["override"] = True # type: ignore
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
else:
|
||||
console.print("[info]Aborted.[/info]")
|
||||
|
||||
if i.lower() in ["n", "no"]:
|
||||
new_name = (
|
||||
datetime.now().strftime("%Y%m%d_%H%M%S_")
|
||||
+ title_for_local_storage
|
||||
)
|
||||
routine_file = os.path.join(
|
||||
current_user.preferences.USER_ROUTINES_DIRECTORY,
|
||||
new_name,
|
||||
)
|
||||
console.print(
|
||||
f"[yellow]The routine name has been updated to '{new_name}'[/yellow]\n"
|
||||
)
|
||||
|
||||
# Writing to file
|
||||
with open(routine_file, "w") as file1:
|
||||
lines = ["# OpenBB Terminal - Routine", "\n"]
|
||||
username = get_current_user().profile.username
|
||||
lines += [f"# Author: {username}", "\n\n"] if username else ["\n"]
|
||||
lines += [
|
||||
f"# Title: {SESSION_RECORDED_NAME}",
|
||||
"\n",
|
||||
f"# Tags: {SESSION_RECORDED_TAGS}",
|
||||
"\n\n",
|
||||
f"# Description: {SESSION_RECORDED_DESCRIPTION}",
|
||||
"\n\n",
|
||||
]
|
||||
lines += [c + "\n" for c in SESSION_RECORDED[:-1]]
|
||||
# Writing data to a file
|
||||
file1.writelines(lines)
|
||||
|
||||
console.print(
|
||||
f"[green]Your routine has been recorded and saved here: {routine_file}[/green]\n"
|
||||
)
|
||||
|
||||
# If user doesn't specify they want to store routine locally
|
||||
else:
|
||||
# Confirm that the user is logged in
|
||||
if not is_local():
|
||||
# routine = read_routine(file_name=routine_file)
|
||||
routine = "\n".join(SESSION_RECORDED[:-1])
|
||||
|
||||
if routine is not None:
|
||||
kwargs = {
|
||||
"auth_header": current_user.profile.get_auth_header(),
|
||||
"name": SESSION_RECORDED_NAME,
|
||||
"description": SESSION_RECORDED_DESCRIPTION,
|
||||
"routine": routine,
|
||||
"tags": SESSION_RECORDED_TAGS,
|
||||
"public": SESSION_RECORDED_PUBLIC,
|
||||
"base_url": Hub.BackendEnvironment.BASE_URL,
|
||||
}
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
if response is not None and response.status_code == 409:
|
||||
i = console.input(
|
||||
"A routine with the same name already exists, "
|
||||
"do you want to replace it? (y/n): "
|
||||
)
|
||||
console.print("")
|
||||
if i.lower() in ["y", "yes"]:
|
||||
kwargs["override"] = True # type: ignore
|
||||
response = Hub.upload_routine(**kwargs) # type: ignore
|
||||
else:
|
||||
console.print("[info]Aborted.[/info]")
|
||||
|
||||
# Clear session to be recorded again
|
||||
RECORD_SESSION = False
|
||||
|
||||
@@ -43,7 +43,7 @@ class DegiroController(BaseController):
|
||||
self.__degiro_view = DegiroView()
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
|
||||
zero_to_hundred: dict = {str(c): {} for c in range(0, 100)}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ __docformat__ = "numpy"
|
||||
import datetime
|
||||
import logging
|
||||
import warnings
|
||||
from os import environ
|
||||
from typing import Any, Dict
|
||||
|
||||
import numpy as np
|
||||
@@ -12,6 +11,7 @@ import pandas as pd
|
||||
import yfinance as yf
|
||||
from tqdm import tqdm
|
||||
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.decorators import log_start_end
|
||||
from openbb_terminal.portfolio.allocation_model import get_allocation
|
||||
from openbb_terminal.portfolio.portfolio_helper import (
|
||||
@@ -196,7 +196,7 @@ class PortfolioEngine:
|
||||
|
||||
# Load transactions from file
|
||||
if path.endswith(".xlsx"):
|
||||
if str(environ.get("DEBUG_MODE", "false")).lower() != "true":
|
||||
if not get_current_system().DEBUG_MODE:
|
||||
warnings.filterwarnings(
|
||||
"ignore", category=UserWarning, module="openpyxl"
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ class ParametersController(BaseController):
|
||||
self.DATA_FILES = params_helpers.load_data_files()
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
choices: dict = {c: {} for c in self.controller_choices}
|
||||
choices: dict = self.choices_default
|
||||
choices["set"] = {c: None for c in self.models}
|
||||
choices["set"]["--model"] = {c: None for c in self.models}
|
||||
choices["set"]["-m"] = "--model"
|
||||
|
||||
@@ -21,7 +21,7 @@ from openbb_terminal.core.config.paths import (
|
||||
SETTINGS_ENV_FILE,
|
||||
STYLES_DIRECTORY_REPO,
|
||||
)
|
||||
from openbb_terminal.core.session.constants import CHARTS_TABLES_URL, COLORS_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_user import (
|
||||
get_current_user,
|
||||
is_local,
|
||||
@@ -231,7 +231,7 @@ class SettingsController(BaseController):
|
||||
" Then, place the downloaded file 'openbb_config.richstyle.json'"
|
||||
f" inside {get_current_user().preferences.USER_STYLES_DIRECTORY} or "
|
||||
f"{STYLES_DIRECTORY_REPO}. If you have a hub account you can change colors "
|
||||
f"here {COLORS_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme'}.",
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-s")
|
||||
@@ -246,6 +246,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="settings",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print("Colors updated.")
|
||||
@@ -266,7 +267,7 @@ class SettingsController(BaseController):
|
||||
dest="style",
|
||||
choices=["dark", "light"],
|
||||
help="Choose chart style. If you have a hub account you can change theme "
|
||||
f"here {CHARTS_TABLES_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme/charts-tables'}.",
|
||||
required="-h" not in other_args and "--help" not in other_args,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -282,6 +283,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="terminal_style",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
theme.apply_style(ns_parser.style)
|
||||
@@ -303,7 +305,7 @@ class SettingsController(BaseController):
|
||||
dest="style",
|
||||
choices=["dark", "light"],
|
||||
help="Choose table style. If you have a hub account you can change theme "
|
||||
f"here {CHARTS_TABLES_URL}.",
|
||||
f"here {BackendEnvironment.HUB_URL + 'app/terminal/theme/charts-tables'}.",
|
||||
required="-h" not in other_args and "--help" not in other_args,
|
||||
)
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -319,6 +321,7 @@ class SettingsController(BaseController):
|
||||
value=ns_parser.style,
|
||||
type_="terminal_style",
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.HUB_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print("Table theme updated.\n")
|
||||
|
||||
@@ -8,7 +8,7 @@ import os
|
||||
from pathlib import Path
|
||||
from typing import List, Optional
|
||||
|
||||
from openbb_terminal.core.session.constants import SOURCES_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
|
||||
# IMPORTATION THIRDPARTY
|
||||
# IMPORTATION INTERNAL
|
||||
@@ -54,7 +54,7 @@ class SourcesController(BaseController):
|
||||
if Path(sources_file).exists() and os.stat(sources_file).st_size > 0:
|
||||
self.source = sources_file
|
||||
else:
|
||||
self.source = SOURCES_URL
|
||||
self.source = BackendEnvironment.HUB_URL + "app/terminal/data-sources"
|
||||
|
||||
def parse_input(self, an_input: str) -> List:
|
||||
"""Parse controller input
|
||||
@@ -176,6 +176,7 @@ class SourcesController(BaseController):
|
||||
key="features_sources",
|
||||
value=choices,
|
||||
auth_header=get_current_user().profile.get_auth_header(),
|
||||
base_url=BackendEnvironment.BASE_URL,
|
||||
)
|
||||
console.print("")
|
||||
console.print(
|
||||
|
||||
@@ -20,7 +20,6 @@ import certifi
|
||||
import pandas as pd
|
||||
import requests
|
||||
from prompt_toolkit import PromptSession
|
||||
from prompt_toolkit.completion import NestedCompleter
|
||||
from prompt_toolkit.formatted_text import HTML
|
||||
from prompt_toolkit.styles import Style
|
||||
|
||||
@@ -34,9 +33,10 @@ from openbb_terminal.core.config.paths import (
|
||||
SETTINGS_ENV_FILE,
|
||||
)
|
||||
from openbb_terminal.core.log.generation.custom_logger import log_terminal
|
||||
from openbb_terminal.core.session import session_controller
|
||||
from openbb_terminal.core.session import constants, session_controller
|
||||
from openbb_terminal.core.session.current_system import set_system_variable
|
||||
from openbb_terminal.core.session.current_user import get_current_user, set_preference
|
||||
from openbb_terminal.custom_prompt_toolkit import NestedCompleter
|
||||
from openbb_terminal.helper_funcs import (
|
||||
EXPORT_ONLY_RAW_DATA_ALLOWED,
|
||||
check_positive,
|
||||
@@ -90,6 +90,7 @@ class TerminalController(BaseController):
|
||||
"news",
|
||||
"intro",
|
||||
"askobb",
|
||||
"record",
|
||||
]
|
||||
CHOICES_MENUS = [
|
||||
"stocks",
|
||||
@@ -142,45 +143,10 @@ class TerminalController(BaseController):
|
||||
|
||||
def update_runtime_choices(self):
|
||||
"""Update runtime choices."""
|
||||
self.ROUTINE_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in get_current_user().preferences.USER_ROUTINES_DIRECTORY.rglob(
|
||||
"*.openbb"
|
||||
)
|
||||
}
|
||||
if get_current_user().profile.get_token():
|
||||
self.ROUTINE_DEFAULT_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "default"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
self.ROUTINE_PERSONAL_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "personal"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
|
||||
self.ROUTINE_CHOICES["--file"] = {
|
||||
filename: None for filename in self.ROUTINE_FILES
|
||||
}
|
||||
self.ROUTINE_CHOICES["--example"] = None
|
||||
self.ROUTINE_CHOICES["-e"] = None
|
||||
self.ROUTINE_CHOICES["--input"] = None
|
||||
self.ROUTINE_CHOICES["-i"] = None
|
||||
self.ROUTINE_CHOICES["--help"] = None
|
||||
self.ROUTINE_CHOICES["--h"] = None
|
||||
self.ROUTINE_CHOICES["--url"] = None
|
||||
|
||||
if session and get_current_user().preferences.USE_PROMPT_TOOLKIT:
|
||||
# choices: dict = self.choices_default
|
||||
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
|
||||
choices["news"]["--source"] = {c: {} for c in ["Biztoc", "Feedparser"]}
|
||||
choices["hold"] = {c: None for c in ["on", "off", "-s", "--sameaxis"]}
|
||||
@@ -188,6 +154,56 @@ class TerminalController(BaseController):
|
||||
if biztoc_model.BIZTOC_TAGS:
|
||||
choices["news"]["--tag"] = {c: {} for c in biztoc_model.BIZTOC_TAGS}
|
||||
|
||||
self.ROUTINE_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in get_current_user().preferences.USER_ROUTINES_DIRECTORY.rglob(
|
||||
"*.openbb"
|
||||
)
|
||||
}
|
||||
if get_current_user().profile.get_token():
|
||||
self.ROUTINE_DEFAULT_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "default"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
self.ROUTINE_PERSONAL_FILES = {
|
||||
filepath.name: filepath
|
||||
for filepath in Path(
|
||||
get_current_user().preferences.USER_ROUTINES_DIRECTORY
|
||||
/ "hub"
|
||||
/ "personal"
|
||||
).rglob("*.openbb")
|
||||
}
|
||||
|
||||
choices["exe"] = {
|
||||
"--file": {
|
||||
filename: {} for filename in list(self.ROUTINE_FILES.keys())
|
||||
},
|
||||
"-f": "--file",
|
||||
"--example": None,
|
||||
"-e": "--example",
|
||||
"--input": None,
|
||||
"-i": "--input",
|
||||
"--url": None,
|
||||
}
|
||||
|
||||
choices["record"] = {
|
||||
"--name": None,
|
||||
"-n": "--name",
|
||||
"--description": None,
|
||||
"-d": "--description",
|
||||
"--public": None,
|
||||
"-p": "--public",
|
||||
"--local": None,
|
||||
"-l": "--local",
|
||||
"--tag1": {c: None for c in constants.SCRIPT_TAGS},
|
||||
"--tag2": {c: None for c in constants.SCRIPT_TAGS},
|
||||
"--tag3": {c: None for c in constants.SCRIPT_TAGS},
|
||||
}
|
||||
|
||||
self.completer = NestedCompleter.from_nested_dict(choices)
|
||||
|
||||
def print_help(self):
|
||||
@@ -1085,6 +1101,7 @@ def run_routine(file: str, routines_args=Optional[str]):
|
||||
|
||||
def main(
|
||||
debug: bool,
|
||||
dev: bool,
|
||||
path_list: List[str],
|
||||
routines_args: Optional[List[str]] = None,
|
||||
**kwargs,
|
||||
@@ -1095,6 +1112,8 @@ def main(
|
||||
----------
|
||||
debug : bool
|
||||
Whether to run the terminal in debug mode
|
||||
dev:
|
||||
Points backend towards development environment instead of production
|
||||
test : bool
|
||||
Whether to run the terminal in integrated test mode
|
||||
filtert : str
|
||||
@@ -1114,6 +1133,11 @@ def main(
|
||||
if debug:
|
||||
set_system_variable("DEBUG_MODE", True)
|
||||
|
||||
if dev:
|
||||
set_system_variable("DEV_BACKEND", True)
|
||||
constants.BackendEnvironment.BASE_URL = "https://payments.openbb.dev/"
|
||||
constants.BackendEnvironment.HUB_URL = "https://my.openbb.dev/"
|
||||
|
||||
cfg.start_plot_backend()
|
||||
|
||||
if isinstance(path_list, list) and path_list[0].endswith(".openbb"):
|
||||
@@ -1141,6 +1165,13 @@ def parse_args_and_run():
|
||||
default=False,
|
||||
help="Runs the terminal in debug mode.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--dev",
|
||||
dest="dev",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help="Points backend towards development environment instead of production",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--file",
|
||||
help="The path or .openbb file to run.",
|
||||
@@ -1212,6 +1243,7 @@ def parse_args_and_run():
|
||||
|
||||
main(
|
||||
ns_parser.debug,
|
||||
ns_parser.dev,
|
||||
ns_parser.path,
|
||||
ns_parser.routine_args,
|
||||
module=ns_parser.module,
|
||||
|
||||
@@ -23,7 +23,7 @@ from openbb_terminal import thought_of_the_day as thought
|
||||
from openbb_terminal.base_helpers import load_env_files
|
||||
from openbb_terminal.core.config.paths import HIST_FILE_PATH, SETTINGS_ENV_FILE
|
||||
from openbb_terminal.core.plots.backend import plots_backend
|
||||
from openbb_terminal.core.session.constants import REGISTER_URL
|
||||
from openbb_terminal.core.session.constants import BackendEnvironment
|
||||
from openbb_terminal.core.session.current_system import get_current_system
|
||||
from openbb_terminal.core.session.current_user import (
|
||||
get_current_user,
|
||||
@@ -257,7 +257,8 @@ def print_guest_block_msg():
|
||||
console.print(
|
||||
"[info]You are currently logged as a guest.[/info]\n"
|
||||
"[info]Login to use this feature.[/info]\n\n"
|
||||
f"[info]If you don't have an account, you can create one here: [/info][cmds]{REGISTER_URL}\n[/cmds]"
|
||||
"[info]If you don't have an account, you can create one here: [/info]"
|
||||
f"[cmds]{BackendEnvironment.HUB_URL + 'register'}\n[/cmds]"
|
||||
)
|
||||
|
||||
|
||||
@@ -369,6 +370,7 @@ def reset(queue: Optional[List[str]] = None):
|
||||
plots_backend().close(reset=True)
|
||||
load_env_files()
|
||||
debug = get_current_system().DEBUG_MODE
|
||||
dev = get_current_system().DEV_BACKEND
|
||||
|
||||
try:
|
||||
# save the current user
|
||||
@@ -399,7 +401,7 @@ def reset(queue: Optional[List[str]] = None):
|
||||
if is_local():
|
||||
from openbb_terminal.terminal_controller import main
|
||||
|
||||
main(debug, queue_list, module="") # type: ignore
|
||||
main(debug, dev, queue_list, module="") # type: ignore
|
||||
else:
|
||||
from openbb_terminal.core.session import session_controller
|
||||
|
||||
|
||||
@@ -34,8 +34,9 @@ def main():
|
||||
and ("--login" in sys.argv[1:] or is_installer())
|
||||
and sys.stdin.isatty()
|
||||
)
|
||||
dev = "--dev" in sys.argv[1:]
|
||||
|
||||
session_controller.main(prompt=prompt_login)
|
||||
session_controller.main(prompt=prompt_login, dev=dev)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -46,7 +46,7 @@ def test_create_session_success(email, password):
|
||||
assert response.json() == TEST_RESPONSE
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "login",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "login",
|
||||
json={"email": email, "password": password, "remember": True},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -113,7 +113,7 @@ def test_create_session_from_token_success(mocker, token):
|
||||
assert response.json() == TEST_RESPONSE
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "sdk/login",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "sdk/login",
|
||||
json={"token": token},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -151,7 +151,7 @@ def test_delete_session_success(auth_header, token):
|
||||
assert response.status_code == 200
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "logout",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "logout",
|
||||
headers={"Authorization": "Bearer test_token"},
|
||||
json={"token": "test_token"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
@@ -336,7 +336,7 @@ def test_fetch_user_configs_success(token_type, access_token):
|
||||
assert result == mock_response
|
||||
requests_get_mock.assert_called_once()
|
||||
_, kwargs = requests_get_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {
|
||||
"Authorization": f"{token_type.title()} {access_token}"
|
||||
}
|
||||
@@ -352,7 +352,7 @@ def test_fetch_user_configs_failure():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert isinstance(result, requests.Response)
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -366,7 +366,7 @@ def test_fetch_user_configs_connection_error():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -378,7 +378,7 @@ def test_fetch_user_configs_timeout():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -390,7 +390,7 @@ def test_fetch_user_configs_exception():
|
||||
result = hub_model.fetch_user_configs(session)
|
||||
assert result is None
|
||||
get_mock.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "terminal/user",
|
||||
url=hub_model.BackendEnvironment.BASE_URL + "terminal/user",
|
||||
headers={"Authorization": "Bearer abc123"},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
@@ -415,7 +415,7 @@ def test_upload_config_success(key, value, type_, auth_header):
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": f"{auth_header}"}
|
||||
assert kwargs["json"] == {"key": f"features_{type_}.{key}", "value": value}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -434,7 +434,7 @@ def test_upload_config_failure():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -451,7 +451,7 @@ def test_upload_config_connection_error():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -468,7 +468,7 @@ def test_upload_config_timeout():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -485,7 +485,7 @@ def test_upload_config_exception():
|
||||
assert result is None
|
||||
requests_patch_mock.assert_called_once()
|
||||
_, kwargs = requests_patch_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "terminal/user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "terminal/user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"key": "features_settings.key", "value": "value"}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -504,7 +504,7 @@ def test_clear_user_configs_success():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -523,7 +523,7 @@ def test_clear_user_configs_failure():
|
||||
assert result.status_code == mock_response.status_code
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -539,7 +539,7 @@ def test_clear_user_configs_timeout():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -555,7 +555,7 @@ def test_clear_user_configs_connection_error():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
@@ -570,7 +570,7 @@ def test_clear_user_configs_exception():
|
||||
assert result is None
|
||||
requests_put_mock.assert_called_once()
|
||||
_, kwargs = requests_put_mock.call_args
|
||||
assert kwargs["url"] == hub_model.BASE_URL + "user"
|
||||
assert kwargs["url"] == hub_model.BackendEnvironment.BASE_URL + "user"
|
||||
assert kwargs["headers"] == {"Authorization": "auth_header"}
|
||||
assert kwargs["json"] == {"config": {}}
|
||||
assert kwargs["timeout"] == hub_model.TIMEOUT
|
||||
|
||||
@@ -68,10 +68,10 @@ def no_suppress():
|
||||
@pytest.mark.vcr(record_mode="none")
|
||||
@pytest.mark.record_stdout
|
||||
@pytest.mark.parametrize(
|
||||
"debug, path",
|
||||
[(True, None), (False, ["scripts/test_alt_covid.openbb"])],
|
||||
"debug, dev, path",
|
||||
[(True, False, None), (False, False, ["scripts/test_alt_covid.openbb"])],
|
||||
)
|
||||
def test_menu(mocker, debug, path):
|
||||
def test_menu(mocker, debug, dev, path):
|
||||
mocker.patch(target="terminal_controller.terminal")
|
||||
mocker.patch(target="terminal_controller.suppress_stdout", side_effect=no_suppress)
|
||||
terminal_controller.main(debug, path)
|
||||
terminal_controller.main(debug, dev, path)
|
||||
|
||||
Reference in New Issue
Block a user