handle multiple types of data (the fetcher should declare them later)

This commit is contained in:
Diogo Sousa
2023-07-30 17:18:28 +01:00
parent 33755303d1
commit c852dc3d4d
6 changed files with 25 additions and 31 deletions

View File

@@ -1,7 +1,8 @@
from dataclasses import dataclass, make_dataclass
from typing import Any, Dict, List, Literal, Optional, Tuple, Union
from typing import Any, Dict, List, Literal, Optional, Tuple, Type, Union
from fastapi import Query
from openbb_provider.abstract.fetcher import GenericDataType
from openbb_provider.query_executor import QueryExecutor
from openbb_provider.registry_map import MapType, RegistryMap
from pydantic import BaseConfig, BaseModel, Extra, Field, create_model
@@ -55,7 +56,7 @@ class ProviderInterface:
Dictionary of provider choices by model.
params : Dict[str, Dict[str, Union[StandardParams, ExtraParams]]]
Dictionary of params by model.
merged_data : Dict[str, BaseModel]
merged_return : Dict[str, Type[BaseModel]]
Dictionary of data by model.
providers_literal : type
Literal of provider names.
@@ -85,7 +86,7 @@ class ProviderInterface:
)
self._params = self._generate_params_dc(self._registry_map)
self._data = self._generate_data_dc(self._registry_map)
self._merged_data = self._merge_data_dc(self._data)
self._merged_return = self._merged_return_model(self._data)
self._providers_literal = self._get_provider_literal(
self._registry_map.available_providers
)
@@ -117,9 +118,9 @@ class ProviderInterface:
return self._data
@property
def merged_data(self) -> Dict[str, BaseModel]:
def merged_return(self) -> Dict[str, Type[BaseModel]]:
"""Dictionary of data by model merged."""
return self._merged_data
return self._merged_return
@property
def providers_literal(self) -> type:
@@ -399,9 +400,9 @@ class ProviderInterface:
return result
def _merge_data_dc(
def _merged_return_model(
self, data: Dict[str, Dict[str, Union[StandardData, ExtraData]]]
) -> Dict[str, BaseModel]:
) -> Dict[str, Type[BaseModel]]:
"""Merge standard data with extra data into a single BaseModel to benzinga
injected as FastAPI dependency."""
result: Dict = {}
@@ -426,12 +427,17 @@ class ProviderInterface:
class Config(BaseConfig):
extra = Extra.allow
result[model_name] = create_model( # type: ignore
model = create_model( # type: ignore
model_name,
__config__=Config,
**fields_dict, # type: ignore
)
# TODO: Get GenericDataType depending on the model
# The info needs to be in the registry_map
# instead of hardcoding it with Union[..., List[...], Dict[str, ...]]
result[model_name] = GenericDataType[model]
return result
def _get_provider_literal(self, available_providers: List[str]) -> type:

View File

@@ -19,7 +19,6 @@ from typing import (
import pkg_resources
from fastapi import APIRouter, Depends
from openbb_provider.abstract.fetcher import GenericDataType
from pydantic import BaseModel
from pydantic.config import BaseConfig
from pydantic.validators import find_validators
@@ -260,10 +259,9 @@ class SignatureInspector:
callable_=provider_interface.params[model]["extra"],
)
# TODO: Implement the output structure in each endpoint and then just fill
# the genertic with `data_type`
data_type = provider_interface.merged_data[model]
func.__annotations__["return"] = CommandOutput[GenericDataType[data_type]]
ReturnModel = provider_interface.merged_return[model]
func.__annotations__["return"] = CommandOutput[ReturnModel] # type: ignore
elif (
"provider_choices" in func.__annotations__
and func.__annotations__["provider_choices"] == ProviderChoices

View File

@@ -1,7 +1,6 @@
### THIS FILE IS AUTO-GENERATED. DO NOT EDIT. ###
from openbb_core.app.static.container import Container

View File

@@ -77,8 +77,6 @@ class Fetcher(
# pylint: disable=E1101
return self.__orig_bases__[0].__args__[3]
@property
def return_type(self):
"""Get the type of the return."""
# pylint: disable=E1101
return self.transform_data.__annotations__["return"]
# TODO: Create abstract class attribute for generic return type
# @property
# def generic_return_type(self):

View File

@@ -42,9 +42,7 @@ class QueryExecutor:
for c in provider.required_credentials:
credential_value = credentials.get(c)
if c not in credentials or credential_value is None:
raise ProviderError(
f"Missing credential '{c}'."
)
raise ProviderError(f"Missing credential '{c}'.")
def execute(
self,

View File

@@ -57,7 +57,7 @@ class RegistryMap:
f = fetcher()
standard_query, extra_query = self.extract_info(f, "query_params")
standard_data, extra_data = self.extract_info(f, "data")
return_info = self.extract_return_info(f)
return_type = self.extract_return_type(f)
if model_name not in map_:
map_[model_name] = {}
@@ -69,7 +69,7 @@ class RegistryMap:
map_[model_name][p] = {
"QueryParams": extra_query,
"Data": extra_data,
"Return": return_info,
"ReturnType": return_type,
}
return map_
@@ -98,12 +98,7 @@ class RegistryMap:
return standard_info, extra_info
@staticmethod
def extract_return_info(fetcher: Fetcher):
def extract_return_type(fetcher: Fetcher):
"""Extract return info from fetcher."""
data_type = getattr(fetcher, "provider_data_type")
return_type = fetcher.return_type
return (data_type, return_type)
return getattr(fetcher, "generic_return_type", None)