diff --git a/README.md b/README.md index 221332fb10d..8c9170ac86c 100644 --- a/README.md +++ b/README.md @@ -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). [![Star History Chart](https://api.star-history.com/svg?repos=openbb-finance/OpenBBTerminal&type=Date)](https://star-history.com/#openbb-finance/OpenBBTerminal&Date) diff --git a/build/docker/compose.env b/build/docker/compose.env index d1c6141e53c..943d85414f3 100644 --- a/build/docker/compose.env +++ b/build/docker/compose.env @@ -1,2 +1,2 @@ OPENBBTERMINAL_DOCKER_REGISTRY="ghcr.io" -OPENBBTERMINAL_DOCKER_RELEASE_VERSION="3.2.0" +OPENBBTERMINAL_DOCKER_RELEASE_VERSION="3.2.1" diff --git a/build/nsis/setup.nsi b/build/nsis/setup.nsi index d80b4ffaf05..8bb8de9696f 100644 --- a/build/nsis/setup.nsi +++ b/build/nsis/setup.nsi @@ -10,7 +10,7 @@ !define NAME "OpenBB Terminal" !define COMPANY "OpenBB" !define APPFILE "OpenBBTerminal.exe" - !define VERSION "3.2.0" + !define VERSION "3.2.1" !define SLUG "${NAME} v${VERSION}" ;-------------------------------- @@ -20,8 +20,8 @@ VIAddVersionKey Comments "An installer for OpenBB Terminal. For additional details, visit OpenBB.co" VIAddVersionKey CompanyName OpenBB.co VIAddVersionKey FileDescription "OpenBB Terminal Program" - VIAddVersionKey FileVersion 3.2.0.0 - VIAddVersionKey ProductVersion 3.2.0.0 + VIAddVersionKey FileVersion 3.2.1.0 + VIAddVersionKey ProductVersion 3.2.1.0 VIAddVersionKey InternalName "OpenBB Terminal" ;-------------------------------- diff --git a/build/pyinstaller/version.rc b/build/pyinstaller/version.rc index 444f270896b..76cb484c2c8 100644 --- a/build/pyinstaller/version.rc +++ b/build/pyinstaller/version.rc @@ -32,10 +32,10 @@ VSVersionInfo( [StringStruct('Comments', 'The OpenBB Terminal. For additional details, visit OpenBB.co'), StringStruct('CompanyName', 'OpenBB'), StringStruct('FileDescription', 'OpenBB Terminal Program'), - StringStruct('FileVersion', '3.2.0.0'), + StringStruct('FileVersion', '3.2.1.0'), StringStruct('InternalName', 'OpenBB Terminal'), StringStruct('ProductName', 'OpenBB Terminal'), - StringStruct('ProductVersion', '3.2.0.0')]) + StringStruct('ProductVersion', '3.2.1.0')]) ]), VarFileInfo([VarStruct('Translation', [1033, 1200])]) ] diff --git a/openbb_terminal/account/account_controller.py b/openbb_terminal/account/account_controller.py index 12b26bb8869..8db4d421c25 100644 --- a/openbb_terminal/account/account_controller.py +++ b/openbb_terminal/account/account_controller.py @@ -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: diff --git a/openbb_terminal/common/behavioural_analysis/reddit_view.py b/openbb_terminal/common/behavioural_analysis/reddit_view.py index 2855c5349cc..0c0f87c46f9 100644 --- a/openbb_terminal/common/behavioural_analysis/reddit_view.py +++ b/openbb_terminal/common/behavioural_analysis/reddit_view.py @@ -1,6 +1,7 @@ """Reddit View.""" __docformat__ = "numpy" +import io import logging import os import textwrap @@ -212,10 +213,10 @@ def display_wsb_community(limit: int = 10, new: bool = False): Flag to sort by new instead of hot, by default False """ subs = reddit_model.get_wsb_community(limit, new) + # I am not proud of this, but it works to eliminate the max recursion bug + subs = pd.read_csv(io.StringIO(subs.to_csv()), index_col=0).fillna("-") if not subs.empty: - # for sub in subs.iterrows(): - # print_reddit_post(sub) - print(print_rich_table(subs)) + print_rich_table(subs) @log_start_end(log=logger) diff --git a/openbb_terminal/common/ultima_newsmonitor_model.py b/openbb_terminal/common/ultima_newsmonitor_model.py index b4e3782ac0d..656ba75c53f 100644 --- a/openbb_terminal/common/ultima_newsmonitor_model.py +++ b/openbb_terminal/common/ultima_newsmonitor_model.py @@ -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 diff --git a/openbb_terminal/core/completer/choices.py b/openbb_terminal/core/completer/choices.py index eff17a6f1fd..fabfb46c384 100644 --- a/openbb_terminal/core/completer/choices.py +++ b/openbb_terminal/core/completer/choices.py @@ -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 diff --git a/openbb_terminal/core/models/system_model.py b/openbb_terminal/core/models/system_model.py index 85d61e7b1bf..7f478d30436 100644 --- a/openbb_terminal/core/models/system_model.py +++ b/openbb_terminal/core/models/system_model.py @@ -28,7 +28,7 @@ class SystemModel(BaseModel): PLATFORM: str = str(platform.platform()) # OpenBB section - VERSION: str = "3.2.0" + VERSION: str = "3.2.1" # Logging section LOGGING_APP_ID: str = "REPLACE_ME" @@ -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 diff --git a/openbb_terminal/core/plots/backend.py b/openbb_terminal/core/plots/backend.py index ba82753ab6d..af6a29e2947 100644 --- a/openbb_terminal/core/plots/backend.py +++ b/openbb_terminal/core/plots/backend.py @@ -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, diff --git a/openbb_terminal/core/sdk/controllers/stocks_sdk_controller.py b/openbb_terminal/core/sdk/controllers/stocks_sdk_controller.py index 7918c33d017..676362d2e6e 100644 --- a/openbb_terminal/core/sdk/controllers/stocks_sdk_controller.py +++ b/openbb_terminal/core/sdk/controllers/stocks_sdk_controller.py @@ -59,7 +59,6 @@ class StocksController(model.StocksRoot): `sentiment_chart`: Plots sentiments from symbol\n `snews`: Get headlines sentiment using VADER model over time. [Source: Finnhub]\n `snews_chart`: Display stock price and headlines sentiment using VADER model over time. [Source: Finnhub]\n - `spacc`: Get top tickers from r/SPACs [Source: reddit].\n `stalker`: Gets messages from given user [Source: stocktwits].\n `text_sent`: Find the sentiment of a post and related comments.\n `trending`: Get trending tickers from stocktwits [Source: stocktwits].\n diff --git a/openbb_terminal/core/sdk/models/stocks_sdk_model.py b/openbb_terminal/core/sdk/models/stocks_sdk_model.py index 0a2ba28f2f8..f0e4c74c4ac 100644 --- a/openbb_terminal/core/sdk/models/stocks_sdk_model.py +++ b/openbb_terminal/core/sdk/models/stocks_sdk_model.py @@ -59,7 +59,6 @@ class StocksBehavioralAnalysis(Category): `sentiment_chart`: Plots sentiments from symbol\n `snews`: Get headlines sentiment using VADER model over time. [Source: Finnhub]\n `snews_chart`: Display stock price and headlines sentiment using VADER model over time. [Source: Finnhub]\n - `spacc`: Get top tickers from r/SPACs [Source: reddit].\n `stalker`: Gets messages from given user [Source: stocktwits].\n `text_sent`: Find the sentiment of a post and related comments.\n `trending`: Get trending tickers from stocktwits [Source: stocktwits].\n @@ -94,7 +93,6 @@ class StocksBehavioralAnalysis(Category): self.snews_chart = ( lib.stocks_ba_finnhub_view.display_stock_price_headlines_sentiment ) - self.spacc = lib.stocks_ba_reddit_model.get_spac_community self.stalker = lib.stocks_ba_stocktwits_model.get_stalker self.text_sent = lib.stocks_ba_reddit_model.get_sentiment self.trending = lib.stocks_ba_stocktwits_model.get_trending diff --git a/openbb_terminal/core/sdk/trail_map.csv b/openbb_terminal/core/sdk/trail_map.csv index 63682195424..a7e369182cd 100644 --- a/openbb_terminal/core/sdk/trail_map.csv +++ b/openbb_terminal/core/sdk/trail_map.csv @@ -400,7 +400,6 @@ stocks.ba.regions,stocks_ba_google_model.get_regions,stocks_ba_google_view.displ stocks.ba.rise,stocks_ba_google_model.get_rise, stocks.ba.sentiment,stocks_ba_twitter_model.get_sentiment,stocks_ba_twitter_view.display_sentiment stocks.ba.snews,stocks_ba_finnhub_model.get_headlines_sentiment,stocks_ba_finnhub_view.display_stock_price_headlines_sentiment -stocks.ba.spacc,stocks_ba_reddit_model.get_spac_community, stocks.ba.stalker,stocks_ba_stocktwits_model.get_stalker, stocks.ba.text_sent,stocks_ba_reddit_model.get_sentiment, stocks.ba.trending,stocks_ba_stocktwits_model.get_trending, diff --git a/openbb_terminal/core/session/constants.py b/openbb_terminal/core/session/constants.py index 252b362d165..83b9b854aac 100644 --- a/openbb_terminal/core/session/constants.py +++ b/openbb_terminal/core/session/constants.py @@ -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" diff --git a/openbb_terminal/core/session/hub_model.py b/openbb_terminal/core/session/hub_model.py index f47412a46b0..8c711b10d07 100644 --- a/openbb_terminal/core/session/hub_model.py +++ b/openbb_terminal/core/session/hub_model.py @@ -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. diff --git a/openbb_terminal/core/session/routines_handler.py b/openbb_terminal/core/session/routines_handler.py index bef93b1e747..56f185aaf2d 100644 --- a/openbb_terminal/core/session/routines_handler.py +++ b/openbb_terminal/core/session/routines_handler.py @@ -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: diff --git a/openbb_terminal/core/session/session_controller.py b/openbb_terminal/core/session/session_controller.py index 4069106a971..6d26fb29784 100644 --- a/openbb_terminal/core/session/session_controller.py +++ b/openbb_terminal/core/session/session_controller.py @@ -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 diff --git a/openbb_terminal/core/session/session_model.py b/openbb_terminal/core/session/session_model.py index a0e9732e499..5140932fe8e 100644 --- a/openbb_terminal/core/session/session_model.py +++ b/openbb_terminal/core/session/session_model.py @@ -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 diff --git a/openbb_terminal/econometrics/econometrics_controller.py b/openbb_terminal/econometrics/econometrics_controller.py index 03b1a9a538d..5229e030e5a 100644 --- a/openbb_terminal/econometrics/econometrics_controller.py +++ b/openbb_terminal/econometrics/econometrics_controller.py @@ -56,7 +56,6 @@ class EconometricsController(BaseController): "type", "desc", "corr", - "season", "index", "clean", "add", @@ -165,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", @@ -188,9 +187,9 @@ class EconometricsController(BaseController): "granger", "coint", "corr", - "season", "lag", "vif", + "panel", ]: choices[feature] = dict() @@ -216,7 +215,6 @@ class EconometricsController(BaseController): "norm", "root", "coint", - "season", "lag", "regressions", "ols", @@ -279,7 +277,6 @@ class EconometricsController(BaseController): mt.add_cmd("type", self.files) mt.add_cmd("desc", self.files) mt.add_cmd("corr", self.files) - mt.add_cmd("season", self.files) mt.add_cmd("index", self.files) mt.add_cmd("clean", self.files) mt.add_cmd("add", self.files) @@ -752,79 +749,6 @@ class EconometricsController(BaseController): ns_parser.export, ) - @log_start_end(log=logger) - def call_season(self, other_args: List[str]): - """Process season command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="season", - description="The seasonality for a given column", - ) - parser.add_argument( - "-v", - "--values", - help="Dataset.column values to be displayed in a plot", - dest="values", - choices={ - f"{dataset}.{column}": {column: None, dataset: None} - for dataset, dataframe in self.datasets.items() - for column in dataframe.columns - }, - type=str, - ) - parser.add_argument( - "-m", - help="A time lag to highlight on the plot", - dest="m", - type=int, - default=None, - ) - parser.add_argument( - "--max_lag", - help="The maximal lag order to consider", - dest="max_lag", - type=int, - default=24, - ) - parser.add_argument( - "-a", - "--alpha", - help="The confidence interval to display", - dest="alpha", - type=float, - default=0.05, - ) - if other_args and "-" not in other_args[0][0]: - other_args.insert(0, "-v") - ns_parser = self.parse_known_args_and_warn( - parser, other_args, export_allowed=EXPORT_ONLY_FIGURES_ALLOWED - ) - - if not ns_parser: - return - - if not ns_parser.values: - console.print("[red]Please enter valid dataset.\n[/red]") - return - - try: - dataset, col = ns_parser.values.split(".") - data = self.datasets[dataset] - data.name = dataset - except ValueError: - console.print("[red]Please enter 'dataset'.'column'.[/red]\n") - return - - econometrics_view.display_seasonality( - data=data, - column=col, - export=ns_parser.export, - m=ns_parser.m, - max_lag=ns_parser.max_lag, - alpha=ns_parser.alpha, - ) - @log_start_end(log=logger) def call_type(self, other_args: List[str]): """Process type command""" diff --git a/openbb_terminal/econometrics/econometrics_view.py b/openbb_terminal/econometrics/econometrics_view.py index 6bebc81065a..6a34ffc126c 100644 --- a/openbb_terminal/econometrics/econometrics_view.py +++ b/openbb_terminal/econometrics/econometrics_view.py @@ -200,63 +200,6 @@ def display_corr( return fig.show(external=external_axes) -@log_start_end(log=logger) -def display_seasonality( - data: pd.DataFrame, - column: str = "close", - export: str = "", - sheet_name: Optional[str] = None, - m: Optional[int] = None, - max_lag: int = 24, - alpha: float = 0.05, - external_axes: bool = False, -) -> Union[OpenBBFigure, None]: - """Plot seasonality from a dataset - - Parameters - ---------- - data: pd.DataFrame - The dataframe to plot - column: str - The column of the dataframe to analyze - sheet_name: str - Optionally specify the name of the sheet the data is exported to. - export: str - Format to export image - m: Optional[int] - Optionally, a time lag to highlight on the plot. Default is none. - max_lag: int - The maximal lag order to consider. Default is 24. - alpha: float - The confidence interval to display. Default is 0.05. - external_axes : bool, optional - Whether to return the figure object or not, by default False - """ - - if data.empty: - return console.print("No data to plot") - - series = data[column] - - ending = get_ending(data.name, column) - - fig = OpenBBFigure() - fig.set_title(f"Seasonality{ending}", wrap=True, wrap_width=55) - fig.add_corr_plot(series, m=m, max_lag=max_lag, alpha=alpha) - fig.update_xaxes(autorange=False, range=[-1, max_lag + 1]) - fig.add_legend_label() - - export_data( - export, - os.path.dirname(os.path.abspath(__file__)), - "plot", - sheet_name=sheet_name, - figure=fig, - ) - - return fig.show(external=external_axes) - - @log_start_end(log=logger) def display_norm( data: pd.Series, diff --git a/openbb_terminal/economy/quantitative_analysis/qa_controller.py b/openbb_terminal/economy/quantitative_analysis/qa_controller.py index a188b9b8e22..f35048f26e1 100644 --- a/openbb_terminal/economy/quantitative_analysis/qa_controller.py +++ b/openbb_terminal/economy/quantitative_analysis/qa_controller.py @@ -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}, diff --git a/openbb_terminal/economy/yfinance_model.py b/openbb_terminal/economy/yfinance_model.py index df410b4e26c..c8c92fbe61c 100644 --- a/openbb_terminal/economy/yfinance_model.py +++ b/openbb_terminal/economy/yfinance_model.py @@ -646,7 +646,6 @@ def get_index( end=end_date, interval=interval, progress=False, - show_errors=False, ignore_tz=True, ) diff --git a/openbb_terminal/featflags_controller.py b/openbb_terminal/featflags_controller.py index 43ef32893e6..b3d3374819d 100644 --- a/openbb_terminal/featflags_controller.py +++ b/openbb_terminal/featflags_controller.py @@ -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): diff --git a/openbb_terminal/forecast/forecast_controller.py b/openbb_terminal/forecast/forecast_controller.py index b4386fa6e75..218fcd66d40 100644 --- a/openbb_terminal/forecast/forecast_controller.py +++ b/openbb_terminal/forecast/forecast_controller.py @@ -1115,8 +1115,8 @@ class ForecastController(BaseController): description="The seasonality for a given column", ) parser.add_argument( - "-v", - "--values", + "-d", + "--dataset", help="Dataset.column values to be displayed in a plot", dest="values", choices=self.get_dataset_columns(), diff --git a/openbb_terminal/futures/sdk_helper.py b/openbb_terminal/futures/sdk_helper.py index 7115b782be1..94688eac5d8 100644 --- a/openbb_terminal/futures/sdk_helper.py +++ b/openbb_terminal/futures/sdk_helper.py @@ -16,7 +16,29 @@ def get_historical( source: Optional[str] = "YahooFinance", expiry: Optional[str] = "", ) -> pd.DataFrame: - """Get historical futures data""" + """Get historical futures data + + Parameters + ---------- + symbols : Union[str, List[str]] + The futures symbols you want to retrieve historical data for. + It can be either a single symbol as a string or a list of symbols. + start_date : str + The start date of the historical data you want to retrieve. The date should be in the format "YYYY-MM-DD". + end_date : str + The end date of the historical data you want to retrieve. The date should be in the format "YYYY-MM-DD". + source : Optional[str], default "YahooFinance" + The source from which you want to retrieve the historical data. + Valid values for the source are "YahooFinance" and "DataBento". + expiry : Optional[str], default "" + The expiry date for futures contracts. This parameter is optional and defaults to an empty string. + It is applicable only when the source is "YahooFinance" and the symbols are futures contracts. + + Returns + ------- + pd.DataFrame + A pandas DataFrame containing the historical data for the given symbols and date range. + """ if source == "YahooFinance": if isinstance(symbols, str): symbols = [symbols] diff --git a/openbb_terminal/keys_controller.py b/openbb_terminal/keys_controller.py index 3a522f68b64..69c94595a53 100644 --- a/openbb_terminal/keys_controller.py +++ b/openbb_terminal/keys_controller.py @@ -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""" diff --git a/openbb_terminal/parent_classes.py b/openbb_terminal/parent_classes.py index f3600597df5..11d31d2a52f 100644 --- a/openbb_terminal/parent_classes.py +++ b/openbb_terminal/parent_classes.py @@ -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,107 @@ 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 "" + pattern = re.compile(r"^[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 +1047,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 diff --git a/openbb_terminal/portfolio/brokers/degiro/degiro_controller.py b/openbb_terminal/portfolio/brokers/degiro/degiro_controller.py index fdae00fab59..bae880cd568 100644 --- a/openbb_terminal/portfolio/brokers/degiro/degiro_controller.py +++ b/openbb_terminal/portfolio/brokers/degiro/degiro_controller.py @@ -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)} diff --git a/openbb_terminal/portfolio/portfolio_engine.py b/openbb_terminal/portfolio/portfolio_engine.py index 22adcd191e9..2c945b661d5 100644 --- a/openbb_terminal/portfolio/portfolio_engine.py +++ b/openbb_terminal/portfolio/portfolio_engine.py @@ -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" ) diff --git a/openbb_terminal/portfolio/portfolio_optimization/parameters/params_controller.py b/openbb_terminal/portfolio/portfolio_optimization/parameters/params_controller.py index 472f0d24bd4..8d92c0188ab 100644 --- a/openbb_terminal/portfolio/portfolio_optimization/parameters/params_controller.py +++ b/openbb_terminal/portfolio/portfolio_optimization/parameters/params_controller.py @@ -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" diff --git a/openbb_terminal/settings_controller.py b/openbb_terminal/settings_controller.py index 4d0b31e6007..4ba909c0021 100644 --- a/openbb_terminal/settings_controller.py +++ b/openbb_terminal/settings_controller.py @@ -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") diff --git a/openbb_terminal/sources_controller.py b/openbb_terminal/sources_controller.py index eebedbe7904..d6483057bbf 100644 --- a/openbb_terminal/sources_controller.py +++ b/openbb_terminal/sources_controller.py @@ -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( diff --git a/openbb_terminal/stocks/behavioural_analysis/ba_controller.py b/openbb_terminal/stocks/behavioural_analysis/ba_controller.py index 30cf872117e..00953436ee6 100644 --- a/openbb_terminal/stocks/behavioural_analysis/ba_controller.py +++ b/openbb_terminal/stocks/behavioural_analysis/ba_controller.py @@ -47,7 +47,6 @@ class BehaviouralAnalysisController(StockBaseController): "load", "wsb", "popular", - "spacc", "getdd", "redditsent", "bullbear", @@ -97,7 +96,6 @@ class BehaviouralAnalysisController(StockBaseController): mt.add_cmd("snews", self.ticker) mt.add_cmd("wsb") mt.add_cmd("popular") - mt.add_cmd("spacc") mt.add_cmd("getdd") mt.add_cmd("redditsent", self.ticker) mt.add_cmd("trending") @@ -137,40 +135,6 @@ class BehaviouralAnalysisController(StockBaseController): symbol=self.ticker, export=ns_parser.export ) - @log_start_end(log=logger) - def call_spacc(self, other_args: List[str]): - """Process spacc command.""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="spacc", - description="""Print other users SPACs announcement under subreddit 'SPACs'. [Source: Reddit]""", - ) - parser.add_argument( - "-l", - "--limit", - action="store", - dest="n_limit", - type=check_positive, - default=10, - help="limit of posts with SPACs retrieved", - ) - parser.add_argument( - "-p", - "--popular", - action="store_true", - default=False, - dest="b_popular", - help="popular flag, if true the posts retrieved are based on score rather than time", - ) - if other_args and "-" not in other_args[0][0]: - other_args.insert(0, "-l") - ns_parser = self.parse_known_args_and_warn(parser, other_args) - if ns_parser: - reddit_view.display_spac_community( - limit=ns_parser.n_limit, popular=ns_parser.b_popular - ) - @log_start_end(log=logger) def call_wsb(self, other_args: List[str]): """Process wsb command.""" diff --git a/openbb_terminal/stocks/comparison_analysis/ca_controller.py b/openbb_terminal/stocks/comparison_analysis/ca_controller.py index 464bf83b8fa..8e1225ae1c1 100644 --- a/openbb_terminal/stocks/comparison_analysis/ca_controller.py +++ b/openbb_terminal/stocks/comparison_analysis/ca_controller.py @@ -442,7 +442,10 @@ class ComparisonAnalysisController(BaseController): other_args.insert(0, "-s") ns_parser = self.parse_known_args_and_warn(parser, other_args) if ns_parser: - self.similar = list(set(ns_parser.l_similar + [self.ticker.upper()])) + if self.ticker: + self.similar = list(set(ns_parser.l_similar + [self.ticker.upper()])) + else: + self.similar = list(set(ns_parser.l_similar)) self.user = "Custom" console.print( f"[{self.user}] Similar Companies: {', '.join(self.similar)}", "\n" diff --git a/openbb_terminal/stocks/government/quiverquant_model.py b/openbb_terminal/stocks/government/quiverquant_model.py index e0428525f86..81f28d42cd8 100644 --- a/openbb_terminal/stocks/government/quiverquant_model.py +++ b/openbb_terminal/stocks/government/quiverquant_model.py @@ -275,8 +275,8 @@ def get_government_buys( else -float(x["min"]), axis=1, ) - - df_gov = df_gov.sort_values("TransactionDate", ascending=True) + df_gov = df_gov[df_gov.Transaction == "Purchase"] + df_gov = df_gov.sort_values(by="Amount", ascending=False).reset_index(drop=True) return df_gov @@ -348,7 +348,11 @@ def get_government_sells( ) df_gov = df_gov.sort_values("TransactionDate", ascending=True) - + df_gov = ( + df_gov[df_gov.Transaction == "Sale"] + .sort_values(by="Amount", key=lambda x: abs(x), ascending=False) + .reset_index(drop=True) + ) return df_gov diff --git a/openbb_terminal/stocks/options/yfinance_view.py b/openbb_terminal/stocks/options/yfinance_view.py index 27e6236ca0d..1359a79523c 100644 --- a/openbb_terminal/stocks/options/yfinance_view.py +++ b/openbb_terminal/stocks/options/yfinance_view.py @@ -320,8 +320,8 @@ def display_vol_surface( tick_kwargs = dict(tickfont=dict(size=13), titlefont=dict(size=16)) fig.update_layout( scene=dict( - xaxis=dict(title="Strike", **tick_kwargs), - yaxis=dict(title="DTE", **tick_kwargs), + xaxis=dict(title="DTE", **tick_kwargs), + yaxis=dict(title="Strike", **tick_kwargs), zaxis=dict(title=z, **tick_kwargs), ) ) diff --git a/openbb_terminal/terminal_controller.py b/openbb_terminal/terminal_controller.py index 7e3df6be9f3..84453250a20 100644 --- a/openbb_terminal/terminal_controller.py +++ b/openbb_terminal/terminal_controller.py @@ -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,44 +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 - 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"]} @@ -187,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): @@ -1084,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, @@ -1094,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 @@ -1113,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"): @@ -1140,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.", @@ -1211,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, diff --git a/openbb_terminal/terminal_helper.py b/openbb_terminal/terminal_helper.py index 81f3ff7e33e..63458b34186 100644 --- a/openbb_terminal/terminal_helper.py +++ b/openbb_terminal/terminal_helper.py @@ -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 diff --git a/poetry.lock b/poetry.lock index 00c92419841..62d5970ce68 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2298,13 +2298,13 @@ user_agent = "*" [[package]] name = "finvizfinance" -version = "0.14.5" +version = "0.14.6rc2" description = "Finviz Finance. Information downloader." optional = false python-versions = ">=3.5" files = [ - {file = "finvizfinance-0.14.5-py3-none-any.whl", hash = "sha256:1b22bfd7af36f01a08c6032e19f64e810ae3f42bfba681e9a2132226a5a90924"}, - {file = "finvizfinance-0.14.5.tar.gz", hash = "sha256:c97fe0e69d681d9108113aed943988561665d0d4dbd64ffa0b666a2899c25899"}, + {file = "finvizfinance-0.14.6rc2-py3-none-any.whl", hash = "sha256:70742b5054e84fbe5a1ffcc7cad97ca9225292e07ce0349dcb78462d5e5e51a0"}, + {file = "finvizfinance-0.14.6rc2.tar.gz", hash = "sha256:736f3064faac1f8ba6d06fdd7c77f79a3e831c2048fc6442759861fce4c4a6e8"}, ] [package.dependencies] @@ -10495,4 +10495,4 @@ optimization = ["Riskfolio-Lib"] [metadata] lock-version = "2.0" python-versions = "^3.8.1,<3.11, !=3.9.7" -content-hash = "10cccda4c8b51c57241490d53d46268092e6ffe9054c8ef22b7e58477ad3b98c" +content-hash = "cf28c86b1360b436443a486b5ed8b33101e35d3a6c02f81c7dc85515e520c634" diff --git a/pyproject.toml b/pyproject.toml index 5de047c19a5..8681c607b34 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "openbb" -version = "3.2.0" +version = "3.2.1" description = "Investment Research for Everyone, Anywhere." license = "MIT" authors = ["Didier Rodrigues Lopes"] @@ -42,7 +42,7 @@ robin-stocks = "^2.0.3" pycoingecko = "^3.1.0" detecta = "^0.0.5" tradingview-ta = "^3.2.3" -finvizfinance = "^0.14.0" +finvizfinance = "0.14.6rc2" statsmodels = "^0.13" python-coinmarketcap = "^0.2" oandapyV20 = "^0.6.3" diff --git a/requirements-full.txt b/requirements-full.txt index b0e0a4e733e..7fea20f1211 100644 --- a/requirements-full.txt +++ b/requirements-full.txt @@ -98,7 +98,7 @@ filelock==3.12.2 ; python_full_version >= "3.8.1" and python_full_version != "3. financedatabase==2.1.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" finnhub-python==2.4.18 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" finviz==1.4.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" -finvizfinance==0.14.5 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" +finvizfinance==0.14.6rc2 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" flake8==6.0.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" flask==2.3.2 ; python_full_version >= "3.8.1" and python_version < "3.11" and python_full_version != "3.9.7" fonttools==4.41.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" diff --git a/requirements.txt b/requirements.txt index 08ea43f9aa6..507bae43bea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -65,7 +65,7 @@ ffn==0.3.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" a financedatabase==2.1.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" finnhub-python==2.4.18 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" finviz==1.4.6 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" -finvizfinance==0.14.5 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" +finvizfinance==0.14.6rc2 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" flake8==6.0.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" fonttools==4.41.0 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" formulaic==0.6.4 ; python_full_version >= "3.8.1" and python_full_version != "3.9.7" and python_version < "3.11" diff --git a/terminal.py b/terminal.py index dd0977a5f62..f9d8d8e5248 100644 --- a/terminal.py +++ b/terminal.py @@ -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__": diff --git a/tests/openbb_terminal/account/test_account_controller.py b/tests/openbb_terminal/account/test_account_controller.py index 6cbfb4edb3d..5dbbaa7ba5c 100644 --- a/tests/openbb_terminal/account/test_account_controller.py +++ b/tests/openbb_terminal/account/test_account_controller.py @@ -404,7 +404,10 @@ def test_call_list(mocker, test_user): controller.call_list(other_args=["--page", "1", "--size", "10"]) mock_list_routines.assert_called_once_with( - auth_header="Bearer 123", page=1, size=10 + auth_header="Bearer 123", + page=1, + size=10, + base_url="https://payments.openbb.co/", ) @@ -446,6 +449,7 @@ def test_call_upload(mocker, test_user): routine="do something", tags="stocks", public=False, + base_url="https://payments.openbb.co/", ) @@ -484,6 +488,7 @@ def test_call_download(mocker, test_user): mock_download_routine.assert_called_once_with( auth_header="Bearer 123", uuid="script1", + base_url="https://payments.openbb.co/", ) mock_save_routine.assert_called_once_with( file_name="script1.openbb", routine=["do something", "personal"] @@ -555,6 +560,7 @@ def test_call_generate(mocker, monkeypatch, test_user): mock_generate.assert_called_once_with( auth_header="Bearer 123", + base_url="https://payments.openbb.co/", days=30, ) diff --git a/tests/openbb_terminal/session/test_hub_model.py b/tests/openbb_terminal/session/test_hub_model.py index 25f620deef9..008325c9300 100644 --- a/tests/openbb_terminal/session/test_hub_model.py +++ b/tests/openbb_terminal/session/test_hub_model.py @@ -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, @@ -233,7 +233,9 @@ def test_get_session_success(): ) as create_session_mock: result = hub_model.get_session("email", "password") assert result == {"session": "info"} - create_session_mock.assert_called_once_with("email", "password") + create_session_mock.assert_called_once_with( + "email", "password", base_url="https://payments.openbb.co/" + ) def test_get_session_401(): @@ -246,7 +248,9 @@ def test_get_session_401(): ) as create_session_mock: result = hub_model.get_session("email", "password") assert result == {} - create_session_mock.assert_called_once_with("email", "password") + create_session_mock.assert_called_once_with( + "email", "password", base_url="https://payments.openbb.co/" + ) def test_get_session_403(): @@ -259,7 +263,9 @@ def test_get_session_403(): ) as create_session_mock: result = hub_model.get_session("email", "password") assert result == {} - create_session_mock.assert_called_once_with("email", "password") + create_session_mock.assert_called_once_with( + "email", "password", base_url="https://payments.openbb.co/" + ) def test_get_session_failed_to_request(): @@ -268,7 +274,9 @@ def test_get_session_failed_to_request(): ) as create_session_mock: result = hub_model.get_session("email", "password") assert result == {} - create_session_mock.assert_called_once_with("email", "password") + create_session_mock.assert_called_once_with( + "email", "password", base_url="https://payments.openbb.co/" + ) def test_get_session_from_token(): @@ -282,7 +290,9 @@ def test_get_session_from_token(): ) as create_session_mock: result = hub_model.get_session_from_token("token") assert result == {"session": "info"} - create_session_mock.assert_called_once_with("token") + create_session_mock.assert_called_once_with( + "token", base_url="https://payments.openbb.co/" + ) def test_get_session_from_token_401(): @@ -295,7 +305,9 @@ def test_get_session_from_token_401(): ) as create_session_mock: result = hub_model.get_session_from_token("token") assert result == {} - create_session_mock.assert_called_once_with("token") + create_session_mock.assert_called_once_with( + "token", base_url="https://payments.openbb.co/" + ) def test_get_session_from_token_403(): @@ -308,7 +320,9 @@ def test_get_session_from_token_403(): ) as create_session_mock: result = hub_model.get_session_from_token("token") assert result == {} - create_session_mock.assert_called_once_with("token") + create_session_mock.assert_called_once_with( + "token", base_url="https://payments.openbb.co/" + ) def test_get_session_from_token_failed_to_request(): @@ -318,7 +332,9 @@ def test_get_session_from_token_failed_to_request(): ) as create_session_mock: result = hub_model.get_session_from_token("token") assert result == {} - create_session_mock.assert_called_once_with("token") + create_session_mock.assert_called_once_with( + "token", base_url="https://payments.openbb.co/" + ) @pytest.mark.parametrize("token_type, access_token", [("TokenType", "AccessToken")]) @@ -336,7 +352,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 +368,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 +382,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 +394,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 +406,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 +431,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 +450,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 +467,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 +484,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 +501,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 +520,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 +539,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 +555,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 +571,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 +586,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 diff --git a/tests/openbb_terminal/session/test_routines_handler.py b/tests/openbb_terminal/session/test_routines_handler.py index 566c275fd10..e62c0fc1b0e 100644 --- a/tests/openbb_terminal/session/test_routines_handler.py +++ b/tests/openbb_terminal/session/test_routines_handler.py @@ -234,6 +234,7 @@ def test_download_routine(mocker, test_user, silent=False): fields=["name", "script"], page=1, size=100, + base_url="https://payments.openbb.co/", silent=silent, ) @@ -272,6 +273,7 @@ def test_download_default_routine_exception(mocker, test_user, silent=False): fields=["name", "script"], page=1, size=100, + base_url="https://payments.openbb.co/", silent=silent, ) @@ -310,6 +312,7 @@ def test_download_personal_routine_exception(mocker, test_user, silent=False): fields=["name", "script"], page=1, size=100, + base_url="https://payments.openbb.co/", silent=silent, ) @@ -339,5 +342,6 @@ def test_download_default_and_personal_routine_exception( fields=["name", "script"], page=1, size=100, + base_url="https://payments.openbb.co/", silent=silent, ) diff --git a/tests/openbb_terminal/session/test_session_model.py b/tests/openbb_terminal/session/test_session_model.py index 25861d3c6bf..138c9af8a6f 100644 --- a/tests/openbb_terminal/session/test_session_model.py +++ b/tests/openbb_terminal/session/test_session_model.py @@ -75,7 +75,9 @@ def test_login_no_response(mocker): assert session_model.login(TEST_SESSION) == session_model.LoginStatus.NO_RESPONSE - mock_fetch_user_configs.assert_called_once_with(TEST_SESSION) + mock_fetch_user_configs.assert_called_once_with( + TEST_SESSION, "https://payments.openbb.co/" + ) mock_apply_configs.assert_not_called() mock_update_flair.assert_not_called() mock_get_updated_hub_sources.assert_not_called() @@ -96,7 +98,9 @@ def test_login_fail_response(mocker): assert session_model.login(TEST_SESSION) == session_model.LoginStatus.FAILED - mock_fetch_user_configs.assert_called_once_with(TEST_SESSION) + mock_fetch_user_configs.assert_called_once_with( + TEST_SESSION, "https://payments.openbb.co/" + ) mock_apply_configs.assert_not_called() mock_update_flair.assert_not_called() mock_get_updated_hub_sources.assert_not_called() @@ -119,7 +123,9 @@ def test_login_success_response(mocker): assert session_model.login(TEST_SESSION) == session_model.LoginStatus.SUCCESS - mock_fetch_user_configs.assert_called_once_with(TEST_SESSION) + mock_fetch_user_configs.assert_called_once_with( + TEST_SESSION, "https://payments.openbb.co/" + ) mock_apply_configs.assert_called_once() mock_update_flair.assert_called_once() @@ -142,10 +148,13 @@ def test_logout_user(mocker, guest): auth_header = "Bearer test_token" token = "test_token" + base_url = "https://payments.openbb.co/" session_model.logout(auth_header, token) if not guest: - mock_delete_session.assert_called_once_with(auth_header, token) + mock_delete_session.assert_called_once_with( + auth_header, token, base_url=base_url + ) assert mock_remove.call_args_list[0] == mocker.call(SESSION_FILE_PATH) assert mock_remove.call_args_list[1] == mocker.call(HIST_FILE_PATH) assert mock_remove.call_args_list[2] == mocker.call( diff --git a/tests/openbb_terminal/stocks/behavioural_analysis/test_ba_controller.py b/tests/openbb_terminal/stocks/behavioural_analysis/test_ba_controller.py index b3e4d94c635..888a0ac6936 100644 --- a/tests/openbb_terminal/stocks/behavioural_analysis/test_ba_controller.py +++ b/tests/openbb_terminal/stocks/behavioural_analysis/test_ba_controller.py @@ -238,16 +238,6 @@ def test_call_func_expect_queue(expected_queue, queue, func): @pytest.mark.parametrize( "tested_func, other_args, mocked_func, called_args, called_kwargs", [ - ( - "call_spacc", - ["--limit=5", "--popular"], - "reddit_view.display_spac_community", - [], - dict( - limit=5, - popular=True, - ), - ), ( "call_wsb", ["--limit=5", "--new"], @@ -426,7 +416,6 @@ def test_call_func( @pytest.mark.parametrize( "func", [ - "call_spacc", "call_wsb", "call_popular", "call_bullbear", diff --git a/tests/openbb_terminal/stocks/behavioural_analysis/txt/test_ba_controller/test_print_help.txt b/tests/openbb_terminal/stocks/behavioural_analysis/txt/test_ba_controller/test_print_help.txt index b8c9ecfe68a..e2a9a232e0b 100644 --- a/tests/openbb_terminal/stocks/behavioural_analysis/txt/test_ba_controller/test_print_help.txt +++ b/tests/openbb_terminal/stocks/behavioural_analysis/txt/test_ba_controller/test_print_help.txt @@ -6,7 +6,6 @@ Ticker: TSLA snews stock price displayed over sentiment of news headlines [Finnhub] wsb show what WSB gang is up to in subreddit wallstreetbets [Reddit] popular show popular tickers [Reddit] - spacc show other users spacs announcements from subreddit SPACs [Reddit] getdd gets due diligence from another user's post [Reddit] redditsent searches reddit for ticker and finds reddit sentiment [Reddit] trending trending stocks [Stocktwits] diff --git a/tests/openbb_terminal/test_terminal_controller.py b/tests/openbb_terminal/test_terminal_controller.py index 7abdbadde20..5ff5f757236 100644 --- a/tests/openbb_terminal/test_terminal_controller.py +++ b/tests/openbb_terminal/test_terminal_controller.py @@ -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) diff --git a/website/content/terminal/changelog/version2_0_0.mdx b/website/content/terminal/changelog/version2_0_0.mdx index c401bd29c86..0841d51f334 100644 --- a/website/content/terminal/changelog/version2_0_0.mdx +++ b/website/content/terminal/changelog/version2_0_0.mdx @@ -3,7 +3,7 @@ title: v2.0.0 version: "2.0.0" date: 2022-11-29 description: v2.0.0 -sidebar_position: 104 +sidebar_position: 105 --- ## Major Release Notes diff --git a/website/content/terminal/changelog/version2_1_0.mdx b/website/content/terminal/changelog/version2_1_0.mdx index e1cdd8e5f44..321425a6955 100644 --- a/website/content/terminal/changelog/version2_1_0.mdx +++ b/website/content/terminal/changelog/version2_1_0.mdx @@ -3,7 +3,7 @@ title: v2.1.0 version: "2.1.0" date: 2022-12-21 description: v2.1.0 -sidebar_position: 103 +sidebar_position: 104 --- ## What's new diff --git a/website/content/terminal/changelog/version2_2_0.mdx b/website/content/terminal/changelog/version2_2_0.mdx index 5bedd316e98..51bc24934de 100644 --- a/website/content/terminal/changelog/version2_2_0.mdx +++ b/website/content/terminal/changelog/version2_2_0.mdx @@ -3,7 +3,7 @@ title: v2.2.0 version: "2.2.0" date: 2022-01-19 description: v2.2.0 -sidebar_position: 102 +sidebar_position: 103 --- ## What's new diff --git a/website/content/terminal/changelog/version2_3_0.mdx b/website/content/terminal/changelog/version2_3_0.mdx index 11a082997df..c6b65de6aa3 100644 --- a/website/content/terminal/changelog/version2_3_0.mdx +++ b/website/content/terminal/changelog/version2_3_0.mdx @@ -3,7 +3,7 @@ title: v2.3.0 version: "2.3.0" date: 2023-01-31 description: v2.3.0 -sidebar_position: 101 +sidebar_position: 102 --- diff --git a/website/content/terminal/changelog/version2_3_1.mdx b/website/content/terminal/changelog/version2_3_1.mdx index 1b553ad84ad..7f811c4a3fc 100644 --- a/website/content/terminal/changelog/version2_3_1.mdx +++ b/website/content/terminal/changelog/version2_3_1.mdx @@ -3,7 +3,7 @@ title: v2.3.1 version: "2.3.1" date: 2023-02-01 description: v2.3.1 -sidebar_position: 100 +sidebar_position: 101 --- ## Fixed diff --git a/website/content/terminal/changelog/version2_4_0.mdx b/website/content/terminal/changelog/version2_4_0.mdx index bea3f19a099..2296a060a3b 100644 --- a/website/content/terminal/changelog/version2_4_0.mdx +++ b/website/content/terminal/changelog/version2_4_0.mdx @@ -3,7 +3,7 @@ title: v2.4.0 version: "2.4.0" date: 2023-02-14 description: v2.4.0 -sidebar_position: 99 +sidebar_position: 100 --- ## What's new diff --git a/website/content/terminal/changelog/version2_4_1.mdx b/website/content/terminal/changelog/version2_4_1.mdx index 1cba750d632..dfa0696ac39 100644 --- a/website/content/terminal/changelog/version2_4_1.mdx +++ b/website/content/terminal/changelog/version2_4_1.mdx @@ -3,7 +3,7 @@ title: v2.4.1 version: "2.4.1" date: 2023-02-17 description: v2.4.1 -sidebar_position: 98 +sidebar_position: 99 --- ## What's new diff --git a/website/content/terminal/changelog/version2_5_0.mdx b/website/content/terminal/changelog/version2_5_0.mdx index 35aaf918ba5..adf11b02a15 100644 --- a/website/content/terminal/changelog/version2_5_0.mdx +++ b/website/content/terminal/changelog/version2_5_0.mdx @@ -3,7 +3,7 @@ title: v2.5.0 version: "2.5.0" date: 2023-03-01 description: v2.5.0 -sidebar_position: 97 +sidebar_position: 98 --- diff --git a/website/content/terminal/changelog/version2_5_1.mdx b/website/content/terminal/changelog/version2_5_1.mdx index ef55df63440..2a52912bda0 100644 --- a/website/content/terminal/changelog/version2_5_1.mdx +++ b/website/content/terminal/changelog/version2_5_1.mdx @@ -3,7 +3,7 @@ title: 2.5.1 version: "2.5.1" date: 2023-03-01 description: Current - v2.5.1 -sidebar_position: 96 +sidebar_position: 97 --- ## Fixed diff --git a/website/content/terminal/changelog/version3_0_0.mdx b/website/content/terminal/changelog/version3_0_0.mdx index 8c44fefb86c..a9bdddeafaf 100644 --- a/website/content/terminal/changelog/version3_0_0.mdx +++ b/website/content/terminal/changelog/version3_0_0.mdx @@ -3,7 +3,7 @@ title: v3.0.0 version: "3.0.0" date: 2023-04-25 description: v3.0.0 -sidebar_position: 95 +sidebar_position: 96 --- ## What's new diff --git a/website/content/terminal/changelog/version3_0_1.mdx b/website/content/terminal/changelog/version3_0_1.mdx index a63a568308c..c800ffe2d9f 100644 --- a/website/content/terminal/changelog/version3_0_1.mdx +++ b/website/content/terminal/changelog/version3_0_1.mdx @@ -3,7 +3,7 @@ title: v3.0.1 version: "3.0.1" date: 2023-05-15 description: v3.0.1 -sidebar_position: 94 +sidebar_position: 95 --- ## Thank you and welcome to our new contributors 🔥 diff --git a/website/content/terminal/changelog/version3_1_0.mdx b/website/content/terminal/changelog/version3_1_0.mdx index 64a7333629d..8c7583c9495 100644 --- a/website/content/terminal/changelog/version3_1_0.mdx +++ b/website/content/terminal/changelog/version3_1_0.mdx @@ -3,7 +3,7 @@ title: v3.1.0 version: "3.1.0" date: 2023-06-21 description: v3.1.0 -sidebar_position: 93 +sidebar_position: 94 --- ## Thank you and welcome to our new contributors 🔥 diff --git a/website/content/terminal/changelog/version3_2_0.mdx b/website/content/terminal/changelog/version3_2_0.mdx index f6394b67ed6..17acdec8042 100644 --- a/website/content/terminal/changelog/version3_2_0.mdx +++ b/website/content/terminal/changelog/version3_2_0.mdx @@ -1,9 +1,9 @@ --- -title: Current - v3.2.0 +title: v3.2.0 version: "3.2.0" date: 2023-07-21 description: Current - v3.2.0 -sidebar_position: 92 +sidebar_position: 93 --- ## Thank you and welcome to our new contributors 🔥 diff --git a/website/content/terminal/changelog/version3_2_1.mdx b/website/content/terminal/changelog/version3_2_1.mdx new file mode 100644 index 00000000000..bb270b77b77 --- /dev/null +++ b/website/content/terminal/changelog/version3_2_1.mdx @@ -0,0 +1,54 @@ +--- +title: Current - v3.2.1 +version: "3.2.1" +date: 2023-08-16 +description: Current - v3.2.1 +sidebar_position: 92 +--- + +## What's new 🎉 + +We are super excited to launch community routines in the terminal! + +This is accompanied by our usual bug fix and general enhancements. + +## What's changed 🚀 +* hotfix/simplify-regex (#5324) @DidierRLopes +* Fix routines creation from the Terminal to Hub (#5312) @DidierRLopes +* Fix regex (#5320) @DidierRLopes +* Creates a "--dev" flag that points to dev backend for testing with hub (#5319) @DidierRLopes +* small fixy (#5318) @DidierRLopes +* few more updates (#5317) @DidierRLopes +* --debug points to dev env (#5316) @DidierRLopes +* Silly (#5313) @DidierRLopes +* hotfix/ `/stocks/fa/pt` show all price targets on hover (#5305) @tehcoderer +* hotfix/options-hist: Fixes `options/hist` to display date column when raw is True (#5304) @deeleeramone +* Allow the exe command to run URLs (#5295) @colin99d +* Feature/news sentiment (#5274) @Sai-132 +* hotfix/ conflict docstrings (#5293) @tehcoderer +* hotfix / forecast, qa/hist (#5290) @tehcoderer +* Fixed the get routines to meet the new backend standard (#5271) @colin99d +* Actually fix databento this time (#5287) @jmaslek +* add `--india` flag to `stocks/load` (#5281) @the-praxs +* Feature/options_views: Add a Variety of Views/Charts to Extend the OptionsChains Class (#5222) @deeleeramone +* hotfix/economy-controller-sort-filter: Fwd P/E regex fix (#5273) @deeleeramone +* Update all_api_keys.json (#5277) @DidierRLopes +* Move hub api keys ts (#5267) @montezdesousa +* Hotfix `economy/overview` rates displaying as dates (#5269) @tehcoderer +* Adds details/image for installing C++ Build Tools (#5268) @deeleeramone +* hotfix/gdp-units - better GDP units (#5262) @deeleeramone +* Hotfix/ locking when deploying streamlit app (#5261) @tehcoderer +* Fix issue where incorrect key for biztoc prints exception (#5257) @jmaslek +* Check token expiration before request (#5255) @montezdesousa +* hotfix/economy-report-duplicate-table: fixes duplicate tables. (#5252) @deeleeramone +* hotfix/docs-sdk-basics-headTitle: fix headTitle (#5253) @deeleeramone +* Fix/reports (#5251) @jmaslek +* Fix/reports (#5250) @jmaslek +* Release/3.2.0 (#5243) @jmaslek + +We are proud of our community contributors and staunch supporters of open-source ecosystems. +Help us promote our community by tagging `@openbb_finance` on Twitter with a link to your pull request, +and join our Discord server to chat about your contribution! We want to hear about your experience! + +### Links 🦋 +[Website](https://openbb.co/), [Twitter](https://twitter.com/openbb_finance), [Linkedin](https://www.linkedin.com/company/openbb-finance), [Instagram](https://www.instagram.com/openbb.finance/), [Reddit](https://www.reddit.com/r/openbb/), [Discord](https://discord.com/invite/xPHTuHCmuV) diff --git a/website/content/terminal/installation/macos.md b/website/content/terminal/installation/macos.md index 5cb04f61679..5e5511dca76 100644 --- a/website/content/terminal/installation/macos.md +++ b/website/content/terminal/installation/macos.md @@ -37,7 +37,7 @@ Install the OpenBB Terminal on MacOS (Big Sur or later). There are two versions
- +
Minimum Requirements diff --git a/website/content/terminal/installation/windows.md b/website/content/terminal/installation/windows.md index 2eaa9e62242..c9c1727bcb4 100644 --- a/website/content/terminal/installation/windows.md +++ b/website/content/terminal/installation/windows.md @@ -30,7 +30,7 @@ import InstallerButton from "@site/src/components/General/InstallerButton"; This section provides you with the installation file as well as the guide to install the OpenBB Terminal via Windows (10 or greater). - +
Minimum Requirements