286 lines
8.5 KiB
Python
286 lines
8.5 KiB
Python
from datetime import date
|
|
from typing import Any, Literal, TYPE_CHECKING
|
|
from uuid import UUID
|
|
|
|
from pydantic import BaseModel, HttpUrl, field_validator
|
|
|
|
from scryfall.models.base import BaseAPIModel
|
|
from scryfall.models.enums import Color
|
|
|
|
if TYPE_CHECKING:
|
|
from scryfall.models.rulings import Ruling
|
|
from scryfall.models.sets import Set
|
|
|
|
|
|
class RelatedCard(BaseModel):
|
|
"""A card that's related to the current card"""
|
|
|
|
id: UUID
|
|
"""The UUID of the related card"""
|
|
|
|
object: Literal["related_card"]
|
|
"""The object type, literally `related_card`"""
|
|
|
|
component: Literal["token", "meld_part", "meld_result", "combo_piece"]
|
|
"""How the card is related"""
|
|
|
|
name: str
|
|
"""The name of the related card"""
|
|
|
|
type_line: str
|
|
"""The type line of the related card"""
|
|
|
|
uri: HttpUrl
|
|
"""The URL of the related card"""
|
|
|
|
|
|
class CardFace(BaseModel):
|
|
"""A card face, for multi-faced cards"""
|
|
|
|
artist: str | None = None
|
|
"""The face artist"""
|
|
|
|
artist_id: str | None = None
|
|
"""The ID of the face artist"""
|
|
|
|
cmc: float | None = None
|
|
"""Card Mana Cost"""
|
|
|
|
color_indicator: list[Color] | None = None
|
|
"""The color indicator(s) of the face"""
|
|
|
|
colors: list[Color] | None = None
|
|
"""The color(s) of the face"""
|
|
|
|
defense: str | None = None
|
|
"""The toughness of the face, if it exists"""
|
|
|
|
flavor_text: str | None = None
|
|
"""The face's flavor text"""
|
|
|
|
illustration_id: UUID | None = None
|
|
"""The face's illustration UUID"""
|
|
|
|
image_uris: dict[Literal["small", "normal", "large", "png", "art_crop", "border_crop"], HttpUrl] | None = None
|
|
"""URLs for the image face for different formats."""
|
|
|
|
layout: str | None = None
|
|
"""Layout of the face."""
|
|
|
|
loyalty: str | None = None
|
|
"""Face loyalty"""
|
|
|
|
mana_cost: str
|
|
"""Face mana cost"""
|
|
|
|
name: str
|
|
"""Name of the face"""
|
|
|
|
object: Literal["card_face"]
|
|
"""Object type, literally `card_face`"""
|
|
|
|
oracle_id: UUID | None = None
|
|
"""Oracle ID of the face"""
|
|
|
|
oracle_text: str | None = None
|
|
"""Oracle text of the face"""
|
|
|
|
power: str | None = None
|
|
"""The face's power"""
|
|
|
|
printed_name: str | None = None
|
|
"""The printed name of the face"""
|
|
|
|
printed_text: str | None = None
|
|
"""The printed text of the face"""
|
|
|
|
printed_type_line: str | None = None
|
|
"""The printed type line of the face"""
|
|
|
|
toughness: str | None = None
|
|
"""The toughness of the face"""
|
|
|
|
type_line: str | None = None
|
|
"""The type line of the face"""
|
|
|
|
watermark: str | None = None
|
|
"""The watermark of the face"""
|
|
|
|
|
|
class Preview(BaseModel):
|
|
"""Object for defining when the card was previewed."""
|
|
|
|
previewed_at: date | None = None
|
|
|
|
"""When it was previewed"""
|
|
|
|
source_uri: HttpUrl | None = None
|
|
"""The URL of where it was previewed"""
|
|
|
|
source: str | None = None
|
|
"""The source of the preview"""
|
|
|
|
@field_validator("source_uri", mode="before")
|
|
@classmethod
|
|
def validate_source_uri(cls, value: Any) -> Any:
|
|
if isinstance(value, str):
|
|
if len(value) > 0:
|
|
return HttpUrl(value)
|
|
return None
|
|
|
|
|
|
class Card(BaseAPIModel):
|
|
"""Main Card model."""
|
|
|
|
# Core fields
|
|
arena_id: int | None = None
|
|
"""MTG Arena ID"""
|
|
|
|
id: UUID
|
|
"""Scryfall card UUID"""
|
|
|
|
lang: str
|
|
"""Card language"""
|
|
|
|
mtgo_id: int | None = None
|
|
"""MTG Online ID"""
|
|
|
|
mtgo_foil_id: int | None = None
|
|
"""MTG Online Foil ID"""
|
|
|
|
multiverse_ids: list[int] | None = None
|
|
"""MTG Multiverse IDs"""
|
|
|
|
tcgplayer_id: int | None = None
|
|
"""TCGPlayer ID"""
|
|
|
|
tcgplayer_etched_id: int | None = None
|
|
"""TCGPlayer Etched ID"""
|
|
|
|
cardmarket_id: int | None = None
|
|
"""Cardmarket ID"""
|
|
|
|
object: Literal["card"]
|
|
"""Object type, literally `card`"""
|
|
|
|
layout: str
|
|
"""Card layout"""
|
|
|
|
oracle_id: UUID | None = None
|
|
"""Oracle UUID"""
|
|
|
|
prints_search_uri: HttpUrl
|
|
"""Print search URL for other printings"""
|
|
|
|
rulings_uri: HttpUrl
|
|
"""Rulings URL"""
|
|
|
|
scryfall_uri: HttpUrl
|
|
"""Scryfall URL"""
|
|
|
|
uri: HttpUrl
|
|
"""Card URL"""
|
|
|
|
# Gameplay fields
|
|
all_parts: list[RelatedCard] | None = None
|
|
"""If this card is closely related to other cards, this property will be an array with Related Card objects."""
|
|
card_faces: list[CardFace] | None = None
|
|
"""All faces of the card"""
|
|
cmc: float
|
|
"""Card mana value"""
|
|
color_identity: list[Color]
|
|
"""Card color identity"""
|
|
color_indicator: list[Color] | None = None
|
|
"""Card color indicator, if any"""
|
|
colors: list[Color] | None = None
|
|
"""Card colors, if any. Colors may be on the card's faces instead"""
|
|
defense: str | None = None
|
|
"""Toughness"""
|
|
edhrec_rank: int | None = None
|
|
"""EDHRec card rank/popularity"""
|
|
game_changer: bool | None = None
|
|
"""If this car is on the Commander Game Changer list"""
|
|
hand_modifier: str | None = None
|
|
"""Vanguard card hand modifier"""
|
|
keywords: list[str]
|
|
"""List of keywords, such as `Flying` or `Cumulative upkeep`"""
|
|
legalities: dict[str, Literal["legal", "not_legal", "restricted", "banned"]]
|
|
"""List of legalitites across different formats"""
|
|
life_modifier: str | None = None
|
|
"""The card's life modifier, if it is a Vanguard card. This value will contain a delta, such as `+2`."""
|
|
loyalty: str | None = None
|
|
"""This loyalty if any. Note that some cards have loyalties that are not numeric, such as X."""
|
|
mana_cost: str | None = None
|
|
"""The mana cost for this card. This value will be any empty string `""` if the cost is absent. Remember that per the game rules, a missing mana cost and a mana cost of `{0}` are different values. Multi-faced cards will report this value in card faces."""
|
|
name: str
|
|
"""The name of this card. If this card has multiple faces, this field will contain both names separated by `␣//␣`."""
|
|
oracle_text: str | None = None
|
|
"""The Oracle text for this card, if any."""
|
|
penny_rank: int | None = None
|
|
"""This card's rank/popularity on Penny Dreadful. Not all cards are ranked."""
|
|
power: str | None = None
|
|
"""This card's power, if any. Note that some cards have powers that are not numeric, such as `*`."""
|
|
produced_mana: list[Color] | None = None
|
|
"""Colors of mana that this card could produce."""
|
|
reserved: bool
|
|
"""True if this card is on the Reserved List."""
|
|
toughness: str | None = None
|
|
"""This card's toughness, if any. Note that some cards have toughnesses that are not numeric, such as `*`."""
|
|
type_line: str
|
|
"""The type line of this card."""
|
|
|
|
# Print fields
|
|
artist: str | None = None
|
|
artist_ids: list[UUID] | None = None
|
|
attraction_lights: list[int] | None = None
|
|
booster: bool
|
|
border_color: Literal["black", "white", "borderless", "yellow", "silver", "gold"]
|
|
card_back_id: UUID | None = None
|
|
collector_number: str
|
|
content_warning: bool | None = None
|
|
digital: bool
|
|
finishes: list[Literal["foil", "nonfoil", "etched"]]
|
|
flavor_name: str | None = None
|
|
flavor_text: str | None = None
|
|
frame_effects: list[str] | None = None
|
|
frame: str
|
|
full_art: bool
|
|
games: list[Literal["paper", "arena", "mtgo"]]
|
|
highres_image: bool
|
|
illustration_id: UUID | None = None
|
|
image_status: Literal["missing", "placeholder", "lowres", "highres_scan"]
|
|
image_uris: dict[Literal["small", "normal", "large", "png", "art_crop", "border_crop"], HttpUrl] | None = None
|
|
oversized: bool
|
|
prices: dict[str, str | None]
|
|
printed_name: str | None = None
|
|
printed_text: str | None = None
|
|
printed_type_line: str | None = None
|
|
promo: bool
|
|
promo_types: list[str] | None = None
|
|
purchase_uris: dict[str, HttpUrl] | None = None
|
|
rarity: Literal["common", "uncommon", "rare", "special", "mythic", "bonus"]
|
|
related_uris: dict[str, HttpUrl]
|
|
released_at: date
|
|
reprint: bool
|
|
scryfall_set_uri: HttpUrl
|
|
set_name: str
|
|
set_search_uri: HttpUrl
|
|
set_type: str
|
|
set_uri: HttpUrl
|
|
set: str
|
|
set_id: UUID
|
|
story_spotlight: bool
|
|
textless: bool
|
|
variation: bool
|
|
variation_of: UUID | None = None
|
|
security_stamp: Literal["oval", "triangle", "acorn", "circle", "arena", "heart"] | None = None
|
|
watermark: str | None = None
|
|
preview: Preview | None = None
|
|
|
|
async def get_set(self) -> "Set":
|
|
"""Get set card is a part of."""
|
|
return await self._client.get_set_by_id(self.set_id)
|
|
|
|
async def get_rulings(self) -> list["Ruling"]:
|
|
"""Get rulings for card."""
|
|
return await self._client.get_rulings_by_card_id(self.id)
|