mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-10-27 12:40:35 +00:00
Set guest by default and put authentication behind environment variable (#4197)
* small bug
* small bug on routines list
* guest as default
* limit logout to users2
* simpler this way
* add logout
* move logout to account & add env var
* put authentication under env var
* fix tests
* remove login
* remove openbb vars on login
* ruff
* revert .toml
* Delete Icon
* Update .env
* fix sdk guest not loading keys
* ruff
* remove press enter & --login
* ruff
* move env load
* load env
* move dot env loading to terminal.py
* fix user sdk login mixing .env with user
* now it works
* fix reset
* fix tests
* ruff
* Login on the SDK using the OpenBB Personal Access Token (#4206)
* openbb key on keys menu
* adding sdk endpoints
* adding login via token to the sdk
* base url
* rename to personal access token
* added docstrings and examples
* openbb is special
* removing extra break line
* making keys working with the personal access token
* resolve conflicting tests
* Revert "resolve conflicting tests"
This reverts commit 2fca2c0ec3.
* using custom requests
* tests
* tests
* tests
* using process_session_response instead
* rewriting some tests
* Fix sdk guest not loading keys (#4207)
* fix sdk guest not loading keys
* ruff
* remove comment
* tests
---------
Co-authored-by: montezdesousa <79287829+montezdesousa@users.noreply.github.com>
Co-authored-by: Diogo Sousa <montezdesousa@gmail.com>
Co-authored-by: James Maslek <jmaslek11@gmail.com>
* test record mode vcr none
* remove yes from tests yml
* specify modules to reload
* try disable check api
* UPdate spec file
* Small stocks bug
* avoid reloading in test mode
* will this work?
* skip session tests
* try with env var as well
* mock sdk reload
* pylint
* bump poetry on python 3.8
* adapt to python 3.8
* adapt to python 3.8 remaining tests
* Tests : update cassettes
* Fix linting
* Makes login conditions simpler
* Tests : txt
---------
Co-authored-by: James Maslek <jmaslek11@gmail.com>
Co-authored-by: Chavithra <chavithra@gmail.com>
Co-authored-by: Henrique Joaquim <h.joaquim@campus.fct.unl.pt>
This commit is contained in:
2
.github/workflows/mac.yml
vendored
2
.github/workflows/mac.yml
vendored
@@ -90,4 +90,4 @@ jobs:
|
||||
|
||||
- name: Start Terminal and exit
|
||||
shell: bash -l {0}
|
||||
run: yes "" | python terminal.py
|
||||
run: python terminal.py
|
||||
|
||||
13
.github/workflows/unit-test.yml
vendored
13
.github/workflows/unit-test.yml
vendored
@@ -6,6 +6,7 @@ env:
|
||||
OPENBB_USE_ION: false
|
||||
OPENBB_USE_PROMPT_TOOLKIT: false
|
||||
OPENBB_FILE_OVERWRITE: true
|
||||
OPENBB_ENABLE_CHECK_API: false
|
||||
PIP_DEFAULT_TIMEOUT: 100
|
||||
|
||||
on:
|
||||
@@ -102,7 +103,7 @@ jobs:
|
||||
- name: Start Terminal and exit
|
||||
run: |
|
||||
source $VENV
|
||||
yes "" | python terminal.py
|
||||
python terminal.py
|
||||
|
||||
tests-python:
|
||||
name: Vanilla Python Tests - ${{ matrix.python-version }}
|
||||
@@ -129,7 +130,7 @@ jobs:
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
version: 1.1.13
|
||||
version: 1.3.2
|
||||
virtualenvs-create: true
|
||||
virtualenvs-in-project: true
|
||||
|
||||
@@ -160,7 +161,7 @@ jobs:
|
||||
- name: Start Terminal and exit
|
||||
run: |
|
||||
source $VENV
|
||||
yes "" | python terminal.py
|
||||
python terminal.py
|
||||
|
||||
full-test:
|
||||
name: Full Test Suite - (${{ matrix.python-version }}, ${{ matrix.os }})
|
||||
@@ -188,7 +189,7 @@ jobs:
|
||||
- name: Install Poetry
|
||||
uses: snok/install-poetry@v1
|
||||
with:
|
||||
version: 1.1.13
|
||||
version: 1.3.2
|
||||
virtualenvs-create: true
|
||||
virtualenvs-in-project: true
|
||||
|
||||
@@ -219,7 +220,7 @@ jobs:
|
||||
- name: Start Terminal and exit
|
||||
run: |
|
||||
source $VENV
|
||||
yes "" | python terminal.py
|
||||
python terminal.py
|
||||
|
||||
tests-conda:
|
||||
name: Anaconda Python Tests - (${{ matrix.python-version }}, ${{ matrix.os }})
|
||||
@@ -324,4 +325,4 @@ jobs:
|
||||
|
||||
- name: Start Terminal and exit
|
||||
shell: bash -l {0}
|
||||
run: yes "" | python terminal.py
|
||||
run: python terminal.py
|
||||
|
||||
2
.github/workflows/windows.yml
vendored
2
.github/workflows/windows.yml
vendored
@@ -104,4 +104,4 @@ jobs:
|
||||
|
||||
- name: Start Terminal and exit
|
||||
shell: bash -l {0}
|
||||
run: yes "" | python terminal.py
|
||||
run: python terminal.py
|
||||
|
||||
4
build/pyinstaller/terminal.spec
vendored
4
build/pyinstaller/terminal.spec
vendored
@@ -69,10 +69,6 @@ added_files = [
|
||||
os.path.join(pathex, "statsmodels", "datasets"),
|
||||
os.path.join("statsmodels", "datasets"),
|
||||
),
|
||||
(
|
||||
os.path.join(pathex, "investpy", "resources"),
|
||||
os.path.join("investpy", "resources"),
|
||||
),
|
||||
(
|
||||
os.path.join(pathex, "debugpy", "_vendored"),
|
||||
os.path.join("debugpy", "_vendored"),
|
||||
|
||||
@@ -21,6 +21,7 @@ from openbb_terminal.session import (
|
||||
hub_model as Hub,
|
||||
local_model as Local,
|
||||
)
|
||||
from openbb_terminal.session.session_model import logout
|
||||
from openbb_terminal.session.user import User
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -30,6 +31,7 @@ class AccountController(BaseController):
|
||||
"""Account Controller Class"""
|
||||
|
||||
CHOICES_COMMANDS = [
|
||||
"logout",
|
||||
"sync",
|
||||
"pull",
|
||||
"clear",
|
||||
@@ -88,8 +90,29 @@ class AccountController(BaseController):
|
||||
mt.add_cmd("upload")
|
||||
mt.add_cmd("download")
|
||||
mt.add_cmd("delete")
|
||||
mt.add_raw("\n")
|
||||
mt.add_info("_authentication_")
|
||||
mt.add_cmd("logout")
|
||||
console.print(text=mt.menu_text, menu="Account")
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_logout(self, other_args: List[str]) -> None:
|
||||
"""Process logout command."""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="logout",
|
||||
description="Logout from current session.",
|
||||
)
|
||||
ns_parser = self.parse_known_args_and_warn(parser, other_args)
|
||||
if ns_parser:
|
||||
logout(
|
||||
auth_header=User.get_auth_header(),
|
||||
token=User.get_token(),
|
||||
guest=User.is_guest(),
|
||||
cls=True,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_sync(self, other_args: List[str]):
|
||||
"""Sync"""
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
# This is for helpers that do NOT import any OpenBB Modules
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Callable, Literal
|
||||
import sys
|
||||
from typing import Any, Callable, List, Literal, Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from rich.console import Console
|
||||
|
||||
from openbb_terminal.core.config.paths import (
|
||||
PACKAGE_ENV_FILE,
|
||||
REPOSITORY_ENV_FILE,
|
||||
USER_ENV_FILE,
|
||||
)
|
||||
|
||||
console = Console()
|
||||
|
||||
menus = Literal["", "featflags", "settings"]
|
||||
@@ -85,3 +95,59 @@ def strtobool(val):
|
||||
raise ValueError(f"invalid truth value {val}")
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def load_dotenv_and_reload_configs():
|
||||
"""Loads the dotenv files in the following order:
|
||||
1. Repository .env file
|
||||
2. Package .env file
|
||||
3. User .env file
|
||||
|
||||
This allows the user to override the package settings with their own
|
||||
settings, and the package to override the repository settings.
|
||||
|
||||
openbb_terminal modules are reloaded to refresh config files with new env,
|
||||
otherwise they will use cache with old variables.
|
||||
"""
|
||||
load_dotenv(REPOSITORY_ENV_FILE, override=True)
|
||||
load_dotenv(PACKAGE_ENV_FILE, override=True)
|
||||
load_dotenv(USER_ENV_FILE, override=True)
|
||||
|
||||
reload_openbb_config_modules()
|
||||
|
||||
|
||||
def reload_openbb_config_modules():
|
||||
"""Reloads openbb config modules"""
|
||||
|
||||
reload_modules(
|
||||
to_reload=[
|
||||
"openbb_terminal.config_plot",
|
||||
"openbb_terminal.config_terminal",
|
||||
"openbb_terminal.feature_flags",
|
||||
"openbb_terminal.core.config",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def reload_modules(to_reload: List[str]):
|
||||
"""Reloads modules"""
|
||||
modules = sys.modules.copy()
|
||||
for module in modules:
|
||||
if module in to_reload:
|
||||
importlib.reload(sys.modules[module])
|
||||
|
||||
|
||||
def remove_log_handlers():
|
||||
"""Remove the log handlers - needs to be done before reloading modules."""
|
||||
for handler in logging.root.handlers[:]:
|
||||
logging.root.removeHandler(handler)
|
||||
|
||||
|
||||
def clear_openbb_env_vars(exceptions: Optional[List[str]] = None):
|
||||
"""Clear openbb environment variables."""
|
||||
for v in os.environ:
|
||||
if v.startswith("OPENBB"):
|
||||
if not exceptions:
|
||||
os.environ.pop(v)
|
||||
elif v not in exceptions:
|
||||
os.environ.pop(v)
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
|
||||
# IMPORTATION INTERNAL
|
||||
from openbb_terminal.base_helpers import load_env_vars, strtobool
|
||||
|
||||
from .helper_classes import TerminalStyle as _TerminalStyle
|
||||
|
||||
SENSITIVE_KEYS = [
|
||||
@@ -194,5 +195,10 @@ API_TOKEN_TERMINAL_KEY = os.getenv("OPENBB_API_TOKEN_TERMINAL_KEY") or "REPLACE_
|
||||
# https://stocksera.pythonanywhere.com/accounts/developers
|
||||
API_STOCKSERA_KEY = os.getenv("OPENBB_API_STOCKSERA_KEY") or "REPLACE_ME"
|
||||
|
||||
# https://my.openbb.co
|
||||
OPENBB_PERSONAL_ACCESS_TOKEN = (
|
||||
os.getenv("OPENBB_OPENBB_PERSONAL_ACCESS_TOKEN") or "REPLACE_ME"
|
||||
)
|
||||
|
||||
# https://intrinio.com/starter-plan
|
||||
API_INTRINIO_KEY = os.getenv("OPENBB_API_INTRINIO_KEY") or "REPLACE_ME"
|
||||
|
||||
@@ -2,22 +2,6 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
|
||||
def load_dotenv_with_priority():
|
||||
"""Loads the dotenv files in the following order:
|
||||
1. Repository .env file
|
||||
2. Package .env file
|
||||
3. User .env file
|
||||
|
||||
This allows the user to override the package settings with their own
|
||||
settings, and the package to override the repository settings.
|
||||
"""
|
||||
load_dotenv(REPOSITORY_ENV_FILE, override=True)
|
||||
load_dotenv(PACKAGE_ENV_FILE, override=True)
|
||||
load_dotenv(USER_ENV_FILE, override=True)
|
||||
|
||||
|
||||
def get_user_data_directory():
|
||||
"""Gets user data path from .env file or returns default path"""
|
||||
|
||||
@@ -54,7 +54,14 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
def check_keys_status(self) -> None:
|
||||
"""Check keys status"""
|
||||
for api in optional_rich_track(self.API_LIST, desc="Checking keys status"):
|
||||
self.status_dict[api] = getattr(keys_model, "check_" + str(api) + "_key")()
|
||||
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"
|
||||
)()
|
||||
|
||||
def print_help(self):
|
||||
"""Print help"""
|
||||
@@ -136,7 +143,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://www.alphavantage.co/support/#api-key\n"
|
||||
"For your API Key, visit: https://www.alphavantage.co/support/#api-key"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -165,9 +172,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://financialmodelingprep.com\n"
|
||||
)
|
||||
console.print("For your API Key, visit: https://financialmodelingprep.com")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -195,7 +200,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://www.quandl.com\n")
|
||||
console.print("For your API Key, visit: https://www.quandl.com")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -223,7 +228,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://polygon.io\n")
|
||||
console.print("For your API Key, visit: https://polygon.io")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -281,7 +286,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://fred.stlouisfed.org\n")
|
||||
console.print("For your API Key, visit: https://fred.stlouisfed.org")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -309,7 +314,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://newsapi.org\n")
|
||||
console.print("For your API Key, visit: https://newsapi.org")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -337,7 +342,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://developer.tradier.com\n")
|
||||
console.print("For your API Key, visit: https://developer.tradier.com")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -365,7 +370,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://coinmarketcap.com\n")
|
||||
console.print("For your API Key, visit: https://coinmarketcap.com")
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-k")
|
||||
@@ -392,7 +397,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://finnhub.io\n")
|
||||
console.print("For your API Key, visit: https://finnhub.io")
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-k")
|
||||
@@ -453,7 +458,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
nargs="+",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://www.reddit.com\n")
|
||||
console.print("For your API Key, visit: https://www.reddit.com")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -506,7 +511,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
required="-h" not in other_args,
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://developer.twitter.com\n")
|
||||
console.print("For your API Key, visit: https://developer.twitter.com")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -542,7 +547,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="password",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://robinhood.com/us/en/\n")
|
||||
console.print("For your API Key, visit: https://robinhood.com/us/en/")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -587,7 +592,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
default="",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://www.degiro.fr\n")
|
||||
console.print("For your API Key, visit: https://www.degiro.fr")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -630,7 +635,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="account type ('live' or 'practice')",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://developer.oanda.com\n")
|
||||
console.print("For your API Key, visit: https://developer.oanda.com")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -668,7 +673,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
required="-h" not in other_args,
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://binance.com\n")
|
||||
console.print("For your API Key, visit: https://binance.com")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -696,7 +701,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://bitquery.io/\n")
|
||||
console.print("For your API Key, visit: https://bitquery.io/")
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-k")
|
||||
@@ -740,7 +745,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
required="-h" not in other_args,
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://docs.pro.coinbase.com/\n")
|
||||
console.print("For your API Key, visit: https://docs.pro.coinbase.com/")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
if ns_parser:
|
||||
@@ -769,7 +774,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://docs.whale-alert.io/\n")
|
||||
console.print("For your API Key, visit: https://docs.whale-alert.io/")
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
other_args.insert(0, "-k")
|
||||
@@ -797,7 +802,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://docs.glassnode.com/basic-api/api-key#how-to-get-an-api-key/\n"
|
||||
"For your API Key, visit: https://docs.glassnode.com/basic-api/api-key#how-to-get-an-api-key/"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -826,7 +831,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://coinglass.github.io/API-Reference/#api-key\n"
|
||||
"For your API Key, visit: https://coinglass.github.io/API-Reference/#api-key"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -855,7 +860,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://cryptopanic.com/developers/api/\n"
|
||||
"For your API Key, visit: https://cryptopanic.com/developers/api/"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -884,7 +889,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://github.com/EverexIO/Ethplorer/wiki/Ethplorer-API\n"
|
||||
"For your API Key, visit: https://github.com/EverexIO/Ethplorer/wiki/Ethplorer-API"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -921,7 +926,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
required="-h" not in other_args,
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://www.smartstake.io\n")
|
||||
console.print("For your API Key, visit: https://www.smartstake.io")
|
||||
return
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
|
||||
@@ -951,7 +956,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api\n"
|
||||
"For your API Key, visit: https://docs.github.com/en/rest/guides/getting-started-with-the-rest-api"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -980,7 +985,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://messari.io/api/docs\n")
|
||||
console.print("For your API Key, visit: https://messari.io/api/docs")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -1009,7 +1014,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://eodhistoricaldata.com/r/?ref=869U7F4J\n"
|
||||
"For your API Key, visit: https://eodhistoricaldata.com/r/?ref=869U7F4J"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -1039,7 +1044,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: "
|
||||
"https://academy.santiment.net/products-and-plans/create-an-api-key\n"
|
||||
"https://academy.santiment.net/products-and-plans/create-an-api-key"
|
||||
)
|
||||
return
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -1068,7 +1073,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, visit: https://sdk.flipsidecrypto.xyz/shroomdk\n"
|
||||
"For your API Key, visit: https://sdk.flipsidecrypto.xyz/shroomdk"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -1097,7 +1102,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
help="key",
|
||||
)
|
||||
if not other_args:
|
||||
console.print("For your API Key, visit: https://tokenterminal.com/\n")
|
||||
console.print("For your API Key, visit: https://tokenterminal.com/")
|
||||
return
|
||||
|
||||
if other_args and "-" not in other_args[0][0]:
|
||||
@@ -1126,7 +1131,7 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
)
|
||||
if not other_args:
|
||||
console.print(
|
||||
"For your API Key, https://stocksera.pythonanywhere.com/accounts/developers\n"
|
||||
"For your API Key, https://stocksera.pythonanywhere.com/accounts/developers"
|
||||
)
|
||||
return
|
||||
|
||||
@@ -1137,3 +1142,31 @@ class KeysController(BaseController): # pylint: disable=too-many-public-methods
|
||||
self.status_dict["stocksera"] = keys_model.set_stocksera_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
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ __docformat__ = "numpy"
|
||||
|
||||
import contextlib
|
||||
import io
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
@@ -35,7 +36,8 @@ from openbb_terminal.cryptocurrency.coinbase_helpers import (
|
||||
from openbb_terminal.helper_funcs import request
|
||||
from openbb_terminal.portfolio.brokers.degiro.degiro_model import DegiroModel
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.session.hub_model import patch_user_configs
|
||||
from openbb_terminal.session.hub_model import BASE_URL, patch_user_configs
|
||||
from openbb_terminal.session.local_model import SESSION_FILE_PATH
|
||||
from openbb_terminal.session.user import User
|
||||
from openbb_terminal.terminal_helper import suppress_stdout
|
||||
|
||||
@@ -66,6 +68,7 @@ API_DICT: Dict = {
|
||||
"rh": "ROBINHOOD",
|
||||
"degiro": "DEGIRO",
|
||||
"oanda": "OANDA",
|
||||
"openbb": "OPENBB",
|
||||
"binance": "BINANCE",
|
||||
"bitquery": "BITQUERY",
|
||||
"coinbase": "COINBASE",
|
||||
@@ -243,7 +246,7 @@ def set_key(env_var_name: str, env_var_value: str, persist: bool = False) -> Non
|
||||
not User.is_guest()
|
||||
and User.is_sync_enabled()
|
||||
and env_var_name not in cfg.SENSITIVE_KEYS
|
||||
and env_var_name.startswith("API_")
|
||||
and (env_var_name.startswith("API_") or env_var_name.startswith("OPENBB_"))
|
||||
):
|
||||
patch_user_configs(
|
||||
key=env_var_name,
|
||||
@@ -280,14 +283,17 @@ def get_keys(show: bool = False) -> pd.DataFrame:
|
||||
|
||||
# TODO: Refactor api variables without prefix API_ and extend API_SOURCE_KEY format
|
||||
|
||||
var_list = [v for v in dir(cfg) if v.startswith("API_")]
|
||||
var_list = [v for v in dir(cfg) if v.startswith("API_") or v.startswith("OPENBB_")]
|
||||
|
||||
current_keys = {}
|
||||
|
||||
for cfg_var_name in var_list:
|
||||
cfg_var_value = getattr(cfg, cfg_var_name)
|
||||
if cfg_var_value != "REPLACE_ME":
|
||||
current_keys[cfg_var_name[4:]] = cfg_var_value
|
||||
if cfg_var_name.startswith("OPENBB_"):
|
||||
current_keys[cfg_var_name] = cfg_var_value
|
||||
else:
|
||||
current_keys[cfg_var_name[4:]] = cfg_var_value
|
||||
|
||||
if current_keys:
|
||||
df = pd.DataFrame.from_dict(current_keys, orient="index")
|
||||
@@ -2485,6 +2491,86 @@ 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_key("OPENBB_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
|
||||
"""
|
||||
if cfg.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 == cfg.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
|
||||
|
||||
|
||||
2
openbb_terminal/miscellaneous/i18n/en.yml
vendored
2
openbb_terminal/miscellaneous/i18n/en.yml
vendored
@@ -18,6 +18,8 @@ en:
|
||||
exe: execute .openbb routine scripts (use exe --example for an example)
|
||||
_configure_: Configure your own terminal
|
||||
_main_menu_: Main menu
|
||||
account/_authentication_: Authentication
|
||||
account/logout: Log out from OpenBB account
|
||||
account/_info_: Cloud storage of keys, settings and feature flags
|
||||
account/sync: Turns the cloud synchronization on/off
|
||||
account/pull: Pull data from cloud
|
||||
|
||||
@@ -533,6 +533,7 @@ keys.santiment,openbb_terminal.keys_model.set_santiment_key,
|
||||
keys.tokenterminal,openbb_terminal.keys_model.set_tokenterminal_key,
|
||||
keys.shroom,openbb_terminal.keys_model.set_shroom_key,
|
||||
keys.stocksera,openbb_terminal.keys_model.set_stocksera_key,
|
||||
keys.openbb,openbb_terminal.keys_model.set_openbb_personal_access_token,
|
||||
futures.search,openbb_terminal.futures.yfinance_model.get_search_futures,
|
||||
futures.historical,openbb_terminal.futures.yfinance_model.get_historical_futures,openbb_terminal.futures.yfinance_view.display_historical
|
||||
futures.curve,openbb_terminal.futures.yfinance_model.get_curve_futures,openbb_terminal.futures.yfinance_view.display_curve
|
||||
@@ -541,3 +542,4 @@ stocks.disc.filings,openbb_terminal.stocks.fundamental_analysis.fmp_model.get_fi
|
||||
stocks.fa.sec_fmp,openbb_terminal.stocks.fundamental_analysis.fmp_model.get_filings,openbb_terminal.stocks.fundamental_analysis.fmp_view.display_filings
|
||||
login,openbb_terminal.session.sdk_session.login,
|
||||
logout,openbb_terminal.session.sdk_session.logout,
|
||||
whoami,openbb_terminal.session.sdk_session.whoami,
|
||||
|
@@ -45,10 +45,9 @@ from openbb_terminal.helper_funcs import (
|
||||
)
|
||||
from openbb_terminal.menu import session
|
||||
from openbb_terminal.rich_config import console, get_ordered_list_sources
|
||||
from openbb_terminal.session.session_model import logout
|
||||
from openbb_terminal.session.user import User
|
||||
from openbb_terminal.stocks import stocks_helper
|
||||
from openbb_terminal.terminal_helper import open_openbb_documentation
|
||||
from openbb_terminal.terminal_helper import is_auth_enabled, open_openbb_documentation
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -96,10 +95,11 @@ class BaseController(metaclass=ABCMeta):
|
||||
"record",
|
||||
"stop",
|
||||
"screenshot",
|
||||
"logout",
|
||||
"whoami",
|
||||
]
|
||||
|
||||
if is_auth_enabled():
|
||||
CHOICES_COMMON += ["whoami"]
|
||||
|
||||
CHOICES_COMMANDS: List[str] = []
|
||||
CHOICES_MENUS: List[str] = []
|
||||
SUPPORT_CHOICES: dict = {}
|
||||
@@ -385,6 +385,9 @@ class BaseController(metaclass=ABCMeta):
|
||||
|
||||
self.log_queue()
|
||||
|
||||
if not self.queue or (self.queue and self.queue[0] not in ("quit", "help")):
|
||||
console.print()
|
||||
|
||||
return self.queue
|
||||
|
||||
@log_start_end(log=logger)
|
||||
@@ -675,25 +678,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
if ns_parser:
|
||||
screenshot()
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_logout(self, other_args: List[str]) -> None:
|
||||
"""Process logout command."""
|
||||
parser = argparse.ArgumentParser(
|
||||
add_help=False,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
prog="logout",
|
||||
description="Logout from OpenBB",
|
||||
)
|
||||
ns_parser = self.parse_simple_args(parser, other_args)
|
||||
|
||||
if ns_parser:
|
||||
logout(
|
||||
auth_header=User.get_auth_header(),
|
||||
token=User.get_token(),
|
||||
guest=User.is_guest(),
|
||||
cls=True,
|
||||
)
|
||||
|
||||
@log_start_end(log=logger)
|
||||
def call_whoami(self, other_args: List[str]) -> None:
|
||||
"""Process whoami command."""
|
||||
@@ -707,7 +691,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
|
||||
if ns_parser:
|
||||
User.whoami()
|
||||
console.print("")
|
||||
|
||||
@staticmethod
|
||||
def parse_simple_args(parser: argparse.ArgumentParser, other_args: List[str]):
|
||||
@@ -964,11 +947,6 @@ class BaseController(metaclass=ABCMeta):
|
||||
if an_input == "logout":
|
||||
return ["logout"]
|
||||
|
||||
if not self.queue or (
|
||||
self.queue and self.queue[0] not in ("quit", "help")
|
||||
):
|
||||
console.print()
|
||||
|
||||
except SystemExit:
|
||||
if not self.contains_keys(an_input):
|
||||
logger.exception(
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
# pylint: disable=unused-import
|
||||
from openbb_terminal import helper_funcs as helper # noqa: F401
|
||||
from openbb_terminal.base_helpers import load_dotenv_and_reload_configs
|
||||
from openbb_terminal.config_terminal import theme # noqa: F401
|
||||
from openbb_terminal.core.library.breadcrumb import Breadcrumb, MetadataBuilder
|
||||
from openbb_terminal.core.library.trail_map import TrailMap
|
||||
from openbb_terminal.cryptocurrency.due_diligence.pycoingecko_model import ( # noqa: F401
|
||||
Coin,
|
||||
from openbb_terminal.cryptocurrency.due_diligence.pycoingecko_model import (
|
||||
Coin, # noqa: F401
|
||||
)
|
||||
from openbb_terminal.helper_classes import TerminalStyle
|
||||
from openbb_terminal.reports import widget_helpers as widgets # noqa: F401
|
||||
from openbb_terminal.session.user import User
|
||||
|
||||
if User.is_guest():
|
||||
load_dotenv_and_reload_configs()
|
||||
|
||||
TerminalStyle().applyMPLstyle()
|
||||
trail = ""
|
||||
|
||||
@@ -4,8 +4,9 @@ import requests
|
||||
|
||||
from openbb_terminal.rich_config import console
|
||||
|
||||
REGISTER_LINK = "https://my.openbb.dev/register"
|
||||
REGISTER_URL = "https://my.openbb.dev/register"
|
||||
BASE_URL = "https://payments.openbb.dev/"
|
||||
# BASE_URL = "http://127.0.0.1:8000/"
|
||||
TIMEOUT = 15
|
||||
|
||||
CONNECTION_ERROR_MSG = "[red]Connection error.[/red]"
|
||||
@@ -51,6 +52,36 @@ def create_session(
|
||||
return None
|
||||
|
||||
|
||||
def create_session_from_token(
|
||||
token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
):
|
||||
"""Create a session from token.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
token : str
|
||||
The token.
|
||||
base_url : str
|
||||
The base url, by default BASE_URL
|
||||
timeout : int
|
||||
The timeout, by default TIMEOUT
|
||||
"""
|
||||
try:
|
||||
data = {
|
||||
"token": token,
|
||||
}
|
||||
return requests.post(url=base_url + "sdk/login", json=data, timeout=timeout)
|
||||
except requests.exceptions.ConnectionError:
|
||||
console.print("\n[red]Connection error.[/red]")
|
||||
return None
|
||||
except requests.exceptions.Timeout:
|
||||
console.print("\n[red]Connection timeout.[/red]")
|
||||
return None
|
||||
except Exception:
|
||||
console.print("\n[red]Failed to request login info.[/red]")
|
||||
return None
|
||||
|
||||
|
||||
def delete_session(
|
||||
auth_header: str, token: str, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
) -> Optional[requests.Response]:
|
||||
@@ -140,6 +171,25 @@ def get_session(email: str, password: str) -> dict:
|
||||
return process_session_response(response)
|
||||
|
||||
|
||||
def get_session_from_token(token: str) -> dict:
|
||||
"""Get the session info from token.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
token : str
|
||||
The token.
|
||||
|
||||
Returns
|
||||
-------
|
||||
dict
|
||||
The session info.
|
||||
"""
|
||||
response = create_session_from_token(token)
|
||||
if response is None:
|
||||
return {}
|
||||
return process_session_response(response)
|
||||
|
||||
|
||||
def fetch_user_configs(
|
||||
session: dict, base_url: str = BASE_URL, timeout: int = TIMEOUT
|
||||
) -> Optional[requests.Response]:
|
||||
|
||||
@@ -6,31 +6,89 @@ from openbb_terminal.session import (
|
||||
from openbb_terminal.session.user import User
|
||||
|
||||
|
||||
def get_session(email: str, password: str, save: bool):
|
||||
session = session_model.create_session(email, password, save)
|
||||
def get_session(email: str, password: str, token: str, save: bool):
|
||||
session = ""
|
||||
|
||||
if token:
|
||||
console.print("Creating session from token.")
|
||||
session = session_model.create_session_from_token(token, save)
|
||||
|
||||
if not session:
|
||||
console.print("Creating session from email and password.")
|
||||
session = session_model.create_session(email, password, save)
|
||||
|
||||
if not (isinstance(session, dict) and session):
|
||||
raise Exception("Failed to create session")
|
||||
raise Exception("Failed to create session.")
|
||||
|
||||
return session
|
||||
|
||||
|
||||
def login(email: str = "", password: str = "", keep_session: bool = False):
|
||||
def login(
|
||||
email: str = "", password: str = "", token: str = "", keep_session: bool = False
|
||||
):
|
||||
"""
|
||||
Login and load user info.
|
||||
If there is a saved session it will be used (this can be achieved by `keep_session=True`).
|
||||
If there's not a local session,
|
||||
the user can use either email and password or the OpenBB Personal Access Token.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
email : str
|
||||
The email.
|
||||
password : str
|
||||
The password.
|
||||
token : str
|
||||
The OpenBB Personal Access Token.
|
||||
keep_session : bool
|
||||
Keep the session, i.e., next time the user logs in,
|
||||
there is no need to enter the email and password or the token.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb_terminal.sdk import openbb
|
||||
>>> openbb.login(email="your_email", password="your_password")
|
||||
"""
|
||||
|
||||
session = Local.get_session()
|
||||
|
||||
if not session:
|
||||
session = get_session(email, password, keep_session)
|
||||
session = get_session(email, password, token, keep_session)
|
||||
else:
|
||||
console.print("Using saved session to login.")
|
||||
|
||||
if session_model.login(session) in [
|
||||
session_model.LoginStatus.FAILED,
|
||||
session_model.LoginStatus.NO_RESPONSE,
|
||||
]:
|
||||
raise Exception("Login failed")
|
||||
raise Exception("Login failed.")
|
||||
|
||||
console.print("[green]Login successful[/green]")
|
||||
console.print("[green]Login successful.[/green]")
|
||||
|
||||
|
||||
def logout():
|
||||
"""
|
||||
Logout and clear session.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb_terminal.sdk import openbb
|
||||
>>> openbb.logout()
|
||||
"""
|
||||
session_model.logout(
|
||||
auth_header=User.get_auth_header(),
|
||||
token=User.get_token(),
|
||||
guest=User.is_guest(),
|
||||
)
|
||||
|
||||
|
||||
def whoami():
|
||||
"""
|
||||
Display user info.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from openbb_terminal.sdk import openbb
|
||||
>>> openbb.whoami()
|
||||
"""
|
||||
User.whoami()
|
||||
|
||||
@@ -6,7 +6,7 @@ import openbb_terminal.session.local_model as Local
|
||||
from openbb_terminal import terminal_controller
|
||||
from openbb_terminal.core.config.paths import PACKAGE_DIRECTORY
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.session.hub_model import REGISTER_LINK
|
||||
from openbb_terminal.session.hub_model import REGISTER_URL
|
||||
from openbb_terminal.session.session_model import (
|
||||
LoginStatus,
|
||||
create_session,
|
||||
@@ -18,7 +18,7 @@ def display_welcome_message():
|
||||
"""Display welcome message"""
|
||||
with open(PACKAGE_DIRECTORY / "session" / "banner.txt") as f:
|
||||
console.print(f"[menu]{f.read()}[/menu]\n")
|
||||
console.print(f"Register : [cmds]{REGISTER_LINK}[/cmds]")
|
||||
console.print(f"Register : [cmds]{REGISTER_URL}[/cmds]")
|
||||
console.print("Ask support : [cmds]https://openbb.co/support[/cmds]")
|
||||
console.print(
|
||||
"[yellow]\nWARNING: This is a pre-release version published for testing.[/yellow]"
|
||||
@@ -34,9 +34,7 @@ def get_user_input() -> Tuple[str, str, bool]:
|
||||
Tuple[str, str, bool]
|
||||
The user email, password and save login option.
|
||||
"""
|
||||
console.print(
|
||||
"[info]\nPlease enter your credentials or press enter for guest mode:[/info]"
|
||||
)
|
||||
console.print("[info]\nPlease enter your credentials:[/info]")
|
||||
|
||||
s: PromptSession = PromptSession()
|
||||
|
||||
@@ -58,7 +56,7 @@ def get_user_input() -> Tuple[str, str, bool]:
|
||||
return email, password, save
|
||||
|
||||
|
||||
def prompt(welcome=True, guest_allowed=False):
|
||||
def prompt(welcome=True):
|
||||
"""Prompt and launch terminal if login is successful.
|
||||
|
||||
Parameters
|
||||
@@ -72,13 +70,11 @@ def prompt(welcome=True, guest_allowed=False):
|
||||
while True:
|
||||
email, password, save = get_user_input()
|
||||
if not email or not password:
|
||||
if guest_allowed:
|
||||
return launch_terminal()
|
||||
continue
|
||||
|
||||
session = create_session(email, password, save)
|
||||
if isinstance(session, dict) and session:
|
||||
return login_and_launch(session=session, guest_allowed=guest_allowed)
|
||||
return login_and_launch(session=session)
|
||||
|
||||
|
||||
def launch_terminal():
|
||||
@@ -86,38 +82,30 @@ def launch_terminal():
|
||||
terminal_controller.parse_args_and_run()
|
||||
|
||||
|
||||
def login_and_launch(session: dict, guest_allowed: bool = True):
|
||||
def login_and_launch(session: dict):
|
||||
"""Login and launch terminal.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
session : dict
|
||||
The session info.
|
||||
guest_allowed : bool, optional
|
||||
Allow guest login, by default True
|
||||
"""
|
||||
status = login(session)
|
||||
if status == LoginStatus.SUCCESS:
|
||||
launch_terminal()
|
||||
elif status == LoginStatus.FAILED:
|
||||
prompt(welcome=False, guest_allowed=guest_allowed)
|
||||
prompt(welcome=False)
|
||||
else:
|
||||
prompt(welcome=True, guest_allowed=guest_allowed)
|
||||
prompt(welcome=True)
|
||||
|
||||
|
||||
def main(guest_allowed: bool = True):
|
||||
"""Main function
|
||||
|
||||
Parameters
|
||||
----------
|
||||
guest_allowed : bool, optional
|
||||
Allow guest login, by default True
|
||||
"""
|
||||
def main():
|
||||
"""Main function"""
|
||||
local_session = Local.get_session()
|
||||
if not local_session:
|
||||
prompt(guest_allowed=guest_allowed)
|
||||
prompt()
|
||||
else:
|
||||
login_and_launch(session=local_session, guest_allowed=guest_allowed)
|
||||
login_and_launch(session=local_session)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import importlib
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import Optional
|
||||
|
||||
@@ -10,6 +6,11 @@ import matplotlib.pyplot as plt
|
||||
|
||||
import openbb_terminal.session.hub_model as Hub
|
||||
import openbb_terminal.session.local_model as Local
|
||||
from openbb_terminal.base_helpers import (
|
||||
clear_openbb_env_vars,
|
||||
reload_openbb_config_modules,
|
||||
remove_log_handlers,
|
||||
)
|
||||
from openbb_terminal.helper_funcs import system_clear
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.session.user import User
|
||||
@@ -42,6 +43,23 @@ def create_session(email: str, password: str, save: bool) -> dict:
|
||||
return session
|
||||
|
||||
|
||||
def create_session_from_token(token: str, save: bool) -> dict:
|
||||
"""Create a session from token.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
token : str
|
||||
The token.
|
||||
save : bool
|
||||
Save the session.
|
||||
"""
|
||||
|
||||
session = Hub.get_session_from_token(token)
|
||||
if session and save:
|
||||
Local.save_session(session)
|
||||
return session
|
||||
|
||||
|
||||
def login(session: dict) -> LoginStatus:
|
||||
"""Login and load user info.
|
||||
|
||||
@@ -50,6 +68,8 @@ def login(session: dict) -> LoginStatus:
|
||||
session : dict
|
||||
The session info.
|
||||
"""
|
||||
clear_openbb_env_vars(exceptions=["OPENBB_ENABLE_AUTHENTICATION"])
|
||||
reload_openbb_config_modules()
|
||||
response = Hub.fetch_user_configs(session)
|
||||
if response is not None:
|
||||
if response.status_code == 200:
|
||||
@@ -99,39 +119,19 @@ def logout(
|
||||
r = Hub.delete_session(auth_header, token)
|
||||
if not r or r.status_code != 200:
|
||||
success = False
|
||||
User.clear()
|
||||
User.clear()
|
||||
|
||||
clear_openbb_env_vars()
|
||||
remove_log_handlers()
|
||||
reload_openbb_modules()
|
||||
|
||||
if not Local.remove_session_file():
|
||||
success = False
|
||||
if not Local.remove_session_file():
|
||||
success = False
|
||||
|
||||
if not Local.remove_cli_history_file():
|
||||
success = False
|
||||
|
||||
clear_openbb_env_vars()
|
||||
remove_log_handlers()
|
||||
reload_openbb_config_modules()
|
||||
|
||||
plt.close("all")
|
||||
|
||||
if success:
|
||||
console.print("[green]\nLogout successful.[/green]")
|
||||
|
||||
|
||||
def clear_openbb_env_vars():
|
||||
"""Clear openbb environment variables."""
|
||||
for v in os.environ:
|
||||
if v.startswith("OPENBB"):
|
||||
os.environ.pop(v)
|
||||
|
||||
|
||||
def remove_log_handlers():
|
||||
"""Remove the log handlers - needs to be done before reloading modules."""
|
||||
for handler in logging.root.handlers[:]:
|
||||
logging.root.removeHandler(handler)
|
||||
|
||||
|
||||
def reload_openbb_modules():
|
||||
"""Reload all openbb modules to clear memorized variables."""
|
||||
modules = sys.modules.copy()
|
||||
for module in modules:
|
||||
if module.startswith("openbb"):
|
||||
importlib.reload(sys.modules[module])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import openbb_terminal.feature_flags as obbff
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.session.hub_model import REGISTER_LINK
|
||||
from openbb_terminal.session.hub_model import REGISTER_URL
|
||||
|
||||
|
||||
class User:
|
||||
@@ -58,10 +58,7 @@ class User:
|
||||
sync = "OFF"
|
||||
console.print(f"[info]sync:[/info] {sync}")
|
||||
else:
|
||||
console.print(
|
||||
"[info]You are currently logged as a guest.\n"
|
||||
f"Create an account here {REGISTER_LINK}.[/info]"
|
||||
)
|
||||
User.print_guest_message()
|
||||
|
||||
@classmethod
|
||||
def clear(cls):
|
||||
@@ -91,3 +88,11 @@ class User:
|
||||
def get_token(cls):
|
||||
"""Get token."""
|
||||
return cls._token
|
||||
|
||||
@classmethod
|
||||
def print_guest_message(cls):
|
||||
"""Print guest message."""
|
||||
console.print(
|
||||
"[info]You are currently logged as a guest.\n"
|
||||
f"[info]Register: [/info][cmds]{REGISTER_URL}\n[/cmds]"
|
||||
)
|
||||
|
||||
@@ -315,7 +315,7 @@ class StocksController(StockBaseController):
|
||||
self.custom_load_wrapper([self.ticker])
|
||||
|
||||
stocks_view.display_quote(
|
||||
ns_parser.s_ticker,
|
||||
self.ticker,
|
||||
ns_parser.export,
|
||||
" ".join(ns_parser.sheet_name) if ns_parser.sheet_name else None,
|
||||
)
|
||||
|
||||
@@ -28,7 +28,9 @@ def display_quote(symbol: str, export: str = "", sheet_name: str = None):
|
||||
if quote.empty:
|
||||
console.print("[red]Data not found[/red]\n")
|
||||
else:
|
||||
print_rich_table(quote, headers=[""], title=f"{symbol} Quote", show_index=True)
|
||||
print_rich_table(
|
||||
quote, headers=[""], title=f"{symbol.upper()} Quote", show_index=True
|
||||
)
|
||||
|
||||
export_data(
|
||||
export,
|
||||
|
||||
@@ -5,7 +5,6 @@ __docformat__ = "numpy"
|
||||
import argparse
|
||||
import contextlib
|
||||
import difflib
|
||||
import importlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
@@ -33,7 +32,6 @@ from openbb_terminal.core.config.paths import (
|
||||
USER_DATA_DIRECTORY,
|
||||
USER_ENV_FILE,
|
||||
USER_ROUTINES_DIRECTORY,
|
||||
load_dotenv_with_priority,
|
||||
)
|
||||
from openbb_terminal.core.log.generation.custom_logger import log_terminal
|
||||
from openbb_terminal.helper_funcs import (
|
||||
@@ -48,12 +46,11 @@ from openbb_terminal.parent_classes import BaseController
|
||||
from openbb_terminal.reports.reports_model import ipykernel_launcher
|
||||
from openbb_terminal.rich_config import MenuText, console
|
||||
from openbb_terminal.session import session_controller
|
||||
from openbb_terminal.session.hub_model import REGISTER_LINK
|
||||
from openbb_terminal.session.user import User
|
||||
from openbb_terminal.terminal_helper import (
|
||||
bootup,
|
||||
check_for_updates,
|
||||
is_installer,
|
||||
is_auth_enabled,
|
||||
is_packaged_application,
|
||||
is_reset,
|
||||
print_goodbye,
|
||||
@@ -82,7 +79,6 @@ class TerminalController(BaseController):
|
||||
"""Terminal Controller class."""
|
||||
|
||||
CHOICES_COMMANDS = [
|
||||
"account",
|
||||
"keys",
|
||||
"settings",
|
||||
"survey",
|
||||
@@ -110,6 +106,9 @@ class TerminalController(BaseController):
|
||||
"funds",
|
||||
]
|
||||
|
||||
if is_auth_enabled():
|
||||
CHOICES_MENUS.append("account")
|
||||
|
||||
PATH = "/"
|
||||
|
||||
GUESS_TOTAL_TRIES = 0
|
||||
@@ -173,7 +172,8 @@ class TerminalController(BaseController):
|
||||
mt.add_cmd("news")
|
||||
mt.add_raw("\n")
|
||||
mt.add_info("_configure_")
|
||||
mt.add_menu("account")
|
||||
if is_auth_enabled():
|
||||
mt.add_menu("account")
|
||||
mt.add_menu("keys")
|
||||
mt.add_menu("featflags")
|
||||
mt.add_menu("sources")
|
||||
@@ -369,10 +369,7 @@ class TerminalController(BaseController):
|
||||
from openbb_terminal.account.account_controller import AccountController
|
||||
|
||||
if User.is_guest():
|
||||
console.print(
|
||||
"[info]You need to be logged in to use this menu.\n"
|
||||
f"Create an account here {REGISTER_LINK}.[/info]\n"
|
||||
)
|
||||
User.print_guest_message()
|
||||
return
|
||||
self.queue = self.load_class(AccountController, self.queue)
|
||||
|
||||
@@ -836,13 +833,6 @@ class TerminalController(BaseController):
|
||||
def terminal(jobs_cmds: List[str] = None, test_mode=False):
|
||||
"""Terminal Menu."""
|
||||
|
||||
if User.is_guest():
|
||||
load_dotenv_with_priority()
|
||||
modules = sys.modules.copy()
|
||||
for module in modules:
|
||||
if module.startswith("openbb"):
|
||||
importlib.reload(sys.modules[module])
|
||||
|
||||
log_terminal(test_mode=test_mode)
|
||||
|
||||
if jobs_cmds is not None and jobs_cmds:
|
||||
@@ -949,6 +939,9 @@ def terminal(jobs_cmds: List[str] = None, test_mode=False):
|
||||
an_input = input(f"{get_flair()} / $ ")
|
||||
|
||||
try:
|
||||
if an_input == "logout":
|
||||
break
|
||||
|
||||
# Process the input command
|
||||
t_controller.queue = t_controller.switch(an_input)
|
||||
|
||||
@@ -963,9 +956,6 @@ def terminal(jobs_cmds: List[str] = None, test_mode=False):
|
||||
print_goodbye()
|
||||
break
|
||||
|
||||
if an_input == "logout":
|
||||
break
|
||||
|
||||
except SystemExit:
|
||||
logger.exception(
|
||||
"The command '%s' doesn't exist on the / menu.",
|
||||
@@ -998,7 +988,7 @@ def terminal(jobs_cmds: List[str] = None, test_mode=False):
|
||||
t_controller.queue.insert(0, an_input)
|
||||
|
||||
if an_input == "logout":
|
||||
return session_controller.main(guest_allowed=not is_installer())
|
||||
return session_controller.main()
|
||||
|
||||
|
||||
def insert_start_slash(cmds: List[str]) -> List[str]:
|
||||
@@ -1217,15 +1207,6 @@ def parse_args_and_run():
|
||||
type=lambda s: [str(item) for item in s.split(",")],
|
||||
default=None,
|
||||
)
|
||||
# The args -m, -f and --HistoryManager.hist_file are used only in reports menu
|
||||
# by papermill and that's why they have suppress help.
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
help=argparse.SUPPRESS,
|
||||
dest="module",
|
||||
default="",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--test",
|
||||
@@ -1235,6 +1216,21 @@ def parse_args_and_run():
|
||||
" to see testing argument options."
|
||||
),
|
||||
)
|
||||
if is_auth_enabled():
|
||||
parser.add_argument(
|
||||
"--login",
|
||||
action="store_true",
|
||||
help="Go to login prompt.",
|
||||
)
|
||||
# The args -m, -f and --HistoryManager.hist_file are used only in reports menu
|
||||
# by papermill and that's why they have suppress help.
|
||||
parser.add_argument(
|
||||
"-m",
|
||||
help=argparse.SUPPRESS,
|
||||
dest="module",
|
||||
default="",
|
||||
type=str,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
help=argparse.SUPPRESS,
|
||||
|
||||
@@ -24,6 +24,7 @@ from openbb_terminal import (
|
||||
from openbb_terminal.config_terminal import LOGGING_APP_NAME, LOGGING_COMMIT_HASH
|
||||
from openbb_terminal.helper_funcs import request
|
||||
from openbb_terminal.rich_config import console
|
||||
from openbb_terminal.session.user import User
|
||||
|
||||
# pylint: disable=too-many-statements,no-member,too-many-branches,C0302
|
||||
|
||||
@@ -229,6 +230,21 @@ def is_packaged_application() -> bool:
|
||||
return LOGGING_APP_NAME == "gst_packaged"
|
||||
|
||||
|
||||
def is_auth_enabled() -> bool:
|
||||
"""Tell whether or not authentication is enabled.
|
||||
|
||||
Returns
|
||||
-------
|
||||
bool
|
||||
If authentication is enabled
|
||||
"""
|
||||
# TODO: This function is a temporary way to block authentication
|
||||
return (
|
||||
str(os.getenv("OPENBB_ENABLE_AUTHENTICATION")).lower() == "true"
|
||||
or "--login" in sys.argv[1:]
|
||||
)
|
||||
|
||||
|
||||
def is_installer() -> bool:
|
||||
"""Tell whether or not it is a packaged version."""
|
||||
# TODO: Merge this with is_packaged_application
|
||||
@@ -338,15 +354,19 @@ def reset(queue: List[str] = None):
|
||||
logger.info("resetting")
|
||||
plt.close("all")
|
||||
|
||||
flag = ""
|
||||
if not User.is_guest():
|
||||
flag = " --login"
|
||||
|
||||
if queue and len(queue) > 0:
|
||||
completed_process = subprocess.run( # nosec
|
||||
f"{sys.executable} terminal.py {'/'.join(queue) if len(queue) > 0 else ''}",
|
||||
f"{sys.executable} terminal.py {'/'.join(queue) if len(queue) > 0 else ''}{flag}",
|
||||
shell=True,
|
||||
check=False,
|
||||
)
|
||||
else:
|
||||
completed_process = subprocess.run( # nosec
|
||||
f"{sys.executable} terminal.py", shell=True, check=False
|
||||
f"{sys.executable} terminal.py{flag}", shell=True, check=False
|
||||
)
|
||||
if completed_process.returncode != 0:
|
||||
console.print("Unfortunately, resetting wasn't possible!\n")
|
||||
|
||||
17
terminal.py
17
terminal.py
@@ -1,14 +1,23 @@
|
||||
import multiprocessing
|
||||
import sys
|
||||
|
||||
from openbb_terminal.core.integration_tests import integration_controller
|
||||
from openbb_terminal.session import session_controller
|
||||
from openbb_terminal.terminal_helper import is_installer
|
||||
from openbb_terminal.base_helpers import load_dotenv_and_reload_configs
|
||||
from openbb_terminal.terminal_helper import is_auth_enabled
|
||||
|
||||
if __name__ == "__main__":
|
||||
multiprocessing.freeze_support()
|
||||
sent_args = sys.argv[1:]
|
||||
|
||||
load_dotenv_and_reload_configs()
|
||||
|
||||
if "-t" in sent_args or "--test" in sent_args:
|
||||
from openbb_terminal.core.integration_tests import integration_controller
|
||||
|
||||
integration_controller.main()
|
||||
else:
|
||||
session_controller.main(guest_allowed=not is_installer())
|
||||
from openbb_terminal.session import session_controller
|
||||
|
||||
if is_auth_enabled():
|
||||
session_controller.main()
|
||||
else:
|
||||
session_controller.launch_terminal()
|
||||
|
||||
@@ -323,6 +323,11 @@ def pytest_addoption(parser: Parser):
|
||||
action="store_true",
|
||||
help="To run tests with the marker : @pytest.mark.optimization",
|
||||
)
|
||||
parser.addoption(
|
||||
"--session",
|
||||
action="store_true",
|
||||
help="To run tests with the marker : @pytest.mark.session",
|
||||
)
|
||||
parser.addoption(
|
||||
"--rewrite-expected",
|
||||
action="store_true",
|
||||
|
||||
@@ -250,6 +250,7 @@ def test_call_func_expect_queue(expected_queue, func, queue):
|
||||
@pytest.mark.parametrize(
|
||||
"func",
|
||||
[
|
||||
"call_logout",
|
||||
"call_sync",
|
||||
"call_pull",
|
||||
"call_clear",
|
||||
@@ -273,6 +274,20 @@ def test_call_func_no_parser(func, mocker):
|
||||
controller.parse_known_args_and_warn.assert_called_once()
|
||||
|
||||
|
||||
def test_call_logout(mocker):
|
||||
controller = account_controller.AccountController(queue=None)
|
||||
path_controller = "openbb_terminal.account.account_controller"
|
||||
|
||||
mock_logout = mocker.patch(
|
||||
target=f"{path_controller}.logout",
|
||||
)
|
||||
|
||||
controller.call_logout([])
|
||||
|
||||
assert controller.queue == []
|
||||
mock_logout.assert_called_once()
|
||||
|
||||
|
||||
@pytest.mark.vcr
|
||||
@pytest.mark.record_stdout
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
@@ -9,3 +9,6 @@ Cloud storage of routines:
|
||||
download Download routine
|
||||
delete Delete routine
|
||||
|
||||
Authentication:
|
||||
logout Log out from OpenBB account
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer a4eaa48d-299c-4305-973f-4398e40eeb49
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:82.1) Gecko/20100101 Firefox/82.1
|
||||
method: GET
|
||||
uri: https://payments.openbb.dev/sdk/token
|
||||
response:
|
||||
body:
|
||||
string: '{"detail":"Could not validate credentials"}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '43'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 13 Feb 2023 10:31:27 GMT
|
||||
Server:
|
||||
- nginx/1.22.1
|
||||
www-authenticate:
|
||||
- Bearer
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,38 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer a4eaa48d-299c-4305-973f-4398e40eeb49
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Mozilla/5.0 (Windows NT 6.1; WOW64; rv:84.0) Gecko/20100101 Firefox/84.0
|
||||
method: GET
|
||||
uri: https://payments.openbb.dev/sdk/token
|
||||
response:
|
||||
body:
|
||||
string: '{"detail":"Could not validate credentials"}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '43'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 13 Feb 2023 10:31:28 GMT
|
||||
Server:
|
||||
- nginx/1.22.1
|
||||
www-authenticate:
|
||||
- Bearer
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
@@ -0,0 +1,38 @@
|
||||
interactions:
|
||||
- request:
|
||||
body: null
|
||||
headers:
|
||||
Accept:
|
||||
- '*/*'
|
||||
Accept-Encoding:
|
||||
- gzip, deflate
|
||||
Authorization:
|
||||
- Bearer a4eaa48d-299c-4305-973f-4398e40eeb49
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Type:
|
||||
- application/json
|
||||
User-Agent:
|
||||
- Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.10; rv:86.1) Gecko/20100101 Firefox/86.1
|
||||
method: GET
|
||||
uri: https://payments.openbb.dev/sdk/token
|
||||
response:
|
||||
body:
|
||||
string: '{"detail":"Could not validate credentials"}'
|
||||
headers:
|
||||
Connection:
|
||||
- keep-alive
|
||||
Content-Length:
|
||||
- '43'
|
||||
Content-Type:
|
||||
- application/json
|
||||
Date:
|
||||
- Mon, 13 Feb 2023 10:31:29 GMT
|
||||
Server:
|
||||
- nginx/1.22.1
|
||||
www-authenticate:
|
||||
- Bearer
|
||||
status:
|
||||
code: 401
|
||||
message: Unauthorized
|
||||
version: 1
|
||||
7
tests/openbb_terminal/session/conftest.py
Normal file
7
tests/openbb_terminal/session/conftest.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import pytest
|
||||
from _pytest.nodes import Node
|
||||
|
||||
|
||||
def pytest_runtest_setup(item: Node):
|
||||
if not item.config.getoption("--session"):
|
||||
pytest.skip(msg="Runs only with option : --session")
|
||||
@@ -61,6 +61,44 @@ def test_create_session_exception(email, password):
|
||||
assert response is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token", [("test_token")])
|
||||
def test_create_session_from_token_success(token):
|
||||
with patch("requests.post") as mock_post:
|
||||
mock_post.return_value.json.return_value = TEST_RESPONSE
|
||||
response = hub_model.create_session_from_token(token)
|
||||
assert response.json() == TEST_RESPONSE
|
||||
|
||||
mock_post.assert_called_once_with(
|
||||
url=hub_model.BASE_URL + "sdk/login",
|
||||
json={"token": token},
|
||||
timeout=hub_model.TIMEOUT,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token", [("test_token")])
|
||||
def test_create_session_from_token_connection_error(token):
|
||||
with patch("requests.post") as mock_post:
|
||||
mock_post.side_effect = requests.exceptions.ConnectionError
|
||||
response = hub_model.create_session_from_token(token)
|
||||
assert response is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token", [("test_token")])
|
||||
def test_create_session_from_token_timeout(token):
|
||||
with patch("requests.post") as mock_post:
|
||||
mock_post.side_effect = requests.exceptions.Timeout
|
||||
response = hub_model.create_session_from_token(token)
|
||||
assert response is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token", [("test_token")])
|
||||
def test_create_session_from_token_exception(token):
|
||||
with patch("requests.post") as mock_post:
|
||||
mock_post.side_effect = Exception
|
||||
response = hub_model.create_session_from_token(token)
|
||||
assert response is None
|
||||
|
||||
|
||||
@pytest.mark.parametrize("auth_header, token", TEST_HEADER_TOKEN)
|
||||
def test_delete_session_success(auth_header, token):
|
||||
with patch("requests.post") as mock_post:
|
||||
@@ -186,6 +224,56 @@ def test_get_session_failed_to_request():
|
||||
create_session_mock.assert_called_once_with("email", "password")
|
||||
|
||||
|
||||
def test_get_session_from_token():
|
||||
mock_response = MagicMock(spec=requests.Response)
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {"session": "info"}
|
||||
|
||||
with patch(
|
||||
"openbb_terminal.session.hub_model.create_session_from_token",
|
||||
return_value=mock_response,
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {"session": "info"}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
|
||||
|
||||
def test_get_session_from_token_401():
|
||||
mock_response = MagicMock(spec=requests.Response)
|
||||
mock_response.status_code = 401
|
||||
|
||||
with patch(
|
||||
"openbb_terminal.session.hub_model.create_session_from_token",
|
||||
return_value=mock_response,
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
|
||||
|
||||
def test_get_session_from_token_403():
|
||||
mock_response = MagicMock(spec=requests.Response)
|
||||
mock_response.status_code = 403
|
||||
|
||||
with patch(
|
||||
"openbb_terminal.session.hub_model.create_session_from_token",
|
||||
return_value=mock_response,
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
|
||||
|
||||
def test_get_session_from_token_failed_to_request():
|
||||
with patch(
|
||||
"openbb_terminal.session.hub_model.create_session_from_token",
|
||||
return_value=None,
|
||||
) as create_session_mock:
|
||||
result = hub_model.get_session_from_token("token")
|
||||
assert result == {}
|
||||
create_session_mock.assert_called_once_with("token")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("token_type, access_token", [("TokenType", "AccessToken")])
|
||||
def test_fetch_user_configs_success(token_type, access_token):
|
||||
mock_response = MagicMock(spec=requests.Response)
|
||||
|
||||
@@ -18,51 +18,83 @@ TEST_SESSION = {
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"email, password, save",
|
||||
"email, password, token, save",
|
||||
[
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_session_exception(email: str, password: str, save: bool):
|
||||
def test_get_session_exception(email: str, password: str, token: str, save: bool):
|
||||
path = "openbb_terminal.session.sdk_session."
|
||||
with patch(path + "session_model.create_session") as mock_create_session:
|
||||
mock_create_session.return_value = {}
|
||||
with patch(
|
||||
path + "session_model.create_session_from_token"
|
||||
) as mock_create_session_from_token:
|
||||
mock_create_session.return_value = {}
|
||||
mock_create_session_from_token.return_value = {}
|
||||
|
||||
with pytest.raises(Exception):
|
||||
sdk_session.get_session(email=email, password=password, save=save)
|
||||
with pytest.raises(Exception):
|
||||
sdk_session.get_session(
|
||||
email=email, password=password, token=token, save=save
|
||||
)
|
||||
|
||||
mock_create_session.assert_called_once_with(email, password, save)
|
||||
mock_create_session.assert_called_once_with(email, password, save)
|
||||
mock_create_session_from_token.assert_called_once_with(token, save)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"email, password, save",
|
||||
"email, password, token, save",
|
||||
[
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_session(email: str, password: str, save: bool):
|
||||
def test_get_session(email: str, password: str, token: str, save: bool):
|
||||
path = "openbb_terminal.session.sdk_session."
|
||||
with patch(path + "session_model.create_session") as mock_create_session:
|
||||
mock_create_session.return_value = TEST_SESSION
|
||||
|
||||
sdk_session.get_session(email=email, password=password, save=save)
|
||||
sdk_session.get_session(email=email, password=password, token=token, save=save)
|
||||
mock_create_session.assert_called_once_with(email, password, save)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"email, password, keep_session, has_session, status",
|
||||
"email, password, token, save",
|
||||
[
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_get_session_from_token(email: str, password: str, token: str, save: bool):
|
||||
path = "openbb_terminal.session.sdk_session."
|
||||
with patch(
|
||||
path + "session_model.create_session_from_token"
|
||||
) as mock_create_session_from_token:
|
||||
mock_create_session_from_token.return_value = TEST_SESSION
|
||||
|
||||
sdk_session.get_session(email=email, password=password, token=token, save=save)
|
||||
mock_create_session_from_token.assert_called_once_with(token, save)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"email, password, token, keep_session, has_session, status",
|
||||
[
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
False,
|
||||
LoginStatus.SUCCESS,
|
||||
@@ -70,6 +102,7 @@ def test_get_session(email: str, password: str, save: bool):
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
True,
|
||||
LoginStatus.SUCCESS,
|
||||
@@ -77,6 +110,7 @@ def test_get_session(email: str, password: str, save: bool):
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
False,
|
||||
LoginStatus.FAILED,
|
||||
@@ -84,6 +118,7 @@ def test_get_session(email: str, password: str, save: bool):
|
||||
(
|
||||
"test_email",
|
||||
"test_pass",
|
||||
"test_token",
|
||||
True,
|
||||
False,
|
||||
LoginStatus.NO_RESPONSE,
|
||||
@@ -91,40 +126,48 @@ def test_get_session(email: str, password: str, save: bool):
|
||||
],
|
||||
)
|
||||
def test_login(
|
||||
mocker,
|
||||
email: str,
|
||||
password: str,
|
||||
token: str,
|
||||
keep_session: bool,
|
||||
has_session: bool,
|
||||
status: LoginStatus,
|
||||
):
|
||||
path = "openbb_terminal.session.sdk_session."
|
||||
with (
|
||||
patch(path + "session_model.login") as mock_login,
|
||||
patch(path + "Local.get_session") as mock_local_get_session,
|
||||
patch(path + "get_session") as mock_hub_get_session,
|
||||
):
|
||||
if has_session:
|
||||
mock_local_get_session.return_value = TEST_SESSION
|
||||
else:
|
||||
mock_local_get_session.return_value = None
|
||||
mock_login = mocker.patch(path + "session_model.login")
|
||||
mock_local_get_session = mocker.patch(path + "Local.get_session")
|
||||
mock_hub_get_session = mocker.patch(path + "get_session")
|
||||
|
||||
mock_hub_get_session.return_value = TEST_SESSION
|
||||
mock_login.return_value = status
|
||||
if has_session:
|
||||
mock_local_get_session.return_value = TEST_SESSION
|
||||
else:
|
||||
mock_local_get_session.return_value = None
|
||||
|
||||
if status in [LoginStatus.FAILED, LoginStatus.NO_RESPONSE]:
|
||||
with pytest.raises(Exception):
|
||||
sdk_session.login(
|
||||
email=email, password=password, keep_session=keep_session
|
||||
)
|
||||
else:
|
||||
sdk_session.login(email=email, password=password, keep_session=keep_session)
|
||||
mock_hub_get_session.return_value = TEST_SESSION
|
||||
mock_login.return_value = status
|
||||
|
||||
mock_local_get_session.assert_called_once()
|
||||
if has_session:
|
||||
mock_hub_get_session.assert_not_called()
|
||||
else:
|
||||
mock_hub_get_session.assert_called_once_with(email, password, keep_session)
|
||||
mock_login.assert_called_once_with(TEST_SESSION)
|
||||
if status in [LoginStatus.FAILED, LoginStatus.NO_RESPONSE]:
|
||||
with pytest.raises(Exception):
|
||||
sdk_session.login(
|
||||
email=email,
|
||||
password=password,
|
||||
token=token,
|
||||
keep_session=keep_session,
|
||||
)
|
||||
else:
|
||||
sdk_session.login(
|
||||
email=email, password=password, token=token, keep_session=keep_session
|
||||
)
|
||||
|
||||
mock_local_get_session.assert_called_once()
|
||||
if has_session:
|
||||
mock_hub_get_session.assert_not_called()
|
||||
else:
|
||||
mock_hub_get_session.assert_called_once_with(
|
||||
email, password, token, keep_session
|
||||
)
|
||||
mock_login.assert_called_once_with(TEST_SESSION)
|
||||
|
||||
|
||||
def test_logout():
|
||||
@@ -137,3 +180,21 @@ def test_logout():
|
||||
token=User.get_token(),
|
||||
guest=User.is_guest(),
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.record_stdout
|
||||
def test_whoami_guest():
|
||||
sdk_session.whoami()
|
||||
|
||||
|
||||
@pytest.mark.record_stdout
|
||||
def test_whoami():
|
||||
User.load_user_info(
|
||||
{
|
||||
"token_type": "MOCK_TOKEN_TYPE",
|
||||
"access_token": "MOCK_ACCESS_TOKEN",
|
||||
"uuid": "MOCK_UUID",
|
||||
},
|
||||
email="MOCK_EMAIL",
|
||||
)
|
||||
sdk_session.whoami()
|
||||
|
||||
@@ -47,18 +47,6 @@ def test_prompt():
|
||||
assert create_session_mock.call_count == 1
|
||||
|
||||
|
||||
def test_prompt_guest_allowed():
|
||||
with patch(
|
||||
"openbb_terminal.session.session_controller.get_user_input",
|
||||
return_value=(None, None, False),
|
||||
) as get_user_input_mock, patch(
|
||||
"openbb_terminal.session.session_controller.launch_terminal", return_value=True
|
||||
) as launch_terminal_mock:
|
||||
session_controller.prompt(guest_allowed=True)
|
||||
assert get_user_input_mock.call_count == 1
|
||||
assert launch_terminal_mock.call_count == 1
|
||||
|
||||
|
||||
def test_launch_terminal():
|
||||
with patch(
|
||||
"openbb_terminal.session.session_controller.terminal_controller.parse_args_and_run",
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
# IMPORTATION THIRDPARTY
|
||||
import json
|
||||
import os
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
from requests import Response
|
||||
@@ -47,14 +45,13 @@ CONFIGS = {
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_create_session(email, password, save):
|
||||
def test_create_session(mocker, email, password, save):
|
||||
path = "openbb_terminal.session.session_model."
|
||||
with (
|
||||
patch(path + "Hub.get_session") as mock_get_session,
|
||||
patch(path + "Local.save_session") as mock_save_session,
|
||||
):
|
||||
mock_get_session.return_value = TEST_SESSION
|
||||
session = session_model.create_session(email, password, save)
|
||||
mock_get_session = mocker.patch(path + "Hub.get_session")
|
||||
mock_save_session = mocker.patch(path + "Local.save_session")
|
||||
|
||||
mock_get_session.return_value = TEST_SESSION
|
||||
session = session_model.create_session(email, password, save)
|
||||
|
||||
assert session == TEST_SESSION
|
||||
|
||||
@@ -63,63 +60,76 @@ def test_create_session(email, password, save):
|
||||
mock_save_session.assert_called_once_with(session)
|
||||
|
||||
|
||||
def test_login_no_response():
|
||||
def test_login_no_response(mocker):
|
||||
path = "openbb_terminal.session.session_model."
|
||||
with (
|
||||
patch(path + "Hub.fetch_user_configs") as mock_fetch_user_configs,
|
||||
patch(path + "Local.apply_configs") as mock_apply_configs,
|
||||
patch(path + "User.load_user_info") as mock_load_user_info,
|
||||
patch(path + "User.update_flair") as mock_update_flair,
|
||||
):
|
||||
mock_fetch_user_configs.return_value = None
|
||||
mock_clear_openbb_env_vars = mocker.patch(path + "clear_openbb_env_vars")
|
||||
mock_reload_openbb_config_modules = mocker.patch(
|
||||
path + "reload_openbb_config_modules"
|
||||
)
|
||||
mock_fetch_user_configs = mocker.patch(path + "Hub.fetch_user_configs")
|
||||
mock_apply_configs = mocker.patch(path + "Local.apply_configs")
|
||||
mock_load_user_info = mocker.patch(path + "User.load_user_info")
|
||||
mock_update_flair = mocker.patch(path + "User.update_flair")
|
||||
|
||||
assert (
|
||||
session_model.login(TEST_SESSION) == session_model.LoginStatus.NO_RESPONSE
|
||||
)
|
||||
mock_fetch_user_configs.return_value = None
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.NO_RESPONSE
|
||||
|
||||
mock_clear_openbb_env_vars.assert_called_once()
|
||||
mock_reload_openbb_config_modules.assert_called_once()
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_apply_configs.assert_not_called()
|
||||
mock_load_user_info.assert_not_called()
|
||||
mock_update_flair.assert_not_called()
|
||||
|
||||
|
||||
def test_login_fail_response():
|
||||
def test_login_fail_response(mocker):
|
||||
path = "openbb_terminal.session.session_model."
|
||||
with (
|
||||
patch(path + "Hub.fetch_user_configs") as mock_fetch_user_configs,
|
||||
patch(path + "Local.apply_configs") as mock_apply_configs,
|
||||
patch(path + "User.load_user_info") as mock_load_user_info,
|
||||
patch(path + "User.update_flair") as mock_update_flair,
|
||||
):
|
||||
response = Response()
|
||||
response.status_code = 400
|
||||
mock_fetch_user_configs.return_value = response
|
||||
mock_clear_openbb_env_vars = mocker.patch(path + "clear_openbb_env_vars")
|
||||
mock_reload_openbb_config_modules = mocker.patch(
|
||||
path + "reload_openbb_config_modules"
|
||||
)
|
||||
mock_fetch_user_configs = mocker.patch(path + "Hub.fetch_user_configs")
|
||||
mock_apply_configs = mocker.patch(path + "Local.apply_configs")
|
||||
mock_load_user_info = mocker.patch(path + "User.load_user_info")
|
||||
mock_update_flair = mocker.patch(path + "User.update_flair")
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.FAILED
|
||||
response = Response()
|
||||
response.status_code = 400
|
||||
mock_fetch_user_configs.return_value = response
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.FAILED
|
||||
|
||||
mock_clear_openbb_env_vars.assert_called_once()
|
||||
mock_reload_openbb_config_modules.assert_called_once()
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_apply_configs.assert_not_called()
|
||||
mock_load_user_info.assert_not_called()
|
||||
mock_update_flair.assert_not_called()
|
||||
|
||||
|
||||
def test_login_success_response():
|
||||
def test_login_success_response(mocker):
|
||||
path = "openbb_terminal.session.session_model."
|
||||
with (
|
||||
patch(path + "Hub.fetch_user_configs") as mock_fetch_user_configs,
|
||||
patch(path + "Local.apply_configs") as mock_apply_configs,
|
||||
patch(path + "User.load_user_info") as mock_load_user_info,
|
||||
patch(path + "User.update_flair") as mock_update_flair,
|
||||
):
|
||||
response = Response()
|
||||
response.status_code = 200
|
||||
response._content = json.dumps( # pylint: disable=protected-access
|
||||
CONFIGS
|
||||
).encode("utf-8")
|
||||
mock_fetch_user_configs.return_value = response
|
||||
mock_clear_openbb_env_vars = mocker.patch(path + "clear_openbb_env_vars")
|
||||
mock_reload_openbb_config_modules = mocker.patch(
|
||||
path + "reload_openbb_config_modules"
|
||||
)
|
||||
mock_fetch_user_configs = mocker.patch(path + "Hub.fetch_user_configs")
|
||||
mock_apply_configs = mocker.patch(path + "Local.apply_configs")
|
||||
mock_load_user_info = mocker.patch(path + "User.load_user_info")
|
||||
mock_update_flair = mocker.patch(path + "User.update_flair")
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.SUCCESS
|
||||
response = Response()
|
||||
response.status_code = 200
|
||||
response._content = json.dumps(CONFIGS).encode( # pylint: disable=protected-access
|
||||
"utf-8"
|
||||
)
|
||||
mock_fetch_user_configs.return_value = response
|
||||
|
||||
assert session_model.login(TEST_SESSION) == session_model.LoginStatus.SUCCESS
|
||||
|
||||
mock_clear_openbb_env_vars.assert_called_once()
|
||||
mock_reload_openbb_config_modules.assert_called_once()
|
||||
mock_fetch_user_configs.assert_called_once_with(TEST_SESSION)
|
||||
mock_apply_configs.assert_called_once()
|
||||
mock_load_user_info.assert_called_once()
|
||||
@@ -133,43 +143,27 @@ def test_login_success_response():
|
||||
True,
|
||||
],
|
||||
)
|
||||
def test_logout_user(guest):
|
||||
def test_logout_user(mocker, guest):
|
||||
path = "openbb_terminal.session.session_model."
|
||||
with (
|
||||
patch(path + "Hub.delete_session") as mock_delete_session,
|
||||
patch(path + "Local.remove_session_file") as mock_remove_session_file,
|
||||
patch(path + "Local.remove_cli_history_file") as mock_remove_cli_history_file,
|
||||
patch(path + "reload_openbb_modules") as mock_reload_openbb_modules,
|
||||
patch(path + "clear_openbb_env_vars") as mock_clear_openbb_env_vars,
|
||||
patch(path + "User.clear") as mock_clear_user,
|
||||
patch(path + "plt.close") as mock_plt_close,
|
||||
):
|
||||
auth_header = "Bearer test_token"
|
||||
token = "test_token"
|
||||
session_model.logout(auth_header, token, guest)
|
||||
mock_delete_session = mocker.patch(path + "Hub.delete_session")
|
||||
mock_remove_session_file = mocker.patch(path + "Local.remove_session_file")
|
||||
mock_remove_cli_history_file = mocker.patch(path + "Local.remove_cli_history_file")
|
||||
mock_reload_openbb_config_modules = mocker.patch(
|
||||
path + "reload_openbb_config_modules"
|
||||
)
|
||||
mock_clear_openbb_env_vars = mocker.patch(path + "clear_openbb_env_vars")
|
||||
mock_clear_user = mocker.patch(path + "User.clear")
|
||||
mock_plt_close = mocker.patch(path + "plt.close")
|
||||
|
||||
auth_header = "Bearer test_token"
|
||||
token = "test_token"
|
||||
session_model.logout(auth_header, token, guest)
|
||||
|
||||
if not guest:
|
||||
mock_delete_session.assert_called_once_with(auth_header, token)
|
||||
mock_clear_user.assert_called_once()
|
||||
mock_clear_user.assert_called_once()
|
||||
mock_remove_session_file.assert_called_once()
|
||||
mock_clear_openbb_env_vars.assert_called_once()
|
||||
mock_reload_openbb_modules.assert_called_once()
|
||||
mock_remove_session_file.assert_called_once()
|
||||
mock_reload_openbb_config_modules.assert_called_once()
|
||||
mock_remove_cli_history_file.assert_called_once()
|
||||
mock_plt_close.assert_called_once()
|
||||
|
||||
|
||||
def test_clear_openbb_env_vars():
|
||||
mock_env = {"OPENBB_TEST": "test", "OPENBB_TEST2": "test2", "TEST": "test"}
|
||||
with patch.dict("openbb_terminal.session.session_model.os.environ", mock_env):
|
||||
session_model.clear_openbb_env_vars()
|
||||
|
||||
assert "OPENBB_TEST" not in os.environ
|
||||
assert "OPENBB_TEST2" not in os.environ
|
||||
assert "TEST" in os.environ
|
||||
|
||||
|
||||
def test_reload_openbb_modules():
|
||||
with patch("openbb_terminal.session.session_model.importlib.reload") as mock_reload:
|
||||
session_model.reload_openbb_modules()
|
||||
|
||||
mock_reload.assert_called()
|
||||
|
||||
3
tests/openbb_terminal/session/txt/test_sdk_session/test_whoami.txt
vendored
Normal file
3
tests/openbb_terminal/session/txt/test_sdk_session/test_whoami.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[info]email:[/info] MOCK_EMAIL
|
||||
[info]uuid:[/info] MOCK_UUID
|
||||
[info]sync:[/info] ON
|
||||
3
tests/openbb_terminal/session/txt/test_sdk_session/test_whoami_guest.txt
vendored
Normal file
3
tests/openbb_terminal/session/txt/test_sdk_session/test_whoami_guest.txt
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[info]email:[/info] test@email.com
|
||||
[info]uuid:[/info] test_uuid
|
||||
[info]sync:[/info] ON
|
||||
@@ -1,2 +1,2 @@
|
||||
[info]
|
||||
Please enter your credentials or press enter for guest mode:[/info]
|
||||
Please enter your credentials:[/info]
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
[info]
|
||||
Please enter your credentials or press enter for guest mode:[/info]
|
||||
Please enter your credentials:[/info]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
[info]You are currently logged as a guest.
|
||||
Create an account here https://my.openbb.dev/register.[/info]
|
||||
[info]Register: [/info][cmds]https://my.openbb.dev/register
|
||||
[/cmds]
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -208,7 +208,7 @@ interactions:
|
||||
HSr/n476/3TU/6l01E+UkXp8evrwdPeL95/fvv3pp/8BRKYJwViiAAA=
|
||||
headers:
|
||||
Age:
|
||||
- '1'
|
||||
- '0'
|
||||
Connection:
|
||||
- keep-alive
|
||||
Expect-CT:
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
Loading Daily data for TSLA with starting period 2020-02-10.
|
||||
|
||||
1 Failed download:
|
||||
- TSLA: No data found for this date range, symbol may be delisted
|
||||
Company Rating Price Target
|
||||
Date
|
||||
2023-02-06 Wedbush Morgan Securities Inc. BUY 225.000000
|
||||
|
||||
@@ -16,6 +16,6 @@ Ten day average volume 3.910 M
|
||||
Three month average volume 4.860 M
|
||||
Timezone America/New_York
|
||||
Two hundred day average 97.606
|
||||
Year change -0.063
|
||||
Year change -0.067
|
||||
Year high 112.480
|
||||
Year low 82.850
|
||||
|
||||
32
tests/openbb_terminal/test_base_helpers.py
Normal file
32
tests/openbb_terminal/test_base_helpers.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# IMPORTATION STANDARD
|
||||
import os
|
||||
|
||||
# IMPORTATION THIRDPARTY
|
||||
from unittest.mock import patch
|
||||
|
||||
import pytest
|
||||
|
||||
# IMPORTATION INTERNAL
|
||||
from openbb_terminal import base_helpers
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"key, value",
|
||||
[
|
||||
("OPENBB_NOT_TO_REMOVE", "value"),
|
||||
],
|
||||
)
|
||||
def test_clear_openbb_env_vars(key, value):
|
||||
mock_env = {
|
||||
"OPENBB_TEST": "test",
|
||||
"OPENBB_TEST2": "test2",
|
||||
"TEST": "test",
|
||||
key: value,
|
||||
}
|
||||
with patch.dict("openbb_terminal.base_helpers.os.environ", mock_env):
|
||||
base_helpers.clear_openbb_env_vars(exceptions=[key])
|
||||
|
||||
assert "OPENBB_TEST" not in os.environ
|
||||
assert "OPENBB_TEST2" not in os.environ
|
||||
assert "TEST" in os.environ
|
||||
assert key in os.environ
|
||||
@@ -234,3 +234,20 @@ 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)
|
||||
|
||||
@@ -1563,3 +1563,53 @@ def test_set_shroom_key(
|
||||
)
|
||||
|
||||
assert_keys_and_status(args, persist, expected, env_var_name_list, status)
|
||||
|
||||
|
||||
@patch.dict(os.environ, {})
|
||||
@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
|
||||
):
|
||||
env_var_name_list = [
|
||||
"OPENBB_OPENBB_PERSONAL_ACCESS_TOKEN",
|
||||
]
|
||||
|
||||
set_naive_environment(env_var_name_list)
|
||||
|
||||
status = keys_model.set_openbb_personal_access_token(
|
||||
key=args[0],
|
||||
persist=persist,
|
||||
show_output=show_output,
|
||||
)
|
||||
|
||||
assert_keys_and_status(args, persist, expected, env_var_name_list, status)
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
from openbb_terminal.sdk import openbb
|
||||
# pylint: disable=import-outside-toplevel
|
||||
|
||||
|
||||
def test_openbb():
|
||||
def test_openbb(mocker):
|
||||
"""Test the openbb function"""
|
||||
mock = mocker.patch("openbb_terminal.base_helpers.load_dotenv_and_reload_configs")
|
||||
from openbb_terminal.sdk import openbb
|
||||
|
||||
mock.assert_called_once()
|
||||
assert "stocks" in dir(openbb)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
[red]defined, test failed[/red]
|
||||
@@ -0,0 +1 @@
|
||||
[red]defined, test failed[/red]
|
||||
@@ -0,0 +1 @@
|
||||
[grey30]not defined[/grey30]
|
||||
Reference in New Issue
Block a user