mirror of
https://github.com/OpenBB-finance/OpenBB.git
synced 2026-11-10 11:21:12 +00:00
[Feature] - Update credential filters to v4 (#5949)
* update cred filters to v4 * ignore v3 key if v4 is there already * add comment + unit test * update hub state instead of replacing * remove unused file * fix unittests * ruff * add comment * remove lc * black * comment * comment * comment * comment * send warning if v3 keys found * tradier v3 * keep v3 intact * better * unit test + minor fixes * cleaner * comment * sorted * remove unecessary class * remove ultima from v3tov4 map * unit test v3tov4 map * unit test v3tov4 map * unit test v3tov4 map * providers.json * ^ --------- Co-authored-by: Igor Radovanovic <74266147+IgorWounds@users.noreply.github.com>
This commit is contained in:
58
openbb_platform/assets/providers.json
vendored
Normal file
58
openbb_platform/assets/providers.json
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
[
|
||||
{
|
||||
"name": "Alpha Vantage",
|
||||
"credentials": ["alpha_vantage_api_key"],
|
||||
"v3_credentials": ["API_KEY_ALPHAVANTAGE"],
|
||||
"link": "https://www.alphavantage.co/support/#api-key",
|
||||
"instructions": "Go to: https://www.alphavantage.co/support/#api-key\n\n\n\nFill out the form, pass Captcha, and click on, \"GET FREE API KEY\"."
|
||||
},
|
||||
{
|
||||
"name": "BizToc",
|
||||
"credentials": ["biztoc_api_key"],
|
||||
"v3_credentials": ["API_BIZTOC_TOKEN"],
|
||||
"link": "https://biztoc.com",
|
||||
"instructions": "The BizToc API is hosted on RapidAPI. To set up, go to: https://rapidapi.com/thma/api/biztoc.\n\n\n\nIn the top right, select 'Sign Up'. After answering some questions, you will be prompted to select one of their plans.\n\n\n\nAfter signing up, navigate back to https://rapidapi.com/thma/api/biztoc. If you are logged in, you will see a header called X-RapidAPI-Key.\n\n"
|
||||
},
|
||||
{
|
||||
"name": "FRED",
|
||||
"credentials": ["fred_api_key"],
|
||||
"v3_credentials": ["API_FRED_KEY"],
|
||||
"link": "https://fred.stlouisfed.org/docs/api/api_key.html",
|
||||
"instructions": "Go to: https://fred.stlouisfed.org\n\n\n\nClick on, \"My Account\", create a new account or sign in with Google:\n\n\n\nAfter completing the sign-up, go to \"My Account\", and select \"API Keys\". Then, click on, \"Request API Key\".\n\n\n\nFill in the box for information about the use-case for FRED, and by clicking, \"Request API key\", at the bottom of the page, the API key will be issued.\n\n"
|
||||
},
|
||||
{
|
||||
"name": "Financial Modeling Prep",
|
||||
"credentials": ["fmp_api_key"],
|
||||
"v3_credentials": ["API_KEY_FINANCIALMODELINGPREP"],
|
||||
"link": "https://financialmodelingprep.com/developer",
|
||||
"instructions": "Go to: https://site.financialmodelingprep.com/developer/docs\n\n\n\nClick on, \"Get my API KEY here\", and sign up for a free account.\n\n\n\nWith an account created, sign in and navigate to the Dashboard, which shows the assigned token. by pressing the \"Dashboard\" button which will show the API key.\n\n"
|
||||
},
|
||||
{
|
||||
"name": "Intrinio",
|
||||
"credentials": ["intrinio_api_key"],
|
||||
"v3_credentials": ["API_INTRINIO_KEY"],
|
||||
"link": "https://intrinio.com/",
|
||||
"instructions": "Go to: https://intrinio.com/starter-plan\n\n\n\nAn API key will be issued with a subscription. Find the token value within the account dashboard."
|
||||
},
|
||||
{
|
||||
"name": "Polygon",
|
||||
"credentials": ["polygon_api_key"],
|
||||
"v3_credentials": ["API_POLYGON_KEY"],
|
||||
"link": "https://polygon.io",
|
||||
"instructions": "Go to: https://polygon.io\n\n\n\nClick on, \"Get your Free API Key\".\n\n\n\nAfter signing up, the API Key is found at the bottom of the account dashboard page.\n\n"
|
||||
},
|
||||
{
|
||||
"name": "Nasdaq",
|
||||
"credentials": ["nasdaq_api_key"],
|
||||
"v3_credentials": ["API_KEY_QUANDL"],
|
||||
"link": "https://www.quandl.com/tools/api",
|
||||
"instructions": "Go to: https://www.quandl.com\n\n\n\nClick on, \"Sign Up\", and register a new account.\n\n\n\nFollow the sign-up instructions, and upon completion the API key will be assigned.\n\n"
|
||||
},
|
||||
{
|
||||
"name": "Tradier",
|
||||
"credentials": ["tradier_api_key"],
|
||||
"v3_credentials": ["API_TRADIER_TOKEN"],
|
||||
"link": "https://tradier.com/products/market-data-api",
|
||||
"instructions": "Go to: https://documentation.tradier.com\n\n\n\nClick on, \"Open Account\", to start the sign-up process. After the account has been setup, navigate to [Tradier Broker Dash](https://dash.tradier.com/login?redirect=settings.api) and create the application. Request a sandbox access token."
|
||||
}
|
||||
]
|
||||
@@ -1,41 +0,0 @@
|
||||
"""Model for API keys for various providers."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class FeaturesKeys(BaseModel):
|
||||
"""API keys for various providers."""
|
||||
|
||||
API_BITQUERY_KEY: Optional[str] = Field(default=None)
|
||||
API_BIZTOC_TOKEN: Optional[str] = Field(default=None)
|
||||
API_CMC_KEY: Optional[str] = Field(default=None)
|
||||
API_COINGLASS_KEY: Optional[str] = Field(default=None)
|
||||
API_CRYPTO_PANIC_KEY: Optional[str] = Field(default=None)
|
||||
API_DAPPRADAR_KEY: Optional[str] = Field(default=None)
|
||||
API_DATABENTO_KEY: Optional[str] = Field(default=None)
|
||||
API_EODHD_KEY: Optional[str] = Field(default=None)
|
||||
API_ETHPLORER_KEY: Optional[str] = Field(default=None)
|
||||
API_FINNHUB_KEY: Optional[str] = Field(default=None)
|
||||
API_FRED_KEY: Optional[str] = Field(default=None)
|
||||
API_GITHUB_KEY: Optional[str] = Field(default=None)
|
||||
API_GLASSNODE_KEY: Optional[str] = Field(default=None)
|
||||
API_INTRINIO_KEY: Optional[str] = Field(default=None)
|
||||
API_KEY_ALPHAVANTAGE: Optional[str] = Field(default=None)
|
||||
API_KEY_FINANCIALMODELINGPREP: Optional[str] = Field(default=None)
|
||||
API_KEY_QUANDL: Optional[str] = Field(default=None)
|
||||
API_MESSARI_KEY: Optional[str] = Field(default=None)
|
||||
API_NEWS_TOKEN: Optional[str] = Field(default=None)
|
||||
API_POLYGON_KEY: Optional[str] = Field(default=None)
|
||||
API_REDDIT_CLIENT_ID: Optional[str] = Field(default=None)
|
||||
API_REDDIT_CLIENT_SECRET: Optional[str] = Field(default=None)
|
||||
API_REDDIT_PASSWORD: Optional[str] = Field(default=None)
|
||||
API_REDDIT_USERNAME: Optional[str] = Field(default=None)
|
||||
API_REDDIT_USER_AGENT: Optional[str] = Field(default=None)
|
||||
API_SANTIMENT_KEY: Optional[str] = Field(default=None)
|
||||
API_SHROOM_KEY: Optional[str] = Field(default=None)
|
||||
API_SMARTSTAKE_KEY: Optional[str] = Field(default=None)
|
||||
API_SMARTSTAKE_TOKEN: Optional[str] = Field(default=None)
|
||||
API_TOKEN_TERMINAL_KEY: Optional[str] = Field(default=None)
|
||||
API_WHALE_ALERT_KEY: Optional[str] = Field(default=None)
|
||||
@@ -1,16 +1,15 @@
|
||||
"""Hub user settings model."""
|
||||
|
||||
# from typing import Dict, List, Union
|
||||
from typing import Dict, Optional
|
||||
|
||||
from openbb_core.app.model.hub.features_keys import FeaturesKeys
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class HubUserSettings(BaseModel):
|
||||
"""User settings for the Hub."""
|
||||
"""Hub user settings model."""
|
||||
|
||||
# features_settings: Dict[str, str]
|
||||
features_keys: FeaturesKeys = Field(default_factory=FeaturesKeys)
|
||||
features_keys: Dict[str, Optional[str]] = Field(default_factory=dict)
|
||||
# features_sources: Dict[str, List[str]]
|
||||
# features_terminal_style: Dict[str, Union[str, Dict[str, str]]]
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Hub manager class."""
|
||||
|
||||
from typing import Optional
|
||||
from warnings import warn
|
||||
|
||||
from fastapi import HTTPException
|
||||
from jose import JWTError
|
||||
@@ -8,13 +9,11 @@ from jose.exceptions import ExpiredSignatureError
|
||||
from jose.jwt import decode, get_unverified_header
|
||||
from openbb_core.app.model.abstract.error import OpenBBError
|
||||
from openbb_core.app.model.credentials import Credentials
|
||||
from openbb_core.app.model.hub.features_keys import FeaturesKeys
|
||||
from openbb_core.app.model.hub.hub_session import HubSession
|
||||
from openbb_core.app.model.hub.hub_user_settings import HubUserSettings
|
||||
from openbb_core.app.model.profile import Profile
|
||||
from openbb_core.app.model.user_settings import UserSettings
|
||||
from openbb_core.env import Env
|
||||
from pydantic import SecretStr
|
||||
from requests import get, post, put
|
||||
|
||||
|
||||
@@ -22,6 +21,18 @@ class HubService:
|
||||
"""Hub service class."""
|
||||
|
||||
TIMEOUT = 10
|
||||
# Mapping of V3 keys to V4 keys for backward compatibility
|
||||
V3TOV4 = {
|
||||
"API_KEY_ALPHAVANTAGE": "alpha_vantage_api_key",
|
||||
"API_BIZTOC_TOKEN": "biztoc_api_key",
|
||||
"API_FRED_KEY": "fred_api_key",
|
||||
"API_KEY_FINANCIALMODELINGPREP": "fmp_api_key",
|
||||
"API_INTRINIO_KEY": "intrinio_api_key",
|
||||
"API_POLYGON_KEY": "polygon_api_key",
|
||||
"API_KEY_QUANDL": "nasdaq_api_key",
|
||||
"API_TRADIER_TOKEN": "tradier_api_key",
|
||||
}
|
||||
V4TOV3 = {v: k for k, v in V3TOV4.items()}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -31,6 +42,7 @@ class HubService:
|
||||
"""Initialize Hub service."""
|
||||
self._base_url = base_url or Env().HUB_BACKEND
|
||||
self._session = session
|
||||
self._hub_user_settings: Optional[HubUserSettings] = None
|
||||
|
||||
@property
|
||||
def base_url(self) -> str:
|
||||
@@ -81,13 +93,10 @@ class HubService:
|
||||
def pull(self) -> UserSettings:
|
||||
"""Pull user settings from Hub."""
|
||||
if self._session:
|
||||
hub_user_settings = self._get_user_settings(self._session)
|
||||
if hub_user_settings:
|
||||
profile = Profile(
|
||||
hub_session=self._session,
|
||||
)
|
||||
credentials = self.hub2platform(hub_user_settings)
|
||||
return UserSettings(profile=profile, credentials=credentials)
|
||||
self._hub_user_settings = self._get_user_settings(self._session)
|
||||
profile = Profile(hub_session=self._session)
|
||||
credentials = self.hub2platform(self._hub_user_settings)
|
||||
return UserSettings(profile=profile, credentials=credentials)
|
||||
raise OpenBBError(
|
||||
"No session found. Login or provide a 'HubSession' on initialization."
|
||||
)
|
||||
@@ -216,42 +225,38 @@ class HubService:
|
||||
detail = response.json().get("detail", None)
|
||||
raise HTTPException(status_code, detail)
|
||||
|
||||
@classmethod
|
||||
def hub2platform(cls, settings: HubUserSettings) -> Credentials:
|
||||
def hub2platform(self, settings: HubUserSettings) -> Credentials:
|
||||
"""Convert Hub user settings to Platform models."""
|
||||
# TODO: Hub is getting credentials from `all_api_keys.json`, which uses
|
||||
# the terminal names conventions. We need to update it to use a file that
|
||||
# lives here in the platform and maps the credential names between the two.
|
||||
credentials = Credentials(
|
||||
alpha_vantage_api_key=settings.features_keys.API_KEY_ALPHAVANTAGE,
|
||||
biztoc_api_key=settings.features_keys.API_BIZTOC_TOKEN,
|
||||
fred_api_key=settings.features_keys.API_FRED_KEY,
|
||||
fmp_api_key=settings.features_keys.API_KEY_FINANCIALMODELINGPREP,
|
||||
intrinio_api_key=settings.features_keys.API_INTRINIO_KEY,
|
||||
polygon_api_key=settings.features_keys.API_POLYGON_KEY,
|
||||
nasdaq_api_key=settings.features_keys.API_KEY_QUANDL,
|
||||
)
|
||||
return credentials
|
||||
if any(k in settings.features_keys for k in self.V3TOV4):
|
||||
deprecated = {
|
||||
k: v for k, v in self.V3TOV4.items() if k in settings.features_keys
|
||||
}
|
||||
msg = ""
|
||||
for k, v in deprecated.items():
|
||||
msg += f"\n'{k}' -> '{v}', "
|
||||
msg = msg.strip(", ")
|
||||
warn(
|
||||
message=f"\nDeprecated v3 credentials found.\n{msg}"
|
||||
"\n\nYou can update them at https://my.openbb.co/app/platform/credentials.",
|
||||
)
|
||||
# We give priority to v4 keys over v3 keys if both are present
|
||||
hub_credentials = {
|
||||
self.V3TOV4.get(k, k): settings.features_keys.get(self.V3TOV4.get(k, k), v)
|
||||
for k, v in settings.features_keys.items()
|
||||
}
|
||||
return Credentials(**hub_credentials)
|
||||
|
||||
@classmethod
|
||||
def platform2hub(cls, credentials: Credentials) -> HubUserSettings:
|
||||
def platform2hub(self, credentials: Credentials) -> HubUserSettings:
|
||||
"""Convert Platform models to Hub user settings."""
|
||||
|
||||
def get_cred(cred: str) -> Optional[str]:
|
||||
secret_str: Optional[SecretStr] = getattr(credentials, cred, None)
|
||||
return secret_str.get_secret_value() if secret_str else None
|
||||
|
||||
features_keys = FeaturesKeys(
|
||||
API_BIZTOC_TOKEN=get_cred("biztoc_api_key"),
|
||||
API_FRED_KEY=get_cred("fred_api_key"),
|
||||
API_INTRINIO_KEY=get_cred("intrinio_api_key"),
|
||||
API_KEY_ALPHAVANTAGE=get_cred("alpha_vantage_api_key"),
|
||||
API_KEY_FINANCIALMODELINGPREP=get_cred("fmp_api_key"),
|
||||
API_POLYGON_KEY=get_cred("polygon_api_key"),
|
||||
API_KEY_QUANDL=get_cred("nasdaq_api_key"),
|
||||
)
|
||||
hub_user_settings = HubUserSettings(features_keys=features_keys)
|
||||
return hub_user_settings
|
||||
# Dump mode json ensures SecretStr values are serialized as strings
|
||||
credentials = credentials.model_dump(mode="json", exclude_none=True)
|
||||
settings = self._hub_user_settings or HubUserSettings()
|
||||
for v4_k, v in sorted(credentials.items()):
|
||||
v3_k = self.V4TOV3.get(v4_k, None)
|
||||
# If v3 key was there, we keep it
|
||||
k = v3_k if v3_k in settings.features_keys else v4_k
|
||||
settings.features_keys[k] = v
|
||||
return settings
|
||||
|
||||
@staticmethod
|
||||
def check_token_expiration(token: str) -> None:
|
||||
|
||||
@@ -34,6 +34,7 @@ class Account:
|
||||
self._openbb_directory = (
|
||||
base_app._command_runner.system_settings.openbb_directory
|
||||
)
|
||||
self._hub_service: Optional[HubService] = None
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""Human readable representation of the object."""
|
||||
@@ -120,18 +121,20 @@ class Account:
|
||||
Optional[UserSettings]
|
||||
User settings: profile, credentials, preferences
|
||||
"""
|
||||
hs = self._create_hub_service(email, password, pat)
|
||||
incoming = hs.pull()
|
||||
self._hub_service = self._create_hub_service(email, password, pat)
|
||||
incoming = self._hub_service.pull()
|
||||
updated: UserSettings = UserService.update_default(incoming)
|
||||
self._base_app._command_runner.user_settings = updated
|
||||
if remember_me:
|
||||
Path(self._openbb_directory).mkdir(parents=False, exist_ok=True)
|
||||
session_file = Path(self._openbb_directory, self.SESSION_FILE)
|
||||
with open(session_file, "w") as f:
|
||||
if not hs.session:
|
||||
if not self._hub_service.session:
|
||||
raise OpenBBError("Not connected to hub.")
|
||||
|
||||
json.dump(hs.session.model_dump(mode="json"), f, indent=4)
|
||||
json.dump(
|
||||
self._hub_service.session.model_dump(mode="json"), f, indent=4
|
||||
)
|
||||
|
||||
if return_settings:
|
||||
return self._base_app._command_runner.user_settings
|
||||
@@ -151,14 +154,12 @@ class Account:
|
||||
Optional[UserSettings]
|
||||
User settings: profile, credentials, preferences
|
||||
"""
|
||||
hub_session = self._base_app._command_runner.user_settings.profile.hub_session
|
||||
if not hub_session:
|
||||
if not self._hub_service:
|
||||
UserService.write_default_user_settings(
|
||||
self._base_app._command_runner.user_settings
|
||||
)
|
||||
else:
|
||||
hs = HubService(hub_session)
|
||||
hs.push(self._base_app._command_runner.user_settings)
|
||||
self._hub_service.push(self._base_app._command_runner.user_settings)
|
||||
|
||||
if return_settings:
|
||||
return self._base_app._command_runner.user_settings
|
||||
@@ -178,14 +179,12 @@ class Account:
|
||||
Optional[UserSettings]
|
||||
User settings: profile, credentials, preferences
|
||||
"""
|
||||
hub_session = self._base_app._command_runner.user_settings.profile.hub_session
|
||||
if not hub_session:
|
||||
if not self._hub_service:
|
||||
self._base_app._command_runner.user_settings = (
|
||||
UserService.read_default_user_settings()
|
||||
)
|
||||
else:
|
||||
hs = HubService(hub_session)
|
||||
incoming = hs.pull()
|
||||
incoming = self._hub_service.pull()
|
||||
updated: UserSettings = UserService.update_default(incoming)
|
||||
updated.id = self._base_app._command_runner.user_settings.id
|
||||
self._base_app._command_runner.user_settings = updated
|
||||
@@ -208,12 +207,10 @@ class Account:
|
||||
Optional[UserSettings]
|
||||
User settings: profile, credentials, preferences
|
||||
"""
|
||||
hub_session = self._base_app._command_runner.user_settings.profile.hub_session
|
||||
if not hub_session:
|
||||
if not self._hub_service:
|
||||
raise OpenBBError("Not connected to hub.")
|
||||
|
||||
hs = HubService(hub_session)
|
||||
hs.disconnect()
|
||||
self._hub_service.disconnect()
|
||||
|
||||
session_file = Path(self._openbb_directory, self.SESSION_FILE)
|
||||
if session_file.exists():
|
||||
|
||||
@@ -62,10 +62,7 @@ class BaseApp:
|
||||
def create_app(extensions: Optional[E] = None) -> Type[BaseApp]:
|
||||
"""Create the app."""
|
||||
|
||||
class EmptyClass:
|
||||
pass
|
||||
|
||||
class App(BaseApp, extensions or EmptyClass): # type: ignore
|
||||
class App(BaseApp, extensions or object): # type: ignore[misc]
|
||||
def __repr__(self) -> str:
|
||||
# pylint: disable=E1101
|
||||
ext_doc = extensions.__doc__ if extensions else ""
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
"""Test the FeaturesKeys class."""
|
||||
|
||||
from openbb_core.app.model.hub.features_keys import FeaturesKeys
|
||||
|
||||
# ruff: noqa: S105 S106
|
||||
|
||||
|
||||
def test_features_keys():
|
||||
"""Test the FeaturesKeys class."""
|
||||
fk = FeaturesKeys(API_BITQUERY_KEY="test", API_BIZTOC_TOKEN="test2")
|
||||
|
||||
assert fk.API_BITQUERY_KEY == "test"
|
||||
assert fk.API_BIZTOC_TOKEN == "test2"
|
||||
@@ -4,10 +4,10 @@
|
||||
# ruff: noqa: S105 S106
|
||||
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
from openbb_core.app.model.hub.features_keys import FeaturesKeys
|
||||
from openbb_core.app.service.hub_service import (
|
||||
Credentials,
|
||||
HubService,
|
||||
@@ -25,6 +25,66 @@ def mocker():
|
||||
yield mock
|
||||
|
||||
|
||||
def test_v3tov4_map():
|
||||
"""Test v3 to v4 map."""
|
||||
|
||||
v3_keys = {
|
||||
"databento": "API_DATABENTO_KEY",
|
||||
"alpha_vantage": "API_KEY_ALPHAVANTAGE",
|
||||
"fmp": "API_KEY_FINANCIALMODELINGPREP",
|
||||
"nasdaq": "API_KEY_QUANDL",
|
||||
"polygon": "API_POLYGON_KEY",
|
||||
"fred": "API_FRED_KEY",
|
||||
"news_api": "API_NEWS_TOKEN",
|
||||
"biztoc": "API_BIZTOC_TOKEN",
|
||||
"cmc": "API_CMC_KEY",
|
||||
"finnhub": "API_FINNHUB_KEY",
|
||||
"whale_alert": "API_WHALE_ALERT_KEY",
|
||||
"glassnode": "API_GLASSNODE_KEY",
|
||||
"coinglass": "API_COINGLASS_KEY",
|
||||
"ethplorer": "API_ETHPLORER_KEY",
|
||||
"cryptopanic": "API_CRYPTO_PANIC_KEY",
|
||||
"crypto_panic": "API_CRYPTO_PANIC_KEY", # If dev choses to use this name
|
||||
"bitquery": "API_BITQUERY_KEY",
|
||||
"smartstake": ["API_SMARTSTAKE_KEY", "API_SMARTSTAKE_TOKEN"],
|
||||
"messari": "API_MESSARI_KEY",
|
||||
"shroom": "API_SHROOM_KEY",
|
||||
"santiment": "API_SANTIMENT_KEY",
|
||||
"eodhd": "API_EODHD_KEY",
|
||||
"tokenterminal": "API_TOKEN_TERMINAL_KEY",
|
||||
"token_terminal": "API_TOKEN_TERMINAL_KEY", # If dev choses to use this name
|
||||
"intrinio": "API_INTRINIO_KEY",
|
||||
"github": "API_GITHUB_KEY",
|
||||
"reddit": [
|
||||
"API_REDDIT_CLIENT_ID",
|
||||
"API_REDDIT_CLIENT_SECRET",
|
||||
"API_REDDIT_USERNAME",
|
||||
"API_REDDIT_USER_AGENT",
|
||||
"API_REDDIT_PASSWORD",
|
||||
],
|
||||
"companies_house": "API_COMPANIESHOUSE_KEY",
|
||||
"companieshouse": "API_COMPANIESHOUSE_KEY", # If dev choses to use this name
|
||||
"dappradar": "API_DAPPRADAR_KEY",
|
||||
"nixtla": "API_KEY_NIXTLA",
|
||||
}
|
||||
|
||||
providers = sorted(
|
||||
[
|
||||
p.stem
|
||||
for p in Path("openbb_platform", "providers").glob("*")
|
||||
if p.is_dir() and p.name not in ("__pycache__", "tests")
|
||||
]
|
||||
)
|
||||
|
||||
for provider in providers:
|
||||
if provider in v3_keys:
|
||||
keys = v3_keys[provider]
|
||||
if not isinstance(keys, list):
|
||||
keys = [keys]
|
||||
for k in keys:
|
||||
assert k in HubService.V3TOV4
|
||||
|
||||
|
||||
def test_connect_with_email_password():
|
||||
"""Test connect with email and password."""
|
||||
mock_hub_session = MagicMock(spec=HubSession)
|
||||
@@ -173,31 +233,78 @@ def test_put_user_settings():
|
||||
)
|
||||
|
||||
|
||||
def test_hub2platform():
|
||||
def test_hub2platform_v4_only():
|
||||
"""Test hub2platform."""
|
||||
mock_user_settings = MagicMock(spec=HubUserSettings)
|
||||
mock_user_settings.features_keys = FeaturesKeys(
|
||||
API_KEY_FINANCIALMODELINGPREP="fmp",
|
||||
API_POLYGON_KEY="polygon",
|
||||
API_FRED_KEY="fred",
|
||||
)
|
||||
mock_user_settings.features_keys = {
|
||||
"fmp_api_key": "abc",
|
||||
"polygon_api_key": "def",
|
||||
"fred_api_key": "ghi",
|
||||
}
|
||||
|
||||
credentials = HubService.hub2platform(mock_user_settings)
|
||||
credentials = HubService().hub2platform(mock_user_settings)
|
||||
assert isinstance(credentials, Credentials)
|
||||
assert credentials.fmp_api_key.get_secret_value() == "fmp"
|
||||
assert credentials.polygon_api_key.get_secret_value() == "polygon"
|
||||
assert credentials.fred_api_key.get_secret_value() == "fred"
|
||||
assert credentials.fmp_api_key.get_secret_value() == "abc"
|
||||
assert credentials.polygon_api_key.get_secret_value() == "def"
|
||||
assert credentials.fred_api_key.get_secret_value() == "ghi"
|
||||
|
||||
|
||||
def test_hub2platform_v3_only():
|
||||
"""Test hub2platform."""
|
||||
mock_user_settings = MagicMock(spec=HubUserSettings)
|
||||
mock_user_settings.features_keys = {
|
||||
"API_KEY_FINANCIALMODELINGPREP": "abc",
|
||||
"API_POLYGON_KEY": "def",
|
||||
"API_FRED_KEY": "ghi",
|
||||
}
|
||||
|
||||
credentials = HubService().hub2platform(mock_user_settings)
|
||||
assert isinstance(credentials, Credentials)
|
||||
assert credentials.fmp_api_key.get_secret_value() == "abc"
|
||||
assert credentials.polygon_api_key.get_secret_value() == "def"
|
||||
assert credentials.fred_api_key.get_secret_value() == "ghi"
|
||||
|
||||
|
||||
def test_hub2platform_v3v4():
|
||||
"""Test hub2platform."""
|
||||
mock_user_settings = MagicMock(spec=HubUserSettings)
|
||||
mock_user_settings.features_keys = {
|
||||
"API_KEY_FINANCIALMODELINGPREP": "abc",
|
||||
"fmp_api_key": "other_key",
|
||||
"API_POLYGON_KEY": "def",
|
||||
"API_FRED_KEY": "ghi",
|
||||
}
|
||||
|
||||
credentials = HubService().hub2platform(mock_user_settings)
|
||||
assert isinstance(credentials, Credentials)
|
||||
assert credentials.fmp_api_key.get_secret_value() == "other_key"
|
||||
assert credentials.polygon_api_key.get_secret_value() == "def"
|
||||
assert credentials.fred_api_key.get_secret_value() == "ghi"
|
||||
|
||||
|
||||
def test_platform2hub():
|
||||
"""Test platform2hub."""
|
||||
mock_credentials = MagicMock(spec=Credentials)
|
||||
mock_credentials.fmp_api_key = SecretStr("fmp")
|
||||
mock_credentials.polygon_api_key = SecretStr("polygon")
|
||||
mock_credentials.fred_api_key = SecretStr("fred")
|
||||
mock_user_settings = MagicMock(spec=HubUserSettings)
|
||||
mock_user_settings.features_keys = { # Received from Hub
|
||||
"API_KEY_FINANCIALMODELINGPREP": "abc",
|
||||
"fmp_api_key": "other_key",
|
||||
"API_FRED_KEY": "ghi",
|
||||
}
|
||||
mock_hub_service = HubService()
|
||||
mock_hub_service._hub_user_settings = mock_user_settings
|
||||
mock_credentials = Credentials( # Current credentials
|
||||
fmp_api_key=SecretStr("fmp"),
|
||||
polygon_api_key=SecretStr("polygon"),
|
||||
fred_api_key=SecretStr("fred"),
|
||||
benzinga_api_key=SecretStr("benzinga"),
|
||||
some_api_key=SecretStr("some"),
|
||||
)
|
||||
user_settings = mock_hub_service.platform2hub(mock_credentials)
|
||||
|
||||
user_settings = HubService.platform2hub(mock_credentials)
|
||||
assert isinstance(user_settings, HubUserSettings)
|
||||
assert user_settings.features_keys.API_KEY_FINANCIALMODELINGPREP == "fmp"
|
||||
assert user_settings.features_keys.API_POLYGON_KEY == "polygon"
|
||||
assert user_settings.features_keys.API_FRED_KEY == "fred"
|
||||
assert user_settings.features_keys["API_KEY_FINANCIALMODELINGPREP"] == "fmp"
|
||||
assert user_settings.features_keys["fmp_api_key"] == "other_key"
|
||||
assert user_settings.features_keys["polygon_api_key"] == "polygon"
|
||||
assert user_settings.features_keys["API_FRED_KEY"] == "fred"
|
||||
assert user_settings.features_keys["benzinga_api_key"] == "benzinga"
|
||||
assert "some_api_key" not in user_settings.features_keys
|
||||
|
||||
Reference in New Issue
Block a user