summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbb_platform/core/openbb_core/app/command_runner.py74
-rw-r--r--openbb_platform/core/openbb_core/app/model/credentials.py54
-rw-r--r--openbb_platform/core/openbb_core/app/model/defaults.py35
-rw-r--r--openbb_platform/core/openbb_core/app/provider_interface.py4
-rw-r--r--openbb_platform/core/openbb_core/app/static/container.py63
-rw-r--r--openbb_platform/core/openbb_core/app/static/package_builder.py27
-rw-r--r--openbb_platform/core/openbb_core/app/static/utils/decorators.py13
-rw-r--r--openbb_platform/core/openbb_core/provider/registry_map.py16
-rw-r--r--openbb_platform/core/openbb_core/provider/standard_models/central_bank_holdings.py30
-rw-r--r--openbb_platform/core/tests/app/model/test_defaults.py9
-rw-r--r--openbb_platform/core/tests/app/static/test_container.py100
-rw-r--r--openbb_platform/core/tests/app/test_command_runner.py55
-rw-r--r--openbb_platform/core/tests/app/test_provider_interface.py2
-rw-r--r--openbb_platform/core/tests/provider/test_registry_map.py3
-rw-r--r--openbb_platform/extensions/economy/integration/test_economy_api.py39
-rw-r--r--openbb_platform/extensions/economy/integration/test_economy_python.py38
-rw-r--r--openbb_platform/extensions/economy/openbb_economy/economy_router.py32
-rw-r--r--openbb_platform/obbject_extensions/charting/examples.md4
-rw-r--r--openbb_platform/openbb/assets/reference.json823
-rw-r--r--openbb_platform/openbb/package/crypto.py8
-rw-r--r--openbb_platform/openbb/package/crypto_price.py8
-rw-r--r--openbb_platform/openbb/package/currency.py16
-rw-r--r--openbb_platform/openbb/package/currency_price.py8
-rw-r--r--openbb_platform/openbb/package/derivatives_options.py16
-rw-r--r--openbb_platform/openbb/package/economy.py254
-rw-r--r--openbb_platform/openbb/package/economy_gdp.py24
-rw-r--r--openbb_platform/openbb/package/equity.py32
-rw-r--r--openbb_platform/openbb/package/equity_calendar.py32
-rw-r--r--openbb_platform/openbb/package/equity_compare.py16
-rw-r--r--openbb_platform/openbb/package/equity_discovery.py64
-rw-r--r--openbb_platform/openbb/package/equity_estimates.py64
-rw-r--r--openbb_platform/openbb/package/equity_fundamental.py200
-rw-r--r--openbb_platform/openbb/package/equity_ownership.py40
-rw-r--r--openbb_platform/openbb/package/equity_price.py32
-rw-r--r--openbb_platform/openbb/package/equity_shorts.py8
-rw-r--r--openbb_platform/openbb/package/etf.py72
-rw-r--r--openbb_platform/openbb/package/fixedincome.py8
-rw-r--r--openbb_platform/openbb/package/fixedincome_corporate.py40
-rw-r--r--openbb_platform/openbb/package/fixedincome_government.py24
-rw-r--r--openbb_platform/openbb/package/fixedincome_rate.py64
-rw-r--r--openbb_platform/openbb/package/fixedincome_spreads.py24
-rw-r--r--openbb_platform/openbb/package/index.py24
-rw-r--r--openbb_platform/openbb/package/news.py16
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/__init__.py7
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/models/central_bank_holdings.py303
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/__init__.py0
-rw-r--r--openbb_platform/providers/federal_reserve/openbb_federal_reserve/utils/ny_fed_api.py636
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_central_bank_holdings_fetcher.yaml209
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_fed_fetcher.yaml18
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_money_measures_fetcher.yaml24
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_treasury_rates_fetcher.yaml16
-rw-r--r--openbb_platform/providers/federal_reserve/tests/record/http/test_federal_reserve_fetchers/test_federal_reserve_yield_curve_fetcher.yaml20
-rw-r--r--openbb_platform/providers/federal_reserve/tests/test_federal_reserve_fetchers.py22
-rw-r--r--website/content/cli/data-sources.md13
-rw-r--r--website/content/platform/getting_started/economic_indicators.mdx2
-rw-r--r--website/content/platform/getting_started/quickstart.mdx2
-rw-r--r--website/content/platform/user_guides/settings_and_environment_variables.mdx92
57 files changed, 2745 insertions, 1134 deletions
diff --git a/openbb_platform/core/openbb_core/app/command_runner.py b/openbb_platform/core/openbb_core/app/command_runner.py
index 89433e45156..e3dce19f465 100644
--- a/openbb_platform/core/openbb_core/app/command_runner.py
+++ b/openbb_platform/core/openbb_core/app/command_runner.py
@@ -21,7 +21,7 @@ from openbb_core.app.model.metadata import Metadata
from openbb_core.app.model.obbject import OBBject
from openbb_core.app.model.system_settings import SystemSettings
from openbb_core.app.model.user_settings import UserSettings
-from openbb_core.app.provider_interface import ExtraParams, ProviderInterface
+from openbb_core.app.provider_interface import ExtraParams
from openbb_core.app.router import CommandMap
from openbb_core.app.service.system_service import SystemService
from openbb_core.app.service.user_service import UserService
@@ -118,68 +118,6 @@ class ParametersBuilder:
return kwargs
@staticmethod
- def update_provider_choices(
- func: Callable,
- command_coverage: Dict[str, List[str]],
- route: str,
- kwargs: Dict[str, Any],
- route_default: Optional[Dict[str, Optional[str]]],
- ) -> Dict[str, Any]:
- """Update the provider choices with the available providers and set default provider."""
-
- def _needs_provider(func: Callable) -> bool:
- """Check if the function needs a provider."""
- parameters = signature(func).parameters.keys()
- return "provider_choices" in parameters
-
- def _has_provider(kwargs: Dict[str, Any]) -> bool:
- """Check if the kwargs already have a provider."""
- provider_choices = kwargs.get("provider_choices")
-
- if isinstance(provider_choices, dict): # when in python
- return provider_choices.get("provider", None) is not None
- if isinstance(provider_choices, object): # when running as fastapi
- return getattr(provider_choices, "provider", None) is not None
- return False
-
- def _get_first_provider() -> Optional[str]:
- """Get the first available provider."""
- available_providers = ProviderInterface().available_providers
- return available_providers[0] if available_providers else None
-
- def _get_default_provider(
- command_coverage: Dict[str, List[str]],
- route_default: Optional[Dict[str, Optional[str]]],
- ) -> Optional[str]:
- """
- Get the default provider for the given route.
-
- Either pick it from the user defaults or from the command coverage.
- """
- cmd_cov_given_route = command_coverage.get(route)
- command_cov_provider = (
- cmd_cov_given_route[0] if cmd_cov_given_route else None
- )
-
- if route_default:
- return route_default.get("provider", None) or command_cov_provider # type: ignore
-
- return command_cov_provider
-
- if not _has_provider(kwargs) and _needs_provider(func):
- provider = (
- _get_default_provider(
- command_coverage,
- route_default,
- )
- if route in command_coverage
- else _get_first_provider()
- )
- kwargs["provider_choices"] = {"provider": provider}
-
- return kwargs
-
- @staticmethod
def _warn_kwargs(
extra_params: Dict[str, Any],
model: Type[BaseModel],
@@ -246,14 +184,12 @@ class ParametersBuilder:
args: Tuple[Any, ...],
execution_context: ExecutionContext,
func: Callable,
- route: str,
kwargs: Dict[str, Any],
) -> Dict[str, Any]:
"""Build the parameters for a function."""
func = cls.get_polished_func(func=func)
system_settings = execution_context.system_settings
user_settings = execution_context.user_settings
- command_map = execution_context.command_map
kwargs = cls.merge_args_and_kwargs(
func=func,
@@ -266,13 +202,6 @@ class ParametersBuilder:
system_settings=system_settings,
user_settings=user_settings,
)
- kwargs = cls.update_provider_choices(
- func=func,
- command_coverage=command_map.command_coverage,
- route=route,
- kwargs=kwargs,
- route_default=user_settings.defaults.routes.get(route, None),
- )
kwargs = cls.validate_kwargs(
func=func,
kwargs=kwargs,
@@ -364,7 +293,6 @@ class StaticCommandRunner:
args=args,
execution_context=execution_context,
func=func,
- route=route,
kwargs=kwargs,
)
diff --git a/openbb_platform/core/openbb_core/app/model/credentials.py b/openbb_platform/core/openbb_core/app/model/credentials.py
index 8979db5957a..f54198e9495 100644
--- a/openbb_platform/core/openbb_core/app/model/credentials.py
+++ b/openbb_platform/core/openbb_core/app/model/credentials.py
@@ -2,7 +2,7 @@
import traceback
import warnings
-from typing import Dict, Optional, Set, Tuple
+from typing import Dict, List, Optional, Tuple
from pydantic import (
BaseModel,
@@ -36,37 +36,39 @@ OBBSecretStr = Annotated[
class CredentialsLoader:
"""Here we create the Credentials model."""
- credentials: Dict[str, Set[str]] = {}
+ credentials: Dict[str, List[str]] = {}
- @staticmethod
- def prepare(
- credentials: Dict[str, Set[str]],
- ) -> Dict[str, Tuple[object, None]]:
+ def format_credentials(self) -> Dict[str, Tuple[object, None]]:
"""Prepare credentials map to be used in the Credentials model."""
formatted: Dict[str, Tuple[object, None]] = {}
- for origin, creds in credentials.items():
- for c in creds:
- # Not sure we should do this, if you require the same credential it breaks
- # if c in formatted:
- # raise ValueError(f"Credential '{c}' already in use.")
- formatted[c] = (
+ for c_origin, c_list in self.credentials.items():
+ for c_name in c_list:
+ if c_name in formatted:
+ warnings.warn(
+ message=f"Skipping '{c_name}', credential already in use.",
+ category=OpenBBWarning,
+ )
+ continue
+ formatted[c_name] = (
Optional[OBBSecretStr],
- Field(
- default=None, description=origin, alias=c.upper()
- ), # register the credential origin (obbject, providers)
+ Field(default=None, description=c_origin, alias=c_name.upper()),
)
- return formatted
+ return dict(sorted(formatted.items()))
def from_obbject(self) -> None:
"""Load credentials from OBBject extensions."""
- self.credentials["obbject"] = set()
- for name, entry in ExtensionLoader().obbject_objects.items(): # type: ignore[attr-defined]
+ for ext_name, ext in ExtensionLoader().obbject_objects.items(): # type: ignore[attr-defined]
try:
- for c in entry.credentials:
- self.credentials["obbject"].add(c)
+ if ext_name in self.credentials:
+ warnings.warn(
+ message=f"Skipping '{ext_name}', name already in user.",
+ category=OpenBBWarning,
+ )
+ continue
+ self.credentials[ext_name] = ext.credentials
except Exception as e:
- msg = f"Error loading extension: {name}\n"
+ msg = f"Error loading extension: {ext_name}\n"
if Env().DEBUG_MODE:
traceback.print_exception(type(e), e, e.__traceback__)
raise LoadingError(msg + f"\033[91m{e}\033[0m") from e
@@ -77,20 +79,20 @@ class CredentialsLoader:
def from_providers(self) -> None:
"""Load credentials from providers."""
- self.credentials["providers"] = set()
- for c in ProviderInterface().credentials:
- self.credentials["providers"].add(c)
+ self.credentials = ProviderInterface().credentials
def load(self) -> BaseModel:
"""Load credentials from providers."""
# We load providers first to give them priority choosing credential names
self.from_providers()
self.from_obbject()
- return create_model( # type: ignore
+ model = create_model( # type: ignore
"Credentials",
__config__=ConfigDict(validate_assignment=True, populate_by_name=True),
- **self.prepare(self.credentials),
+ **self.format_credentials(),
)
+ model.origins = self.credentials
+ return model
_Credentials = CredentialsLoader().load()
diff --git a/openbb_platform/core/openbb_core/app/model/defaults.py b/openbb_platform/core/openbb_core/app/model/defaults.py
index 52007edf5de..1f4a176674f 100644
--- a/openbb_platform/core/openbb_core/app/model/defaults.py
+++ b/openbb_platform/core/openbb_core/app/model/defaults.py
@@ -1,19 +1,46 @@
"""Defaults model."""
-from typing import Dict, Optional
+from typing import Dict, List, Optional
+from warnings import warn
-from pydantic import BaseModel, ConfigDict, Field
+from pydantic import BaseModel, ConfigDict, Field, model_validator
+
+from openbb_core.app.model.abstract.warning import OpenBBWarning
class Defaults(BaseModel):
"""Defaults."""
- model_config = ConfigDict(validate_assignment=True)
+ model_config = ConfigDict(validate_assignment=True, populate_by_name=True)
- routes: Dict[str, Dict[str, Optional[str]]] = Field(default_factory=dict)
+ commands: Dict[str, Dict[str, Optional[List[str]]]] = Field(
+ default_factory=dict,
+ alias="routes",
+ )
def __repr__(self) -> str:
"""Return string representation."""
return f"{self.__class__.__name__}\n\n" + "\n".join(
f"{k}: {v}" for k, v in self.model_dump().items()
)
+
+ @model_validator(mode="before")
+ @classmethod
+ def validate_before(cls, values: dict) -> dict:
+ """Validate model (before)."""
+ key = "commands"
+ if "routes" in values:
+ warn(
+ message="'routes' is deprecated. Use 'commands' instead.",
+ category=OpenBBWarning,
+ )
+ key = "routes"
+
+ new_values: Dict[str, Dict[str, Optional[List[str]]]] = {"commands": {}}
+ for k, v in values.get(key, {}).items():
+ clean_k = k.strip("/").replace("/", ".")
+ provider = v.get("provider") if v else None
+ if isinstance(provider, str):
+ v["provider"] = [provider]
+ new_values["commands"][clean_k] = v
+ return new_values
diff --git a/openbb_platform/core/openbb_core/app/provider_interface.py b/openbb_platform/core/openbb_core/app/provider_interface.py
index 11bb21d5f77..014b7c255d7 100644
--- a/openbb_platform/core/openbb_core/app/provider_interface.py
+++ b/openbb_platform/core/openbb_core/app/provider_interface.py
@@ -126,8 +126,8 @@ class ProviderInterface(metaclass=SingletonMeta):
return self._map
@property
- def credentials(self) -> List[str]:
- """Dictionary of required credentials by provider."""
+ def credentials(self) -> Dict[str, List[str]]:
+ """Map providers to credentials."""
return self._registry_map.credentials
@property
diff --git a/openbb_platform/core/openbb_core/app/static/container.py b/openbb_platform/core/openbb_core/app/static/container.py
index 60fc1def9bb..bcabe6507a2 100644
--- a/openbb_platform/core/openbb_core/app/static/container.py
+++ b/openbb_platform/core/openbb_core/app/static/container.py
@@ -24,18 +24,59 @@ class Container:
return obbject
return getattr(obbject, "to_" + output_type)()
+ def _check_credentials(self, provider: str) -> Optional[bool]:
+ """Check required credentials are populated."""
+ credentials = self._command_runner.user_settings.credentials
+ if provider not in credentials.origins:
+ return None
+ required = credentials.origins.get(provider)
+ return all(getattr(credentials, r, None) for r in required)
+
def _get_provider(
- self, choice: Optional[str], cmd: str, available: Tuple[str, ...]
+ self, choice: Optional[str], command: str, default_priority: Tuple[str, ...]
) -> str:
- """Get the provider to use in execution."""
+ """Get the provider to use in execution.
+
+ If no choice is specified, the configured priority list is used. A provider is used
+ when all of its required credentials are populated.
+
+ Parameters
+ ----------
+ choice: Optional[str]
+ The provider choice, for example 'fmp'.
+ command: str
+ The command to get the provider for, for example 'equity.price.historical'
+ default_priority: Tuple[str, ...]
+ A tuple of available providers for the given command to use as default priority list.
+
+ Returns
+ -------
+ str
+ The provider to use in the command.
+
+ Raises
+ ------
+ OpenBBError
+ Raises error when all the providers in the priority list failed.
+ """
if choice is None:
- if config_default := self._command_runner.user_settings.defaults.routes.get(
- cmd, {}
- ).get("provider"):
- if config_default in available:
- return config_default
- raise OpenBBError(
- f"provider '{config_default}' is not available. Choose from