Source code for scholar_flux.api.models.base_parameters

# /api/models/base_parameters.py
"""The scholar_flux.api.models.base_parameters module implements BaseAPIParameterMap and APISpecificParameter classes.

These classes define the core and API-specific fields required to interact with and create requests to API providers.

Classes:
    BaseAPIParameterMap: Defines parameters for interacting with a provider's API specification.
    APISpecificParameters: Defines optional and required parameters specific to an API provider.

"""
from __future__ import annotations
from typing import Optional, Dict, Any, Callable
from pydantic import BaseModel, Field
from pydantic.dataclasses import dataclass
from scholar_flux.utils.repr_utils import generate_repr, generate_repr_from_string
import logging

logger = logging.getLogger(__name__)


[docs] @dataclass class APISpecificParameter: """Dataclass that defines the specification of an API-specific parameter for an API provider. Implements optionally specifiable defaults, validation steps, and indicators for optional vs. required fields. Args: name (str): The name of the parameter used when sending requests to APis. description (str): A description of the API-specific parameter. validator (Optional[Callable[[Any], Any]]): An optional function/method for verifying and pre-processing parameter input based on required types, constrained values, etc. default (Any): An default value used for the parameter if not specified by the user required (bool): Indicates whether the current parameter is required for API calls. """ name: str description: str validator: Optional[Callable[[Any], Any]] = None default: Any = None required: bool = False @property def validator_name(self): """Helper method for generating a human readable string from the validator function, if used.""" if self.validator is None: return "None" name = getattr(self.validator, "__name__", "unnamed") validator_type = type(self.validator).__name__ return f"{name} ({validator_type})"
[docs] def structure(self, flatten: bool = False, show_value_attributes: bool = True) -> str: """Helper method for showing the structure of the current APISpecificParameter.""" class_name = self.__class__.__name__ # the representation will include all attributes in the current dataclass attribute_dict = dict( name=self.name, description=self.description, # validator manually added. otherwise, functions don't show in dataclass representations validator=self.validator_name, default=self.default, required=self.required, ) return generate_repr_from_string( class_name, attribute_dict, flatten=flatten, show_value_attributes=show_value_attributes )
def __repr__(self) -> str: """Helper method for displaying parameter information in a user- friendly manner.""" return self.structure()
[docs] class BaseAPIParameterMap(BaseModel): """Base class for Mapping universal SearchAPI parameter names to API-specific parameter names. Includes core logic for distinguishing parameter names, indicating required API keys, and defining pagination logic. Attributes: query (str): The API-specific parameter name for the search query. start (Optional[str]): The API-specific parameter name for optional pagination (start index or page number). records_per_page (str): The API-specific parameter name for records per page. api_key_parameter (Optional[str]): The API-specific parameter name for the API key. api_key_required (bool): Indicates whether an API key is required. page_required (bool): If True, indicates that a page is required. auto_calculate_page (bool): If True, calculates start index from page; if False, passes page number directly. zero_indexed_pagination (bool): Treats page=0 as an allowed page value when retrieving data from the API. api_specific_parameters (Dict[str, APISpecificParameter]): Additional API-specific parameter mappings. """ query: str records_per_page: str start: Optional[str] = None api_key_parameter: Optional[str] = None api_key_required: bool = False auto_calculate_page: bool = True zero_indexed_pagination: bool = False api_specific_parameters: Dict[str, APISpecificParameter] = Field(default_factory=dict)
[docs] def update(self, other: BaseAPIParameterMap | Dict[str, Any]) -> BaseAPIParameterMap: """Update the current instance with values from another BaseAPIParameterMap or dictionary. Args: other (BaseAPIParameterMap | Dict): The object containing updated values. Returns: BaseAPIParameterMap: A new instance with updated values. """ if isinstance(other, BaseAPIParameterMap): other = other.to_dict() updated_dict = self.to_dict() | other return self.from_dict(updated_dict)
[docs] @classmethod def from_dict(cls, obj: Dict[str, Any]) -> BaseAPIParameterMap: """Create a new instance of BaseAPIParameterMap from a dictionary. Args: obj (dict): The dictionary containing the data for the new instance. Returns: BaseAPIParameterMap: A new instance created from the given dictionary. """ return cls.model_validate(obj)
[docs] def to_dict(self) -> Dict[str, Any]: """Convert the current instance into a dictionary representation. Returns: Dict: A dictionary representation of the current instance. """ return self.model_dump()
[docs] def show_parameters(self) -> list: """Helper method to show the complete list of all parameters that can be found in the current ParameterMap. Returns: List: The complete list of all universal and api specific parameters corresponding to the current API """ parameters = [ parameter for parameter in self.model_dump() if parameter not in ("api_key_required", "auto_calculate_page", "api_specific_parameters", "zero_indexed_pagination") ] parameters += list(self.api_specific_parameters.keys()) return parameters
[docs] def structure(self, flatten: bool = False, show_value_attributes: bool = True) -> str: """Helper method that shows the current structure of the BaseAPIParameterMap.""" return generate_repr(self, flatten=flatten, show_value_attributes=show_value_attributes)
def __repr__(self) -> str: """Helper method for displaying the config in a user-friendly manner.""" return self.structure()
__all__ = ["BaseAPIParameterMap", "APISpecificParameter"]