Source code for somerandomapi.clients.animal

from __future__ import annotations

from typing import TYPE_CHECKING, Any, overload
from collections.abc import Coroutine
import logging

from .. import (
    enums,
    utils as _utils,
)
from ..internals.endpoints import (
    Animal as AnimalEndpoint,
    Facts as AnimalFactsEndpoint,
    Img as AnimalImgEndpoint,
)
from ..models.animal_fact import AnimalImageFact, AnimalImageOrFact
from .abc import BaseClient

if TYPE_CHECKING:
    from ..types.animal import (
        Animal as AnimalPayload,
        ValidAnimal as AnimalsLiterals,
    )
    from ..types.facts import (
        Fact as FactPayload,
        ValidFact as FactsAnimalsLiterals,
    )
    from ..types.img import (
        Img as ImgPayload,
        ValidImg as ImgAnimalsLiterals,
    )


__all__ = ("AnimalClient",)

_log = logging.getLogger(__name__)


[docs] class AnimalClient(BaseClient): """Represents the "Animal" endpoint. This class is not meant to be instantiated by you. Instead, access it through the :attr:`~somerandomapi.Client.animal` attribute of the :class:`~somerandomapi.Client` class. """ @overload def __handle_animal( self, _enum: type[enums.Animal], _input: enums.Animal | AnimalsLiterals, ) -> Coroutine[Any, Any, AnimalPayload]: ... @overload def __handle_animal( self, _enum: type[enums.Img], _input: enums.Img | ImgAnimalsLiterals, ) -> Coroutine[Any, Any, ImgPayload]: ... @overload def __handle_animal( self, _enum: type[enums.Fact], _input: enums.Fact | FactsAnimalsLiterals, ) -> Coroutine[Any, Any, FactPayload]: ... def __handle_animal( self, _enum: type[enums.Animal | enums.Img | enums.Fact], _input: enums.Animal | AnimalsLiterals | enums.Img | ImgAnimalsLiterals | enums.Fact | FactsAnimalsLiterals, ) -> Coroutine[Any, Any, AnimalPayload | ImgPayload | FactPayload]: endpoint_from_enum = { enums.Animal: AnimalEndpoint, enums.Img: AnimalImgEndpoint, enums.Fact: AnimalFactsEndpoint, } return self._http.request(endpoint_from_enum[_enum].from_enum(_utils._str_or_enum(_input, _enum)))
[docs] async def get_image_and_fact(self, animal: enums.Animal | AnimalsLiterals) -> AnimalImageFact: """Get a random image and fact about an animal. Parameters ---------- animal: Union[:class:`.Animal`, :class:`str`] The animal to get an image and fact about. Returns ------- :class:`.AnimalImageFact` Object representing the requested animal and its image and fact. Use :attr:`.fact` and :attr:`.image` to get the fact and image url respectively. """ response = await self.__handle_animal(enums.Animal, animal) return AnimalImageFact(**response)
# @BaseClient._contextmanager
[docs] async def get_image(self, animal: enums.Img | ImgAnimalsLiterals) -> str: """Get a random image of an animal. Parameters ---------- animal: Union[:class:`.Img`, :class:`str`] The animal to get an image of. Returns ------- :class:`str` The image URL. """ response = await self.__handle_animal(enums.Img, animal) return response["link"]
[docs] async def get_fact(self, animal: enums.Fact | FactsAnimalsLiterals) -> str: """Get a random fact about an animal. Parameters ---------- animal: Union[:class:`.Fact`, :class:`str`] The animal to get a fact about. Returns ------- :class:`str` The fact about the animal. """ response = await self.__handle_animal(enums.Fact, animal) return response["fact"]
# @BaseClient._contextmanager
[docs] async def get_image_or_fact( self, animal: enums.Animal | AnimalsLiterals | enums.Img | ImgAnimalsLiterals | enums.Fact | FactsAnimalsLiterals, ) -> AnimalImageOrFact: """A helper method to get either an image or a fact or both about an animal since the API provides different endpoints for each. .. versionadded:: 0.1.0 This uses the following methods in order to get the image or fact or both: 1. :meth:`~somerandomapi.AnimalClient.get_image_and_fact` 2. :meth:`~somerandomapi.AnimalClient.get_fact` 3. :meth:`~somerandomapi.AnimalClient.get_image` And returns an :class:`~somerandomapi.models.animal_fact.AnimalImageOrFact` object with the results. Parameters ---------- animal: Union[:class:`.Animal`, :class:`.Img`, :class:`.Fact`, :class:`str`] The animal to get an image or fact or both of. Returns ------- :class:`.AnimalImageOrFact` Object representing the requested animal and its image or fact or both. Use :attr:`.fact` and :attr:`.image` to get the fact and image url respectively. """ fact: str | None = None image: str | None = None animal_str: Any = str(animal.value) if not isinstance(animal, str) else animal.lower() # try getting both image and fact try: res = await self.get_image_and_fact(animal_str) fact = res.fact image = res.image except (ValueError, TypeError) as e: _log.debug("Failed to get image and fact for %r. Error: %s", animal_str, e) # get fact if not yet gotten if not fact: try: fact = await self.get_fact(animal_str) except (ValueError, TypeError) as e: _log.debug("Failed to get fact for %r. Error: %s", animal_str, e) # get image if not yet gotten if not image: try: image = await self.get_image(animal_str) except (ValueError, TypeError) as e: _log.debug("Failed to get image for %r. Error: %s", animal_str, e) return AnimalImageOrFact(fact=fact, image=image)