Media: Sprites & Cries¶
Pokémon models come back from PokéAPI full of URLs to sprites and cries, not raw bytes. PokeLance provides dedicated helpers (get_image and get_audio) to fetch those, backed by an LRU cache so repeated lookups are instant.
Fetching an image¶
get_image downloads and validates any sprite URL, returning raw bytes:
import asyncio
from pokelance import PokeLanceAsyncClient
async def main() -> None:
async with PokeLanceAsyncClient() as client:
pokemon = await client.pokemon.fetch_pokemon("pikachu")
assert pokemon.sprites.front_default is not None
img = await client.get_image(pokemon.sprites.front_default)
print(f"Downloaded {len(img)} bytes from {pokemon.sprites.front_default}")
asyncio.run(main())
from pokelance import PokeLanceSyncClient
with PokeLanceSyncClient() as client:
pokemon = client.pokemon.fetch_pokemon("pikachu")
assert pokemon.sprites.front_default is not None
img = client.get_image(pokemon.sprites.front_default)
print(f"Downloaded {len(img)} bytes from {pokemon.sprites.front_default}")
Accepted content types are png, jpg, jpeg, gif, webp, and svg; anything else raises ImageNotFound.
import asyncio
import base64
from pokelance import PokeLanceAsyncClient
async def main() -> str:
async with PokeLanceAsyncClient() as client:
pokemon = await client.pokemon.fetch_pokemon("pikachu")
assert pokemon.sprites.front_default is not None
img = await client.get_image(pokemon.sprites.front_default)
encoded = base64.b64encode(img).decode("ascii")
return f'<img src="data:image/png;base64,{encoded}" alt="pikachu sprite" width="96" height="96"/>'
print(asyncio.run(main()))
Fetching a cry¶
get_audio works identically for the cries field on Pokemon models:
import asyncio
from pokelance import PokeLanceAsyncClient
async def main() -> None:
async with PokeLanceAsyncClient() as client:
pokemon = await client.pokemon.fetch_pokemon("pikachu")
audio = await client.get_audio(pokemon.cries.latest)
print(f"Downloaded {len(audio)} bytes from {pokemon.cries.latest}")
asyncio.run(main())
Accepted content types are ogg, wav, and mp3; anything else raises AudioNotFound.
import asyncio
import base64
from pokelance import PokeLanceAsyncClient
async def main() -> str:
async with PokeLanceAsyncClient() as client:
pokemon = await client.pokemon.fetch_pokemon("pikachu")
audio = await client.get_audio(pokemon.cries.latest)
encoded = base64.b64encode(audio).decode("ascii")
return f'<audio controls preload="none"><source src="data:audio/ogg;base64,{encoded}" type="audio/ogg"></audio>'
print(asyncio.run(main()))
Media caching¶
Image and audio helpers in PokeLanceAsyncClient use an asynchronous LRU cache (alru_cache), which deduplicates concurrent in-flight requests for the same URL.
Cache sizes can be configured during client construction or dynamically:
client = PokeLanceAsyncClient(image_cache_size=256, audio_cache_size=64)
client.image_cache_size = 512 # resize image cache
Error handling¶
Both helpers raise descriptive exceptions if the media URL is invalid or the network request fails:
import asyncio
from pokelance import PokeLanceAsyncClient
from pokelance.exceptions import ImageNotFound
async def main() -> None:
async with PokeLanceAsyncClient() as client:
try:
await client.get_image("https://pokeapi.co/api/v2/pokemon/invalid")
except ImageNotFound as exc:
print(f"Caught expected error: {exc}")
asyncio.run(main())
Caught expected error: Request to https://pokeapi.co/api/v2/pokemon/invalid was unsuccessful or the URL is not an image. (text/plain; charset=utf-8) | <Route endpoint= method=GET> | 404
See Error Handling for the full exception hierarchy.