[Feature] Allow Arbitrary Credentials From user_settings.json To Populate Credentials Model (#7040)

* allow arbitrary credentials to be created from user_settings.json

* test_hub_service
This commit is contained in:
Danglewood
2025-02-21 22:56:07 -08:00
committed by GitHub
parent 3662037298
commit ca3a33827d
2 changed files with 26 additions and 3 deletions

View File

@@ -1,9 +1,12 @@
"""Credentials model and its utilities."""
import json
import traceback
import warnings
from pathlib import Path
from typing import Dict, List, Optional, Tuple
from openbb_core.app.constants import USER_SETTINGS_PATH
from openbb_core.app.extension_loader import ExtensionLoader
from openbb_core.app.model.abstract.warning import OpenBBWarning
from openbb_core.app.provider_interface import ProviderInterface
@@ -37,7 +40,7 @@ class CredentialsLoader:
credentials: Dict[str, List[str]] = {}
def format_credentials(self) -> Dict[str, Tuple[object, None]]:
def format_credentials(self, additional: dict) -> Dict[str, Tuple[object, None]]:
"""Prepare credentials map to be used in the Credentials model."""
formatted: Dict[str, Tuple[object, None]] = {}
for c_origin, c_list in self.credentials.items():
@@ -53,6 +56,15 @@ class CredentialsLoader:
Field(default=None, description=c_origin, alias=c_name.upper()),
)
if additional:
for key, value in additional.items():
if key in formatted:
continue
formatted[key] = (
Optional[OBBSecretStr],
Field(default=value, description=key, alias=key.upper()),
)
return dict(sorted(formatted.items()))
def from_obbject(self) -> None:
@@ -85,10 +97,19 @@ class CredentialsLoader:
# We load providers first to give them priority choosing credential names
self.from_providers()
self.from_obbject()
path = Path(USER_SETTINGS_PATH)
additional: dict = {}
if path.exists():
with open(USER_SETTINGS_PATH, encoding="utf-8") as f:
data = json.load(f)
if "credentials" in data:
additional = data["credentials"]
model = create_model(
"Credentials",
__config__=ConfigDict(validate_assignment=True, populate_by_name=True),
**self.format_credentials(), # type: ignore
**self.format_credentials(additional), # type: ignore
)
model.origins = self.credentials
return model
@@ -100,6 +121,8 @@ _Credentials = CredentialsLoader().load()
class Credentials(_Credentials): # type: ignore
"""Credentials model used to store provider credentials."""
model_config = ConfigDict(extra="allow")
def __repr__(self) -> str:
"""Define the string representation of the credentials."""
return (

View File

@@ -334,7 +334,7 @@ def test_platform2hub():
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
assert "some_api_key" in user_settings.features_keys
assert "defaults" in user_settings.features_settings