from typing import Any, Literal from pydantic import BaseModel, HttpUrl, ValidationError, model_validator from scryfall.models.base import BaseAPIModel from scryfall.models.cards import Card from scryfall.models.rulings import Ruling from scryfall.models.sets import Set from scryfall.models.symbols import CardSymbol CLASS_LOOKUP = {"card": Card, "card_symbol": CardSymbol, "ruling": Ruling, "set": Set} class APIError(BaseModel): """Scryfall API error model.""" status: int """HTTP status code""" code: str """HTTP status code text (i.e. not_found)""" details: str """More details""" type: str | None = None """The error type""" warnings: list[str] | None = None """Any associated warnings that are not quite errors""" class APIList(BaseAPIModel): """Scryfall API list model for paginated requests""" object: Literal["list"] """The object type, `list` in this case""" data: list[Card | CardSymbol | Ruling | Set] """The page of data, max 175 items unless it is an entire set of cards""" has_more: bool """If there are more pages""" next_page: HttpUrl | None = None """The URL to the next page""" total_cards: int | None = None """The total number of cards found by the original query""" warnings: list[str] | None = None """Warnings generated by the query that are not quite errors""" @model_validator(mode="before") @classmethod def validate_data(cls, data: Any) -> Any: if data.get("object") == "list": for item in data.get("data"): item["_client"] = data["_client"] obj = item.get("object") if obj not in CLASS_LOOKUP: raise ValidationError("Item missing object field") item = CLASS_LOOKUP[obj](**item) return data async def get_next_page(self) -> "APIList | None": """Get the next page of the query""" if self.has_more and self.next_page is not None: params = dict(self.next_page.query_params()) params.pop("format", None) return await self._client.search_cards(**params) # type: ignore return None