diff --git a/openbb_terminal/account/account_controller.py b/openbb_terminal/account/account_controller.py index e834e62bd5de..674d6fcd8930 100644 --- a/openbb_terminal/account/account_controller.py +++ b/openbb_terminal/account/account_controller.py @@ -5,17 +5,20 @@ from pathlib import Path from typing import Dict, List, Optional -from openbb_terminal import ( - keys_model, +from openbb_terminal.account.account_model import ( + get_diff, + get_routines_info, ) -from openbb_terminal.account.account_model import get_diff, get_routines_info from openbb_terminal.account.account_view import display_routines_list from openbb_terminal.core.session import ( hub_model as Hub, local_model as Local, ) -from openbb_terminal.core.session.current_user import get_current_user, is_local -from openbb_terminal.core.session.preferences_handler import set_preference +from openbb_terminal.core.session.current_user import ( + get_current_user, + is_local, + set_preference, +) from openbb_terminal.core.session.session_model import logout from openbb_terminal.custom_prompt_toolkit import NestedCompleter from openbb_terminal.decorators import log_start_end @@ -156,16 +159,23 @@ def call_sync(self, other_args: List[str]): ns_parser = self.parse_known_args_and_warn(parser, other_args) if ns_parser: - current_user = get_current_user() if ns_parser.sync is None: - sync = "ON" if current_user.preferences.SYNC_ENABLED is True else "OFF" + sync = ( + "ON" + if get_current_user().preferences.SYNC_ENABLED is True + else "OFF" + ) console.print(f"sync is {sync}, use --on or --off to change.") else: set_preference( name="SYNC_ENABLED", value=ns_parser.sync, ) - sync = "ON" if current_user.preferences.SYNC_ENABLED is True else "OFF" + sync = ( + "ON" + if get_current_user().preferences.SYNC_ENABLED is True + else "OFF" + ) console.print(f"[info]sync:[/info] {sync}") @log_start_end(log=logger) @@ -489,17 +499,6 @@ def call_generate(self, other_args: List[str]) -> None: if token: console.print(f"\n[info]Token:[/info] {token}\n") - save_to_keys = False - if not ns_parser.save: - save_to_keys = console.input( - "Would you like to save the token to the keys? (y/n): " - ).lower() in ["y", "yes"] - - if save_to_keys or ns_parser.save: - keys_model.set_openbb_personal_access_token( - key=token, persist=True, show_output=True - ) - @log_start_end(log=logger) def call_show(self, other_args: List[str]) -> None: """Process show command.""" diff --git a/openbb_terminal/core/models/credentials_model.py b/openbb_terminal/core/models/credentials_model.py index 28f576564a60..24e78f9833fd 100644 --- a/openbb_terminal/core/models/credentials_model.py +++ b/openbb_terminal/core/models/credentials_model.py @@ -64,9 +64,6 @@ class CredentialsModel: API_COINBASE_SECRET: str = "REPLACE_ME" API_COINBASE_PASS_PHRASE: str = "REPLACE_ME" - # Others - OPENBB_PERSONAL_ACCESS_TOKEN: str = "REPLACE_ME" - def __repr__(self) -> str: """Return string representation of model.""" dataclass_repr = "" diff --git a/openbb_terminal/core/models/preferences_model.py b/openbb_terminal/core/models/preferences_model.py index bc3ef9c427f8..2f255cf9c25b 100644 --- a/openbb_terminal/core/models/preferences_model.py +++ b/openbb_terminal/core/models/preferences_model.py @@ -47,7 +47,6 @@ class PreferencesModel: # Enable interactive matplotlib mode: change variable name to be more descriptive and delete comment USE_ION: bool = True USE_WATERMARK: bool = True - # Enable command and source in the figures: change variable name to be more descriptive and delete comment USE_CMD_LOCATION_FIGURE: bool = True USE_PROMPT_TOOLKIT: bool = True USE_PLOT_AUTOSCALING: bool = False diff --git a/openbb_terminal/core/sdk/models/keys_sdk_model.py b/openbb_terminal/core/sdk/models/keys_sdk_model.py index 3bc746f19414..a216196b062f 100644 --- a/openbb_terminal/core/sdk/models/keys_sdk_model.py +++ b/openbb_terminal/core/sdk/models/keys_sdk_model.py @@ -30,7 +30,6 @@ class KeysRoot(Category): `mykeys`: Get currently set API keys.\n `news`: Set News key\n `oanda`: Set Oanda key\n - `openbb`: Set OpenBB Personal Access Token.\n `polygon`: Set Polygon key\n `quandl`: Set Quandl key\n `reddit`: Set Reddit key\n @@ -71,7 +70,6 @@ def __init__(self): self.mykeys = lib.keys_model.get_keys self.news = lib.keys_model.set_news_key self.oanda = lib.keys_model.set_oanda_key - self.openbb = lib.keys_model.set_openbb_personal_access_token self.polygon = lib.keys_model.set_polygon_key self.quandl = lib.keys_model.set_quandl_key self.reddit = lib.keys_model.set_reddit_key diff --git a/openbb_terminal/core/session/credentials_handler.py b/openbb_terminal/core/session/credentials_handler.py deleted file mode 100644 index d643777a9a59..000000000000 --- a/openbb_terminal/core/session/credentials_handler.py +++ /dev/null @@ -1,73 +0,0 @@ -# IMPORTS STANDARD -import dataclasses - -# IMPORTS THIRDPARTY -from dotenv import set_key - -# IMPORTS INTERNAL -from openbb_terminal.core.config.paths import SETTINGS_ENV_FILE -from openbb_terminal.core.session.current_user import ( - get_current_user, - is_local, - set_current_user, -) -from openbb_terminal.core.session.hub_model import patch_user_configs - -LOCAL_KEYS = [ - "RH_USERNAME", - "RH_PASSWORD", - "DG_USERNAME", - "DG_PASSWORD", - "DG_TOTP_SECRET", - "OANDA_ACCOUNT_TYPE", - "OANDA_ACCOUNT", - "OANDA_TOKEN", - "API_BINANCE_KEY", - "API_BINANCE_SECRET", - "API_COINBASE_KEY", - "API_COINBASE_SECRET", - "API_COINBASE_PASS_PHRASE", -] - - -def set_credential( - name: str, - value: str, - persist: bool = False, - login: bool = False, -): - """Set credential - - Parameters - ---------- - name : str - Credential name - value : str - Credential value - persist : bool - Force saving to .env file - login : bool - If preference set during login - """ - - current_user = get_current_user() - sync_enabled = current_user.preferences.SYNC_ENABLED - local_user = is_local() - - # Set credential in current user - updated_credentials = dataclasses.replace(current_user.credentials, **{name: value}) - updated_user = dataclasses.replace(current_user, credentials=updated_credentials) - set_current_user(updated_user) - - # Set credential in local env file - if persist and local_user: - set_key(str(SETTINGS_ENV_FILE), "OPENBB_" + name, str(value)) - - # Send credential to cloud - if not local_user and sync_enabled and name not in LOCAL_KEYS and not login: - patch_user_configs( - key=name, - value=str(value), - type_="keys", - auth_header=current_user.profile.get_auth_header(), - ) diff --git a/openbb_terminal/core/session/current_user.py b/openbb_terminal/core/session/current_user.py index 9798963d1b2c..e606c968ec53 100644 --- a/openbb_terminal/core/session/current_user.py +++ b/openbb_terminal/core/session/current_user.py @@ -1,6 +1,8 @@ # IMPORTS STANDARD +import dataclasses from copy import deepcopy -from typing import Optional +from pathlib import Path +from typing import Optional, Union # IMPORTS INTERNAL from openbb_terminal.core.models import ( @@ -9,7 +11,10 @@ ProfileModel, UserModel, ) -from openbb_terminal.core.session.env_handler import load_env_to_model, reading_env +from openbb_terminal.core.session.env_handler import ( + load_env_to_model, + reading_env, +) __env_dict = reading_env() __credentials = load_env_to_model(__env_dict, CredentialsModel) @@ -36,6 +41,21 @@ def set_current_user(user: UserModel): __current_user = user +def get_local_user() -> UserModel: + """Get local user.""" + return deepcopy(__local_user) + + +def get_env_dict() -> dict: + """Get env dict.""" + return deepcopy(__env_dict) + + +def get_local_preferences() -> PreferencesModel: + """Get preferences.""" + return deepcopy(__preferences) # type: ignore + + def is_local() -> bool: """Check if user is guest. @@ -65,3 +85,38 @@ def copy_user( ) return user_copy + + +def set_preference( + name: str, + value: Union[bool, Path, str], +): + """Set preference + + Parameters + ---------- + name : str + Preference name + value : Union[bool, Path, str] + Preference value + """ + current_user = get_current_user() + updated_preferences = dataclasses.replace(current_user.preferences, **{name: value}) + updated_user = dataclasses.replace(current_user, preferences=updated_preferences) + set_current_user(updated_user) + + +def set_credential(name: str, value: str): + """Set credential + + Parameters + ---------- + name : str + Credential name + value : str + Credential value + """ + current_user = get_current_user() + updated_credentials = dataclasses.replace(current_user.credentials, **{name: value}) + updated_user = dataclasses.replace(current_user, credentials=updated_credentials) + set_current_user(updated_user) diff --git a/openbb_terminal/core/session/env_handler.py b/openbb_terminal/core/session/env_handler.py index a25a30e4cb12..8ab5eaf67a89 100644 --- a/openbb_terminal/core/session/env_handler.py +++ b/openbb_terminal/core/session/env_handler.py @@ -2,7 +2,7 @@ from typing import Any, Dict, Optional, Type, Union # IMPORTS THIRDPARTY -from dotenv import dotenv_values +from dotenv import dotenv_values, set_key from pydantic import ValidationError # IMPORTS INTERNAL @@ -53,10 +53,10 @@ def load_env_to_model( Union[Type[CredentialsModel], Type[PreferencesModel]] Model with environment variables. """ + model_name = model.__name__.strip("Model").lower() try: return model(**env_dict) # type: ignore except ValidationError as error: - model_name = model.__name__.strip("Model").lower() print(f"Error loading {model_name}:") for err in error.errors(): loc = err.get("loc", None) @@ -69,3 +69,19 @@ def load_env_to_model( print(f" {var_name}: {msg}, using default -> {default}") return model(**env_dict) # type: ignore + except Exception: + print(f"Error loading {model_name}, using defaults.") + return model() # type: ignore + + +def write_to_dotenv(name: str, value: str) -> None: + """Write to .env file. + + Parameters + ---------- + name : str + Name of the variable. + value : str + Value of the variable. + """ + set_key(str(SETTINGS_ENV_FILE), name, str(value)) diff --git a/openbb_terminal/core/session/hub_model.py b/openbb_terminal/core/session/hub_model.py index e1fc818e57db..103f1afb9e6a 100644 --- a/openbb_terminal/core/session/hub_model.py +++ b/openbb_terminal/core/session/hub_model.py @@ -232,7 +232,7 @@ def fetch_user_configs( return None -def patch_user_configs( +def upload_config( key: str, value: str, type_: str, @@ -565,7 +565,7 @@ def generate_personal_access_token( Optional[requests.Response] """ - url = f"{base_url}/sdk/token" + url = f"{base_url}sdk/token" payload = json.dumps({"days": days}) headers = { @@ -612,7 +612,7 @@ def get_personal_access_token( Optional[requests.Response] """ - url = f"{base_url}/sdk/token" + url = f"{base_url}sdk/token" headers = {"Authorization": auth_header} @@ -655,7 +655,7 @@ def revoke_personal_access_token( Optional[requests.Response] """ - url = f"{base_url}/sdk/token" + url = f"{base_url}sdk/token" headers = {"Authorization": auth_header} diff --git a/openbb_terminal/core/session/local_model.py b/openbb_terminal/core/session/local_model.py index 39ae92d44176..61ab5a4e76d9 100644 --- a/openbb_terminal/core/session/local_model.py +++ b/openbb_terminal/core/session/local_model.py @@ -7,9 +7,11 @@ HIST_FILE_PATH, SETTINGS_DIRECTORY, ) -from openbb_terminal.core.session.credentials_handler import set_credential -from openbb_terminal.core.session.current_user import get_current_user -from openbb_terminal.core.session.preferences_handler import set_preference +from openbb_terminal.core.session.current_user import ( + get_current_user, + get_local_user, + set_credential, +) from openbb_terminal.rich_config import console SESSION_FILE_PATH = SETTINGS_DIRECTORY / "session.json" @@ -110,38 +112,12 @@ def apply_configs(configs: dict): configs : dict The configurations. """ - if configs: - settings = configs.get("features_settings", {}) - sync = update_sync_flag(settings) - if sync: - if settings: - for k, v in settings.items(): - set_preference(k, v, login=True) - - keys = configs.get("features_keys", {}) - if keys: - for k, v in keys.items(): - set_credential(k, v, login=True) - - -def update_sync_flag(settings: dict) -> bool: - """Update the sync flag. - - Parameters - ---------- - settings : dict - The settings. - - Returns - ------- - bool - The sync flag. - """ - sync = not (settings and settings.get("SYNC_ENABLED", "true").lower() == "false") - - set_preference("SYNC_ENABLED", sync, login=True) + if configs and get_local_user().preferences.SYNC_ENABLED: + credentials = configs.get("features_keys", {}) or {} + for k, v in credentials.items(): + set_credential(k, v) - return sync + # TODO: apply other configs here def get_routine(file_name: str, folder: Optional[Path] = None) -> Optional[str]: diff --git a/openbb_terminal/core/session/preferences_handler.py b/openbb_terminal/core/session/preferences_handler.py deleted file mode 100644 index 4e44e93a1c88..000000000000 --- a/openbb_terminal/core/session/preferences_handler.py +++ /dev/null @@ -1,59 +0,0 @@ -# IMPORTS STANDARD -import dataclasses -from pathlib import Path -from typing import Union - -# IMPORTS THIRDPARTY -from dotenv import set_key - -# IMPORTS INTERNAL -from openbb_terminal.base_helpers import console -from openbb_terminal.core.config.paths import SETTINGS_ENV_FILE -from openbb_terminal.core.session.current_user import ( - get_current_user, - is_local, - set_current_user, -) -from openbb_terminal.core.session.hub_model import patch_user_configs - - -def set_preference( - name: str, - value: Union[bool, Path, str], - login: bool = False, -): - """Set preference - - Parameters - ---------- - name : str - Preference name - value : Union[bool, Path, str] - Preference value - login : bool - If the preference is set during login - """ - - current_user = get_current_user() - sync_enabled = current_user.preferences.SYNC_ENABLED - local_user = is_local() - - # Set preference in current user - updated_preferences = dataclasses.replace(current_user.preferences, **{name: value}) - updated_user = dataclasses.replace(current_user, preferences=updated_preferences) - set_current_user(updated_user) - - # Set preference in local env file - if local_user: - set_key(str(SETTINGS_ENV_FILE), "OPENBB_" + name, str(value)) - - # Send preference to cloud - if not login and not local_user and (sync_enabled or name == "SYNC_ENABLED"): - patch_user_configs( - key=name, - value=str(value), - type_="settings", - auth_header=current_user.profile.get_auth_header(), - ) - - console.print(f"[yellow]{name}[/] [green]has been set to[/] {value}") diff --git a/openbb_terminal/core/session/session_model.py b/openbb_terminal/core/session/session_model.py index 4312803c2a54..773e6cf3eca9 100644 --- a/openbb_terminal/core/session/session_model.py +++ b/openbb_terminal/core/session/session_model.py @@ -11,14 +11,15 @@ ) from openbb_terminal.core.models.user_model import ( CredentialsModel, - PreferencesModel, ProfileModel, UserModel, ) from openbb_terminal.core.session.current_user import ( + get_env_dict, + get_local_preferences, set_current_user, + set_preference, ) -from openbb_terminal.core.session.preferences_handler import set_preference from openbb_terminal.helper_funcs import system_clear from openbb_terminal.rich_config import console @@ -76,26 +77,24 @@ def login(session: dict) -> LoginStatus: session : dict The session info. """ - # create a new user hub_user = UserModel( # type: ignore credentials=CredentialsModel(), profile=ProfileModel(), - preferences=PreferencesModel(), + preferences=get_local_preferences(), ) response = Hub.fetch_user_configs(session) if response is not None: if response.status_code == 200: configs = json.loads(response.content) email = configs.get("email", "") - feature_settings = configs.get("features_settings", {}) or {} hub_user.profile.load_user_info(session, email) set_current_user(hub_user) Local.apply_configs(configs=configs) - if feature_settings.get("FLAIR", None) is None: + if "FLAIR" not in get_env_dict(): MAX_FLAIR_LEN = 20 flair = "[" + hub_user.profile.username[:MAX_FLAIR_LEN] + "]" + " 🦋" - set_preference("FLAIR", flair, login=True) + set_preference("FLAIR", flair) return LoginStatus.SUCCESS if response.status_code == 401: return LoginStatus.UNAUTHORIZED diff --git a/openbb_terminal/featflags_controller.py b/openbb_terminal/featflags_controller.py index 64975dc2b04f..ccda80753dd4 100644 --- a/openbb_terminal/featflags_controller.py +++ b/openbb_terminal/featflags_controller.py @@ -3,13 +3,17 @@ # IMPORTATION STANDARD import logging -from typing import List, Optional +from pathlib import Path +from typing import List, Optional, Union # IMPORTATION THIRDPARTY -from openbb_terminal.core.session.current_user import get_current_user +from openbb_terminal.core.session.current_user import ( + get_current_user, + set_preference, +) +from openbb_terminal.core.session.env_handler import write_to_dotenv # IMPORTATION INTERNAL -from openbb_terminal.core.session.preferences_handler import set_preference from openbb_terminal.custom_prompt_toolkit import NestedCompleter from openbb_terminal.decorators import log_start_end from openbb_terminal.menu import session @@ -22,6 +26,20 @@ logger = logging.getLogger(__name__) +def set_and_save_preference(name: str, value: Union[bool, Path, str]): + """Set preference and write to .env + + Parameters + ---------- + name : str + Preference name + value : Union[bool, Path, str] + Preference value + """ + set_preference(name, value) + write_to_dotenv("OPENBB_" + name, str(value)) + + class FeatureFlagsController(BaseController): """Feature Flags Controller class""" @@ -85,7 +103,7 @@ def print_help(self): def call_overwrite(self, _): """Process overwrite command""" - set_preference( + set_and_save_preference( "FILE_OVERWITE", not get_current_user().preferences.FILE_OVERWRITE ) @@ -95,28 +113,28 @@ def call_version(self, _): def call_retryload(self, _): """Process retryload command""" - set_preference( + set_and_save_preference( "RETRY_WITH_LOAD", not get_current_user().preferences.RETRY_WITH_LOAD ) @log_start_end(log=logger) def call_tab(self, _): """Process tab command""" - set_preference( + set_and_save_preference( "USE_TABULATE_DF", not get_current_user().preferences.USE_TABULATE_DF ) @log_start_end(log=logger) def call_interactive(self, _): """Process interactive command""" - set_preference( + set_and_save_preference( "USE_INTERACTIVE_DF", not get_current_user().preferences.USE_INTERACTIVE_DF ) @log_start_end(log=logger) def call_cls(self, _): """Process cls command""" - set_preference( + set_and_save_preference( "USE_CLEAR_AFTER_CMD", not get_current_user().preferences.USE_CLEAR_AFTER_CMD, ) @@ -124,12 +142,14 @@ def call_cls(self, _): @log_start_end(log=logger) def call_color(self, _): """Process color command""" - set_preference("USE_COLOR", not get_current_user().preferences.USE_COLOR) + set_and_save_preference( + "USE_COLOR", not get_current_user().preferences.USE_COLOR + ) @log_start_end(log=logger) def call_promptkit(self, _): """Process promptkit command""" - set_preference( + set_and_save_preference( "USE_PROMPT_TOOLKIT", not get_current_user().preferences.USE_PROMPT_TOOLKIT, ) @@ -137,7 +157,7 @@ def call_promptkit(self, _): @log_start_end(log=logger) def call_thoughts(self, _): """Process thoughts command""" - set_preference( + set_and_save_preference( "ENABLE_THOUGHTS_DAY", not get_current_user().preferences.ENABLE_THOUGHTS_DAY, ) @@ -145,7 +165,7 @@ def call_thoughts(self, _): @log_start_end(log=logger) def call_reporthtml(self, _): """Process reporthtml command""" - set_preference( + set_and_save_preference( "OPEN_REPORT_AS_HTML", not get_current_user().preferences.OPEN_REPORT_AS_HTML, ) @@ -153,7 +173,7 @@ def call_reporthtml(self, _): @log_start_end(log=logger) def call_exithelp(self, _): """Process exithelp command""" - set_preference( + set_and_save_preference( "ENABLE_EXIT_AUTO_HELP", not get_current_user().preferences.ENABLE_EXIT_AUTO_HELP, ) @@ -161,7 +181,7 @@ def call_exithelp(self, _): @log_start_end(log=logger) def call_rcontext(self, _): """Process rcontext command""" - set_preference( + set_and_save_preference( "REMEMBER_CONTEXTS", not get_current_user().preferences.REMEMBER_CONTEXTS, ) @@ -169,17 +189,21 @@ def call_rcontext(self, _): @log_start_end(log=logger) def call_dt(self, _): """Process dt command""" - set_preference("USE_DATETIME", not get_current_user().preferences.USE_DATETIME) + set_and_save_preference( + "USE_DATETIME", not get_current_user().preferences.USE_DATETIME + ) @log_start_end(log=logger) def call_rich(self, _): """Process rich command""" - set_preference("ENABLE_RICH", not get_current_user().preferences.ENABLE_RICH) + set_and_save_preference( + "ENABLE_RICH", not get_current_user().preferences.ENABLE_RICH + ) @log_start_end(log=logger) def call_richpanel(self, _): """Process richpanel command""" - set_preference( + set_and_save_preference( "ENABLE_RICH_PANEL", not get_current_user().preferences.ENABLE_RICH_PANEL, ) @@ -187,19 +211,19 @@ def call_richpanel(self, _): @log_start_end(log=logger) def call_ion(self, _): """Process ion command""" - set_preference("USE_ION", not get_current_user().preferences.USE_ION) + set_and_save_preference("USE_ION", not get_current_user().preferences.USE_ION) @log_start_end(log=logger) def call_watermark(self, _): """Process watermark command""" - set_preference( + set_and_save_preference( "USE_WATERMARK", not get_current_user().preferences.USE_WATERMARK ) @log_start_end(log=logger) def call_cmdloc(self, _): """Process cmdloc command""" - set_preference( + set_and_save_preference( "USE_CMD_LOCATION_FIGURE", not get_current_user().preferences.USE_CMD_LOCATION_FIGURE, ) @@ -209,4 +233,6 @@ def call_tbhint(self, _): """Process tbhint command""" if get_current_user().preferences.TOOLBAR_HINT: console.print("Will take effect when running terminal next.") - set_preference("TOOLBAR_HINT", not get_current_user().preferences.TOOLBAR_HINT) + set_and_save_preference( + "TOOLBAR_HINT", not get_current_user().preferences.TOOLBAR_HINT + ) diff --git a/openbb_terminal/helper_funcs.py b/openbb_terminal/helper_funcs.py index b85d1d9a9c0c..f1ac3ed9447e 100644 --- a/openbb_terminal/helper_funcs.py +++ b/openbb_terminal/helper_funcs.py @@ -1214,26 +1214,29 @@ def str_to_bool(value) -> bool: def get_screeninfo(): """Get screeninfo.""" screens = get_monitors() # Get all available monitors - current_user = get_current_user() - if ( - len(screens) - 1 < current_user.preferences.MONITOR - ): # Check to see if chosen monitor is detected - monitor = 0 - console.print( - f"Could not locate monitor {current_user.preferences.MONITOR}, using primary monitor." - ) - else: - monitor = current_user.preferences.MONITOR - main_screen = screens[monitor] # Choose what monitor to get + if screens: + current_user = get_current_user() + if ( + len(screens) - 1 < current_user.preferences.MONITOR + ): # Check to see if chosen monitor is detected + monitor = 0 + console.print( + f"Could not locate monitor {current_user.preferences.MONITOR}, using primary monitor." + ) + else: + monitor = current_user.preferences.MONITOR + main_screen = screens[monitor] # Choose what monitor to get - return (main_screen.width, main_screen.height) + return (main_screen.width, main_screen.height) + return None def plot_autoscale(): """Autoscale plot.""" current_user = get_current_user() - if current_user.preferences.USE_PLOT_AUTOSCALING: - x, y = get_screeninfo() # Get screen size + screen_info = get_screeninfo() + if current_user.preferences.USE_PLOT_AUTOSCALING and screen_info: + x, y = screen_info # Get screen size # account for ultrawide monitors if x / y > 1.5: x = x * 0.4 diff --git a/openbb_terminal/keys_controller.py b/openbb_terminal/keys_controller.py index 6b4985c7cbf5..106578edd736 100644 --- a/openbb_terminal/keys_controller.py +++ b/openbb_terminal/keys_controller.py @@ -53,14 +53,7 @@ def __init__( def check_keys_status(self) -> None: """Check keys status""" for api in optional_rich_track(self.API_LIST, desc="Checking keys status"): - if api == "openbb": - self.status_dict[api] = getattr( - keys_model, "check_" + str(api) + "_personal_access_token" - )() - else: - self.status_dict[api] = getattr( - keys_model, "check_" + str(api) + "_key" - )() + self.status_dict[api] = getattr(keys_model, "check_" + str(api) + "_key")() def print_help(self): """Print help""" @@ -1167,31 +1160,3 @@ def call_databento(self, other_args: List[str]): self.status_dict["databento"] = keys_model.set_databento_key( key=ns_parser.key, persist=True, show_output=True ) - - @log_start_end(log=logger) - def call_openbb(self, other_args: List[str]): - """Process openbb command""" - parser = argparse.ArgumentParser( - add_help=False, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - prog="openbb", - description="Set OpenBB Personal Access Token. ", - ) - parser.add_argument( - "-k", - "--key", - type=str, - dest="key", - help="key", - ) - if not other_args: - console.print("For your Personal Access Token, visit: https://openbb.co/") - return - - if other_args and "-" not in other_args[0][0]: - other_args.insert(0, "-k") - ns_parser = self.parse_simple_args(parser, other_args) - if ns_parser: - self.status_dict["openbb"] = keys_model.set_openbb_personal_access_token( - key=ns_parser.key, persist=True, show_output=True - ) diff --git a/openbb_terminal/keys_model.py b/openbb_terminal/keys_model.py index 47ba54b6f470..847f4d2c8a42 100644 --- a/openbb_terminal/keys_model.py +++ b/openbb_terminal/keys_model.py @@ -5,9 +5,7 @@ import contextlib import io -import json import logging -import os import sys from enum import Enum from typing import Dict, List, Union @@ -25,10 +23,13 @@ from prawcore.exceptions import ResponseException from tokenterminal import TokenTerminal -from openbb_terminal.core.session.credentials_handler import set_credential -from openbb_terminal.core.session.current_user import get_current_user -from openbb_terminal.core.session.hub_model import BASE_URL -from openbb_terminal.core.session.local_model import SESSION_FILE_PATH +from openbb_terminal.core.session.current_user import ( + get_current_user, + is_local, + set_credential, +) +from openbb_terminal.core.session.env_handler import write_to_dotenv +from openbb_terminal.core.session.hub_model import upload_config from openbb_terminal.cryptocurrency.coinbase_helpers import ( CoinbaseApiException, CoinbaseProAuth, @@ -67,7 +68,6 @@ "rh": "ROBINHOOD", "degiro": "DEGIRO", "oanda": "OANDA", - "openbb": "OPENBB", "binance": "BINANCE", "bitquery": "BITQUERY", "coinbase": "COINBASE", @@ -89,6 +89,22 @@ # sorting api key section by name API_DICT = dict(sorted(API_DICT.items())) +LOCAL_KEYS = [ + "RH_USERNAME", + "RH_PASSWORD", + "DG_USERNAME", + "DG_PASSWORD", + "DG_TOTP_SECRET", + "OANDA_ACCOUNT_TYPE", + "OANDA_ACCOUNT", + "OANDA_TOKEN", + "API_BINANCE_KEY", + "API_BINANCE_SECRET", + "API_COINBASE_KEY", + "API_COINBASE_SECRET", + "API_COINBASE_PASS_PHRASE", +] + class KeyStatus(str, Enum): """Class to handle status messages and colors""" @@ -230,7 +246,7 @@ def get_keys(show: bool = False) -> pd.DataFrame: for k, _ in current_user.credentials.get_fields().items(): field_value = current_user.credentials.get_field_value(field=k) - if field_value != "REPLACE_ME": + if field_value and field_value != "REPLACE_ME": current_keys[k] = field_value if current_keys: @@ -245,6 +261,35 @@ def get_keys(show: bool = False) -> pd.DataFrame: return pd.DataFrame() +def handle_credential(name: str, value: str, persist: bool = False): + """Handle credential + + Parameters + ---------- + name: str + Name of credential + value: str + Value of credential + persist: bool, optional + Write to .env file. By default, False. + """ + current_user = get_current_user() + sync_enabled = current_user.preferences.SYNC_ENABLED + local_user = is_local() + + set_credential(name, value) + + if local_user and persist: + write_to_dotenv("OPENBB_" + name, value) + elif not local_user and sync_enabled and name not in LOCAL_KEYS: + upload_config( + key=name, + value=str(value), + type_="keys", + auth_header=current_user.profile.get_auth_header(), + ) + + def set_av_key(key: str, persist: bool = False, show_output: bool = False) -> str: """Set Alpha Vantage key @@ -270,7 +315,7 @@ def set_av_key(key: str, persist: bool = False, show_output: bool = False) -> st >>> openbb.keys.av(key="example_key") """ - set_credential("API_KEY_ALPHAVANTAGE", key, persist) + handle_credential("API_KEY_ALPHAVANTAGE", key, persist) return check_av_key(show_output) @@ -337,7 +382,7 @@ def set_fmp_key(key: str, persist: bool = False, show_output: bool = False) -> s >>> openbb.keys.fmp(key="example_key") """ - set_credential("API_KEY_FINANCIALMODELINGPREP", key, persist) + handle_credential("API_KEY_FINANCIALMODELINGPREP", key, persist) return check_fmp_key(show_output) @@ -408,7 +453,7 @@ def set_quandl_key(key: str, persist: bool = False, show_output: bool = False) - >>> openbb.keys.quandl(key="example_key") """ - set_credential("API_KEY_QUANDL", key, persist) + handle_credential("API_KEY_QUANDL", key, persist) return check_quandl_key(show_output) @@ -474,7 +519,7 @@ def set_polygon_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.polygon(key="example_key") """ - set_credential("API_POLYGON_KEY", key, persist) + handle_credential("API_POLYGON_KEY", key, persist) return check_polygon_key(show_output) @@ -543,7 +588,7 @@ def set_fred_key(key: str, persist: bool = False, show_output: bool = False) -> >>> openbb.keys.fred(key="example_key") """ - set_credential("API_FRED_KEY", key, persist) + handle_credential("API_FRED_KEY", key, persist) return check_fred_key(show_output) @@ -611,7 +656,7 @@ def set_news_key(key: str, persist: bool = False, show_output: bool = False) -> >>> openbb.keys.news(key="example_key") """ - set_credential("API_NEWS_TOKEN", key, persist) + handle_credential("API_NEWS_TOKEN", key, persist) return check_news_key(show_output) @@ -679,7 +724,7 @@ def set_tradier_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.tradier(key="example_key") """ - set_credential("API_TRADIER_TOKEN", key, persist) + handle_credential("API_TRADIER_TOKEN", key, persist) return check_tradier_key(show_output) @@ -752,7 +797,7 @@ def set_cmc_key(key: str, persist: bool = False, show_output: bool = False) -> s >>> openbb.keys.cmc(key="example_key") """ - set_credential("API_CMC_KEY", key, persist) + handle_credential("API_CMC_KEY", key, persist) return check_cmc_key(show_output) @@ -816,7 +861,7 @@ def set_finnhub_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.finnhub(key="example_key") """ - set_credential("API_FINNHUB_KEY", key, persist) + handle_credential("API_FINNHUB_KEY", key, persist) return check_finnhub_key(show_output) @@ -906,11 +951,11 @@ def set_reddit_key( ) """ - set_credential("API_REDDIT_CLIENT_ID", client_id, persist) - set_credential("API_REDDIT_CLIENT_SECRET", client_secret, persist) - set_credential("API_REDDIT_PASSWORD", password, persist) - set_credential("API_REDDIT_USERNAME", username, persist) - set_credential("API_REDDIT_USER_AGENT", useragent, persist) + handle_credential("API_REDDIT_CLIENT_ID", client_id, persist) + handle_credential("API_REDDIT_CLIENT_SECRET", client_secret, persist) + handle_credential("API_REDDIT_PASSWORD", password, persist) + handle_credential("API_REDDIT_USERNAME", username, persist) + handle_credential("API_REDDIT_USER_AGENT", useragent, persist) return check_reddit_key(show_output) @@ -1002,7 +1047,7 @@ def set_bitquery_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.bitquery(key="example_key") """ - set_credential("API_BITQUERY_KEY", key, persist) + handle_credential("API_BITQUERY_KEY", key, persist) return check_bitquery_key(show_output) @@ -1092,7 +1137,7 @@ def set_twitter_key( ) """ - set_credential("API_TWITTER_BEARER_TOKEN", access_token, persist) + handle_credential("API_TWITTER_BEARER_TOKEN", access_token, persist) return check_twitter_key(show_output) @@ -1180,8 +1225,8 @@ def set_rh_key( ) """ - set_credential("RH_USERNAME", username, persist) - set_credential("RH_PASSWORD", password, persist) + handle_credential("RH_USERNAME", username, persist) + handle_credential("RH_PASSWORD", password, persist) return check_rh_key(show_output) @@ -1257,9 +1302,9 @@ def set_degiro_key( ) """ - set_credential("DG_USERNAME", username, persist) - set_credential("DG_PASSWORD", password, persist) - set_credential("DG_TOTP_SECRET", secret, persist) + handle_credential("DG_USERNAME", username, persist) + handle_credential("DG_PASSWORD", password, persist) + handle_credential("DG_TOTP_SECRET", secret, persist) return check_degiro_key(show_output) @@ -1355,9 +1400,9 @@ def set_oanda_key( ) """ - set_credential("OANDA_ACCOUNT", account, persist) - set_credential("OANDA_TOKEN", access_token, persist) - set_credential("OANDA_ACCOUNT_TYPE", account_type, persist) + handle_credential("OANDA_ACCOUNT", account, persist) + handle_credential("OANDA_TOKEN", access_token, persist) + handle_credential("OANDA_ACCOUNT_TYPE", account_type, persist) return check_oanda_key(show_output) @@ -1442,8 +1487,8 @@ def set_binance_key( ) """ - set_credential("API_BINANCE_KEY", key, persist) - set_credential("API_BINANCE_SECRET", secret, persist) + handle_credential("API_BINANCE_KEY", key, persist) + handle_credential("API_BINANCE_SECRET", secret, persist) return check_binance_key(show_output) @@ -1529,9 +1574,9 @@ def set_coinbase_key( ) """ - set_credential("API_COINBASE_KEY", key, persist) - set_credential("API_COINBASE_SECRET", secret, persist) - set_credential("API_COINBASE_PASS_PHRASE", passphrase, persist) + handle_credential("API_COINBASE_KEY", key, persist) + handle_credential("API_COINBASE_SECRET", secret, persist) + handle_credential("API_COINBASE_PASS_PHRASE", passphrase, persist) return check_coinbase_key(show_output) @@ -1606,7 +1651,7 @@ def set_walert_key(key: str, persist: bool = False, show_output: bool = False) - >>> openbb.keys.walert(key="example_key") """ - set_credential("API_WHALE_ALERT_KEY", key, persist) + handle_credential("API_WHALE_ALERT_KEY", key, persist) return check_walert_key(show_output) @@ -1679,7 +1724,7 @@ def set_glassnode_key( >>> openbb.keys.glassnode(key="example_key") """ - set_credential("API_GLASSNODE_KEY", key, persist) + handle_credential("API_GLASSNODE_KEY", key, persist) return check_glassnode_key(show_output) @@ -1754,7 +1799,7 @@ def set_coinglass_key( >>> openbb.keys.coinglass(key="example_key") """ - set_credential("API_COINGLASS_KEY", key, persist) + handle_credential("API_COINGLASS_KEY", key, persist) return check_coinglass_key(show_output) @@ -1825,7 +1870,7 @@ def set_cpanic_key(key: str, persist: bool = False, show_output: bool = False) - >>> openbb.keys.cpanic(key="example_key") """ - set_credential("API_CRYPTO_PANIC_KEY", key, persist) + handle_credential("API_CRYPTO_PANIC_KEY", key, persist) return check_cpanic_key(show_output) @@ -1895,7 +1940,7 @@ def set_ethplorer_key( >>> openbb.keys.ethplorer(key="example_key") """ - set_credential("API_ETHPLORER_KEY", key, persist) + handle_credential("API_ETHPLORER_KEY", key, persist) return check_ethplorer_key(show_output) @@ -1972,8 +2017,8 @@ def set_smartstake_key( ) """ - set_credential("API_SMARTSTAKE_KEY", key, persist) - set_credential("API_SMARTSTAKE_TOKEN", access_token, persist) + handle_credential("API_SMARTSTAKE_KEY", key, persist) + handle_credential("API_SMARTSTAKE_TOKEN", access_token, persist) return check_smartstake_key(show_output) @@ -2058,7 +2103,7 @@ def set_github_key(key: str, persist: bool = False, show_output: bool = False) - >>> openbb.keys.github(key="example_key") """ - set_credential("API_GITHUB_KEY", key, persist) + handle_credential("API_GITHUB_KEY", key, persist) return check_github_key(show_output) @@ -2119,7 +2164,7 @@ def set_messari_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.messari(key="example_key") """ - set_credential("API_MESSARI_KEY", key, persist) + handle_credential("API_MESSARI_KEY", key, persist) return check_messari_key(show_output) @@ -2189,7 +2234,7 @@ def set_eodhd_key(key: str, persist: bool = False, show_output: bool = False) -> >>> openbb.keys.eodhd(key="example_key") """ - set_credential("API_EODHD_KEY", key, persist) + handle_credential("API_EODHD_KEY", key, persist) return check_eodhd_key(show_output) @@ -2258,7 +2303,7 @@ def set_santiment_key( >>> openbb.keys.santiment(key="example_key") """ - set_credential("API_SANTIMENT_KEY", key, persist) + handle_credential("API_SANTIMENT_KEY", key, persist) return check_santiment_key(show_output) @@ -2338,7 +2383,7 @@ def set_shroom_key(key: str, persist: bool = False, show_output: bool = False) - >>> openbb.keys.shroom(key="example_key") """ - set_credential("API_SHROOM_KEY", key, persist) + handle_credential("API_SHROOM_KEY", key, persist) return check_shroom_key(show_output) @@ -2413,7 +2458,7 @@ def set_tokenterminal_key( >>> from openbb_terminal.sdk import openbb >>> openbb.keys.tokenterminal(key="example_key") """ - set_credential("API_TOKEN_TERMINAL_KEY", key, persist) + handle_credential("API_TOKEN_TERMINAL_KEY", key, persist) return check_tokenterminal_key(show_output) @@ -2478,7 +2523,7 @@ def set_stocksera_key(key: str, persist: bool = False, show_output: bool = False >>> from openbb_terminal.sdk import openbb >>> openbb.keys.stocksera(key="example_key") """ - set_credential("API_STOCKSERA_KEY", key, persist) + handle_credential("API_STOCKSERA_KEY", key, persist) return check_stocksera_key(show_output) @@ -2517,89 +2562,6 @@ def check_stocksera_key(show_output: bool = False): return str(status) -def set_openbb_personal_access_token( - key: str, persist: bool = False, show_output: bool = False -): - """Set OpenBB Personal Access Token. - - Parameters - ---------- - key: str - Personal Access Token - persist: bool, optional - If False, api key change will be contained to where it was changed. For example, a Jupyter notebook session. - If True, api key change will be global, i.e. it will affect terminal environment variables. - By default, False. - show_output: bool, optional - Display status string or not. By default, False. - - Returns - ------- - str - Status of key set - - Examples - -------- - >>> from openbb_terminal.sdk import openbb - >>> openbb.keys.openbb(key="example_key") - """ - set_credential("OPENBB_PERSONAL_ACCESS_TOKEN", key, persist) - return check_openbb_personal_access_token(show_output) - - -def check_openbb_personal_access_token(show_output: bool = False): - """Check OpenBB Personal Access Token - - Returns - ------- - str - Status of key set - """ - - current_user = get_current_user() - - if current_user.credentials.OPENBB_PERSONAL_ACCESS_TOKEN == "REPLACE_ME": - logger.info("OpenBB Personal Access Token not defined") - status = KeyStatus.NOT_DEFINED - else: - try: - access_token = "" - - # TODO: is there a better way to test the key? - # This requires a valid session file - - if os.path.isfile(SESSION_FILE_PATH): - with open(SESSION_FILE_PATH) as f: - access_token = json.load(f).get("access_token") - - headers = { - "Authorization": f"Bearer {access_token}", - "Content-Type": "application/json", - } - response = request( - url=f"{BASE_URL}sdk/token", method="GET", headers=headers - ) - - token = response.json().get("token") - - if ( - response.status_code == 200 - and token == current_user.credentials.OPENBB_PERSONAL_ACCESS_TOKEN - ): - logger.info("OpenBB Personal Access Token defined, test passed") - status = KeyStatus.DEFINED_TEST_PASSED - else: - logger.warning("OpenBB Personal Access Token. defined, test failed") - status = KeyStatus.DEFINED_TEST_FAILED - except requests.exceptions.RequestException: - logger.warning("OpenBB Personal Access Token. defined, test failed") - status = KeyStatus.DEFINED_TEST_FAILED - - if show_output: - console.print(status.colorize()) - return str(status) - - def set_intrinio_key(key: str, persist: bool = False, show_output: bool = False) -> str: """Set Intrinio key @@ -2625,7 +2587,7 @@ def set_intrinio_key(key: str, persist: bool = False, show_output: bool = False) >>> openbb.keys.intrinio(key="example_key") """ - set_credential("API_INTRINIO_KEY", key, persist) + handle_credential("API_INTRINIO_KEY", key, persist) return check_intrinio_key(show_output) @@ -2695,7 +2657,7 @@ def set_databento_key( >>> openbb.keys.databento(key="example_key") """ - set_credential("API_DATABENTO_KEY", key, persist) + handle_credential("API_DATABENTO_KEY", key, persist) return check_databento_key(show_output) diff --git a/openbb_terminal/sdk.py b/openbb_terminal/sdk.py index 405c9034ef3b..8779f27c106f 100644 --- a/openbb_terminal/sdk.py +++ b/openbb_terminal/sdk.py @@ -351,7 +351,6 @@ def keys(self): `mykeys`: Get currently set API keys.\n `news`: Set News key\n `oanda`: Set Oanda key\n - `openbb`: Set OpenBB Personal Access Token.\n `polygon`: Set Polygon key\n `quandl`: Set Quandl key\n `reddit`: Set Reddit key\n diff --git a/openbb_terminal/settings_controller.py b/openbb_terminal/settings_controller.py index d3e64e5f595e..82610d7898f2 100644 --- a/openbb_terminal/settings_controller.py +++ b/openbb_terminal/settings_controller.py @@ -7,7 +7,7 @@ import os import os.path from pathlib import Path -from typing import List, Optional +from typing import List, Optional, Union # IMPORTATION THIRDPARTY import pytz @@ -19,8 +19,11 @@ SETTINGS_ENV_FILE, USER_DATA_SOURCES_DEFAULT_FILE, ) -from openbb_terminal.core.session.current_user import get_current_user -from openbb_terminal.core.session.preferences_handler import set_preference +from openbb_terminal.core.session.current_user import ( + get_current_user, + set_preference, +) +from openbb_terminal.core.session.env_handler import write_to_dotenv from openbb_terminal.custom_prompt_toolkit import NestedCompleter from openbb_terminal.decorators import log_start_end from openbb_terminal.helper_funcs import ( @@ -193,6 +196,20 @@ def print_help(self): mt.add_param("_tk", current_user.preferences.TOOLBAR_TWEET_NEWS_KEYWORDS) console.print(text=mt.menu_text, menu="Settings") + @staticmethod + def set_and_save_preference(name: str, value: Union[bool, Path, str]): + """Set preference and write to .env + + Parameters + ---------- + name : str + Preference name + value : Union[bool, Path, str] + Preference value + """ + set_preference(name, value) + write_to_dotenv("OPENBB_" + name, str(value)) + @log_start_end(log=logger) def call_colors(self, other_args: List[str]): """Process colors command""" @@ -227,7 +244,7 @@ def call_dt(self, other_args: List[str]): ) ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference( + self.set_and_save_preference( "USE_DATETIME", not get_current_user().preferences.USE_DATETIME ) @@ -253,7 +270,9 @@ def call_source(self, other_args: List[str]): ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: if os.path.exists(ns_parser.file): - set_preference("PREFERRED_DATA_SOURCE_FILE", ns_parser.file) + self.set_and_save_preference( + "PREFERRED_DATA_SOURCE_FILE", ns_parser.file + ) console.print("[green]Sources file changed successfully![/green]") else: console.print("[red]Couldn't find the sources file![/red]") @@ -269,7 +288,7 @@ def call_autoscaling(self, other_args: List[str]): ) ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference( + self.set_and_save_preference( "USE_PLOT_AUTOSCALING", not get_current_user().preferences.USE_PLOT_AUTOSCALING, ) @@ -295,7 +314,7 @@ def call_dpi(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser and ns_parser.value: - set_preference("PLOT_DPI", ns_parser.value) + self.set_and_save_preference("PLOT_DPI", ns_parser.value) @log_start_end(log=logger) def call_height(self, other_args: List[str]): @@ -318,7 +337,7 @@ def call_height(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("PLOT_HEIGHT", ns_parser.value) + self.set_and_save_preference("PLOT_HEIGHT", ns_parser.value) @log_start_end(log=logger) def call_width(self, other_args: List[str]): @@ -341,7 +360,7 @@ def call_width(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("PLOT_WIDTH", ns_parser.value) + self.set_and_save_preference("PLOT_WIDTH", ns_parser.value) @log_start_end(log=logger) def call_pheight(self, other_args: List[str]): @@ -363,7 +382,7 @@ def call_pheight(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("PLOT_HEIGHT_PERCENTAGE", ns_parser.value) + self.set_and_save_preference("PLOT_HEIGHT_PERCENTAGE", ns_parser.value) @log_start_end(log=logger) def call_pwidth(self, other_args: List[str]): @@ -385,7 +404,7 @@ def call_pwidth(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("PLOT_WIDTH_PERCENTAGE", ns_parser.value) + self.set_and_save_preference("PLOT_WIDTH_PERCENTAGE", ns_parser.value) @log_start_end(log=logger) def call_monitor(self, other_args: List[str]): @@ -407,7 +426,7 @@ def call_monitor(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("MONITOR", ns_parser.value) + self.set_and_save_preference("MONITOR", ns_parser.value) @log_start_end(log=logger) def call_backend(self, other_args: List[str]): @@ -429,7 +448,7 @@ def call_backend(self, other_args: List[str]): other_args.insert(0, "-v") ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: - set_preference("BACKEND", ns_parser.value) + self.set_and_save_preference("BACKEND", ns_parser.value) @log_start_end(log=logger) def call_lang(self, other_args: List[str]): @@ -454,7 +473,7 @@ def call_lang(self, other_args: List[str]): ns_parser = self.parse_simple_args(parser, other_args) if ns_parser: if ns_parser.value: - set_preference("USE_LANGUAGE", ns_parser.value) + self.set_and_save_preference("USE_LANGUAGE", ns_parser.value) else: console.print( f"Languages available: {', '.join(self.languages_available)}" @@ -484,7 +503,7 @@ def call_tz(self, other_args: List[str]): ns_parser = self.parse_simple_args(parser, other_args) if ns_parser and ns_parser.timezone: - set_preference("TIMEZONE", ns_parser.timezone) + self.set_and_save_preference("TIMEZONE", ns_parser.timezone) @log_start_end(log=logger) def call_flair(self, other_args: List[str]): @@ -512,7 +531,7 @@ def call_flair(self, other_args: List[str]): else: ns_parser.emoji = " ".join(ns_parser.emoji) - set_preference("FLAIR", ns_parser.emoji) + self.set_and_save_preference("FLAIR", ns_parser.emoji) @log_start_end(log=logger) def call_userdata(self, other_args: List[str]): @@ -550,7 +569,7 @@ def call_userdata(self, other_args: List[str]): console.print( f"User data to be saved in the default folder: '{default_path}'" ) - set_preference("USER_DATA_DIRECTORY", default_path) + self.set_and_save_preference("USER_DATA_DIRECTORY", default_path) success_userdata = True else: # If the path selected does not start from the user root, give relative location from root @@ -564,7 +583,9 @@ def call_userdata(self, other_args: List[str]): console.print( f"User data to be saved in the selected folder: '{userdata_path}'" ) - set_preference("USER_DATA_DIRECTORY", userdata_path) + self.set_and_save_preference( + "USER_DATA_DIRECTORY", userdata_path + ) success_userdata = True else: console.print( @@ -581,7 +602,9 @@ def call_userdata(self, other_args: List[str]): console.print( f"[green]Folder '{userdata_path}' successfully created.[/green]" ) - set_preference("USER_DATA_DIRECTORY", userdata_path) + self.set_and_save_preference( + "USER_DATA_DIRECTORY", userdata_path + ) else: # Do not update userdata_folder path since we will keep the same as before console.print( @@ -607,7 +630,7 @@ def call_tbnews(self, other_args): current_user = get_current_user() if current_user.preferences.TOOLBAR_TWEET_NEWS: console.print("Will take effect when running terminal next.") - set_preference( + self.set_and_save_preference( "TOOLBAR_TWEET_NEWS", not get_current_user().preferences.TOOLBAR_TWEET_NEWS, ) @@ -659,25 +682,25 @@ def call_tweetnews(self, other_args: List[str]): ns_parser = self.parse_known_args_and_warn(parser, other_args) if ns_parser: if ns_parser.time: - set_preference( + self.set_and_save_preference( "TOOLBAR_TWEET_NEWS_SECONDS_BETWEEN_UPDATES", str(ns_parser.time), ) if ns_parser.number: - set_preference( + self.set_and_save_preference( "TOOLBAR_TWEET_NEWS_NUM_LAST_TWEETS_TO_READ", str(ns_parser.number), ) if ns_parser.accounts: - set_preference( + self.set_and_save_preference( "TOOLBAR_TWEET_NEWS_ACCOUNTS_TO_TRACK", str(ns_parser.accounts), ) if ns_parser.keywords: - set_preference( + self.set_and_save_preference( "TOOLBAR_TWEET_NEWS_KEYWORDS", str(" ".join(ns_parser.keywords)), ) diff --git a/openbb_terminal/terminal_helper.py b/openbb_terminal/terminal_helper.py index 68455b3b396d..2f5d1001f619 100644 --- a/openbb_terminal/terminal_helper.py +++ b/openbb_terminal/terminal_helper.py @@ -25,8 +25,11 @@ # IMPORTATION INTERNAL from openbb_terminal.core.config.paths import SETTINGS_ENV_FILE from openbb_terminal.core.plots.backend import plots_backend -from openbb_terminal.core.session.current_user import get_current_user -from openbb_terminal.core.session.preferences_handler import set_preference +from openbb_terminal.core.session.current_user import ( + get_current_user, + set_preference, +) +from openbb_terminal.core.session.env_handler import write_to_dotenv from openbb_terminal.helper_funcs import request from openbb_terminal.rich_config import console @@ -413,5 +416,6 @@ def first_time_user() -> bool: """ if SETTINGS_ENV_FILE.stat().st_size == 0: set_preference("PREVIOUS_USE", True) + write_to_dotenv("OPENBB_PREVIOUS_USE", "True") return True return False diff --git a/tests/openbb_terminal/account/test_account_controller.py b/tests/openbb_terminal/account/test_account_controller.py index 399e80279b0a..46a72463a736 100644 --- a/tests/openbb_terminal/account/test_account_controller.py +++ b/tests/openbb_terminal/account/test_account_controller.py @@ -352,7 +352,9 @@ def test_call_sync(mocker, other_args, sync): target="openbb_terminal.core.session.current_user.__current_user", new=mock_current_user, ) - + mocker.patch( + target="openbb_terminal.account.account_controller.set_preference", + ) controller.call_sync(other_args=other_args) assert controller.queue == [] @@ -619,12 +621,6 @@ def test_call_generate(mocker, monkeypatch, test_user): mock_input = "y" monkeypatch.setattr(f"{path_controller}.console.input", lambda _: mock_input) - # mock save to keys - mocker.patch( - target=f"{path_controller}.keys_model.set_openbb_personal_access_token", - return_value=True, - ) - controller.call_generate(other_args=["--save", "--days", "30"]) mock_generate.assert_called_once_with( diff --git a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args0-False].txt b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args0-False].txt index f4adc09b1145..3992f63030eb 100644 --- a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args0-False].txt +++ b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args0-False].txt @@ -1,3 +1,2 @@ -SYNC_ENABLED has been set to True [info]sync:[/info] OFF ['--on'] diff --git a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args1-True].txt b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args1-True].txt index 9d0fb18be9ec..e2401bc93e0c 100644 --- a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args1-True].txt +++ b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args1-True].txt @@ -1,3 +1,2 @@ -SYNC_ENABLED has been set to False [info]sync:[/info] ON ['--off'] diff --git a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args2-True].txt b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args2-True].txt index d162b18b8919..939d5a1cd391 100644 --- a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args2-True].txt +++ b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args2-True].txt @@ -1,3 +1,2 @@ -SYNC_ENABLED has been set to True [info]sync:[/info] ON ['--on'] diff --git a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args3-False].txt b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args3-False].txt index 67e38be2b147..72602083de84 100644 --- a/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args3-False].txt +++ b/tests/openbb_terminal/account/txt/test_account_controller/test_call_sync[other_args3-False].txt @@ -1,3 +1,2 @@ -SYNC_ENABLED has been set to False [info]sync:[/info] OFF ['--off'] diff --git a/tests/openbb_terminal/session/test_hub_model.py b/tests/openbb_terminal/session/test_hub_model.py index 3f94c22c3471..b30f512b2826 100644 --- a/tests/openbb_terminal/session/test_hub_model.py +++ b/tests/openbb_terminal/session/test_hub_model.py @@ -360,7 +360,7 @@ def test_fetch_user_configs_exception(): ("key", "value", "settings", "auth_header"), ], ) -def test_patch_user_configs_success(key, value, type_, auth_header): +def test_upload_config_success(key, value, type_, auth_header): mock_response = MagicMock(spec=requests.Response) mock_response.status_code = 200 @@ -368,7 +368,7 @@ def test_patch_user_configs_success(key, value, type_, auth_header): "openbb_terminal.core.session.hub_model.requests.patch", return_value=mock_response, ) as requests_patch_mock: - result = hub_model.patch_user_configs(key, value, type_, auth_header) + result = hub_model.upload_config(key, value, type_, auth_header) assert result.status_code == mock_response.status_code requests_patch_mock.assert_called_once() @@ -379,7 +379,7 @@ def test_patch_user_configs_success(key, value, type_, auth_header): assert kwargs["timeout"] == hub_model.TIMEOUT -def test_patch_user_configs_failure(): +def test_upload_config_failure(): mock_response = MagicMock(spec=requests.Response) mock_response.status_code = 400 @@ -387,7 +387,7 @@ def test_patch_user_configs_failure(): "openbb_terminal.core.session.hub_model.requests.patch", return_value=mock_response, ) as requests_patch_mock: - result = hub_model.patch_user_configs("key", "value", "keys", "auth_header") + result = hub_model.upload_config("key", "value", "keys", "auth_header") assert result.status_code == mock_response.status_code requests_patch_mock.assert_called_once() @@ -398,13 +398,13 @@ def test_patch_user_configs_failure(): assert kwargs["timeout"] == hub_model.TIMEOUT -def test_patch_user_configs_connection_error(): +def test_upload_config_connection_error(): with patch( "openbb_terminal.core.session.hub_model.requests.patch" ) as requests_patch_mock: requests_patch_mock.side_effect = requests.exceptions.ConnectionError() - result = hub_model.patch_user_configs("key", "value", "keys", "auth_header") + result = hub_model.upload_config("key", "value", "keys", "auth_header") assert result is None requests_patch_mock.assert_called_once() @@ -415,13 +415,13 @@ def test_patch_user_configs_connection_error(): assert kwargs["timeout"] == hub_model.TIMEOUT -def test_patch_user_configs_timeout(): +def test_upload_config_timeout(): with patch( "openbb_terminal.core.session.hub_model.requests.patch" ) as requests_patch_mock: requests_patch_mock.side_effect = requests.exceptions.Timeout() - result = hub_model.patch_user_configs("key", "value", "keys", "auth_header") + result = hub_model.upload_config("key", "value", "keys", "auth_header") assert result is None requests_patch_mock.assert_called_once() @@ -432,13 +432,13 @@ def test_patch_user_configs_timeout(): assert kwargs["timeout"] == hub_model.TIMEOUT -def test_patch_user_configs_exception(): +def test_upload_config_exception(): with patch( "openbb_terminal.core.session.hub_model.requests.patch" ) as requests_patch_mock: requests_patch_mock.side_effect = Exception() - result = hub_model.patch_user_configs("key", "value", "keys", "auth_header") + result = hub_model.upload_config("key", "value", "keys", "auth_header") assert result is None requests_patch_mock.assert_called_once() @@ -750,7 +750,7 @@ def test_generate_personal_access_token( assert result.status_code == mock_response.status_code requests_put_mock.assert_called_once() _, kwargs = requests_put_mock.call_args - assert kwargs["url"] == base_url + "/sdk/token" + assert kwargs["url"] == base_url + "sdk/token" assert kwargs["headers"] == { "Authorization": auth_header, "Content-Type": "application/json", @@ -798,7 +798,7 @@ def test_get_personal_access_token(auth_header, base_url, timeout, status_code): assert result.status_code == mock_response.status_code requests_get_mock.assert_called_once() _, kwargs = requests_get_mock.call_args - assert kwargs["url"] == base_url + "/sdk/token" + assert kwargs["url"] == base_url + "sdk/token" assert kwargs["headers"] == {"Authorization": auth_header} assert kwargs["timeout"] == timeout @@ -842,7 +842,7 @@ def test_revoke_personal_access_token(auth_header, base_url, timeout, status_cod assert result.status_code == mock_response.status_code requests_get_mock.assert_called_once() _, kwargs = requests_get_mock.call_args - assert kwargs["url"] == base_url + "/sdk/token" + assert kwargs["url"] == base_url + "sdk/token" assert kwargs["headers"] == {"Authorization": auth_header} assert kwargs["timeout"] == timeout diff --git a/tests/openbb_terminal/test_featflags_controller.py b/tests/openbb_terminal/test_featflags_controller.py index 478e357b7d40..681d8e24dd87 100644 --- a/tests/openbb_terminal/test_featflags_controller.py +++ b/tests/openbb_terminal/test_featflags_controller.py @@ -24,12 +24,9 @@ def controller(mocker): ) mocker.patch( - target="openbb_terminal.featflags_controller.set_preference", + target="openbb_terminal.featflags_controller.set_and_save_preference", ) - mocker.patch( - target="openbb_terminal.core.session.preferences_handler.set_preference" - ) return FeatureFlagsController() diff --git a/tests/openbb_terminal/test_keys_controller.py b/tests/openbb_terminal/test_keys_controller.py index 65f461f606e5..f41b1a8c3e38 100644 --- a/tests/openbb_terminal/test_keys_controller.py +++ b/tests/openbb_terminal/test_keys_controller.py @@ -252,20 +252,3 @@ def test_call_tokenterminal(other): @pytest.mark.parametrize("other", [[], ["-k", "1234", "-t", "456"]]) def test_call_shroom(other): controller.call_shroom(other) - - -@pytest.mark.vcr -@pytest.mark.parametrize("other", [[], ["-k", "1234", "-t", "456"]]) -def test_call_openbb(mocker, other): - # MOCK GET - attrs = { - "status_code": 200, - "json.return_value": {"token": "MOCK_TOKEN"}, - } - mock_response = mocker.Mock(**attrs) - mocker.patch( - target="openbb_terminal.keys_model.request", - new=mocker.Mock(return_value=mock_response), - ) - - controller.call_openbb(other) diff --git a/tests/openbb_terminal/test_keys_model.py b/tests/openbb_terminal/test_keys_model.py index d9a38b784893..a786ec6e8134 100644 --- a/tests/openbb_terminal/test_keys_model.py +++ b/tests/openbb_terminal/test_keys_model.py @@ -1456,53 +1456,6 @@ def test_set_shroom_key( ) -@pytest.mark.vcr -@pytest.mark.record_stdout -@pytest.mark.parametrize( - "args, persist, show_output, __expected", - [ - ( - ["test_key"], - False, - True, - keys_model.KeyStatus.DEFINED_TEST_FAILED, - ), - ( - ["test_key"], - False, - False, - keys_model.KeyStatus.DEFINED_TEST_FAILED, - ), - ( - ["test_key"], - True, - True, - keys_model.KeyStatus.DEFINED_TEST_FAILED, - ), - ( - ["REPLACE_ME"], - False, - True, - keys_model.KeyStatus.NOT_DEFINED, - ), - ], -) -def test_set_openbb_key( - args: List[str], persist: bool, show_output: bool, __expected: str -): - var_name_list = [ - "OPENBB_OPENBB_PERSONAL_ACCESS_TOKEN", - ] - - set_naive_environment(var_name_list) - - keys_model.set_openbb_personal_access_token( - key=args[0], - persist=persist, - show_output=show_output, - ) - - def delete_tmp_files(): tmp_files = TEST_PATH.glob(f"*{proc_id}.tmp") for file in tmp_files: