Skip to content

PokeLance

client

ClientBase

ClientBase(
    *, http: _HTTPClientT_co, **kwargs: Unpack[ClientConfig]
)

Bases: Generic[_HTTPClientT_co]

Shared base logic for PokeLanceAsyncClient and PokeLanceSyncClient.

Parameters:

Name Type Description Default
http AsyncHttpClient | SyncHttpClient

The HTTP client used to make requests to the PokeAPI.

required
**kwargs Unpack[ClientConfig]

Optional client configuration options.

{}

Attributes:

Name Type Description
http AsyncHttpClient | SyncHttpClient

The HTTP client used to make requests to the PokeAPI.

cache_endpoints bool

Whether to pre-populate endpoint caches.

image_cache_size int

The size of the image cache.

audio_cache_size int

The size of the audio cache.

ext_tasks list[tuple[Callable, str]]

A list of setup callables/coroutines to load extension data.

Source code in pokelance/client/_base.py
def __init__(
    self,
    *,
    http: _HTTPClientT_co,
    **kwargs: Unpack[ClientConfig],
) -> None:
    if kwargs.get("setup_logging", True):
        setup_logging(
            log_level=kwargs.get("log_level", logging.INFO),
            structured=kwargs.get("structured_logging", False),
            file_logging=kwargs.get("file_logging", False),
            log_dir=kwargs.get("log_dir", "logs"),
            set_excepthook=kwargs.get("set_excepthook", True),
        )
    self._http = http
    self._cache_endpoints = kwargs.get("cache_endpoints", True)
    self._ext_tasks = []
    self._image_cache_size = kwargs.get("image_cache_size", 128)
    self._audio_cache_size = kwargs.get("audio_cache_size", 128)

http property

http: _HTTPClientT_co

The HTTP client used to make requests to the PokeAPI.

cache_endpoints property

cache_endpoints: bool

Whether to pre-populate endpoint caches.

ext_tasks property

ext_tasks: list[tuple[Callable[..., Any], str]]

A list of setup callables/coroutines to load extension data.

image_cache_size property

image_cache_size: int

The size of the image cache.

audio_cache_size property

audio_cache_size: int

The size of the audio cache.

setup_hook

setup_hook(ext_pkg: str) -> None

Dynamically loads extensions from the specified package directory.

Source code in pokelance/client/_base.py
def setup_hook(self, ext_pkg: str) -> None:
    """Dynamically loads extensions from the specified package directory."""
    logger.info(f"Using cache size: {self._http.cache_manager.max_size}")
    if not self.EXTENSIONS.exists():
        logger.warning(f"Extensions directory '{self.EXTENSIONS}' does not exist.")
        return
    for extension in self.EXTENSIONS.iterdir():
        if extension.is_file() and extension.suffix == ".py" and "_" not in extension.stem:
            module = __import__(f"{ext_pkg}.{extension.stem}", fromlist=["setup"])
            module.setup(self)
            logger.debug(f"Loaded extension module: {extension.stem}")
    logger.info("Setup complete")

add_extension

add_extension(
    name: str, extension: BaseExtension[_HTTPClientT_co]
) -> None

Adds an extension to the client.

Source code in pokelance/client/_base.py
def add_extension(self, name: str, extension: BaseExtension[_HTTPClientT_co]) -> None:
    """Adds an extension to the client."""
    self._ext_tasks.append((extension.setup, name))
    setattr(self, name, extension)
    logger.debug(f"Registered extension '{name}'")

ClientConfig

Bases: TypedDict

Configuration options for PokeLance clients.

Attributes:

Name Type Description
audio_cache_size int

Max entries in the audio LRU cache.

image_cache_size int

Max entries in the image LRU cache.

cache_endpoints bool

Whether to eagerly cache the name/id registries on client startup.

setup_logging bool

Whether PokeLance should configure default terminal logging.

log_level int

Log severity level filter.

structured_logging bool

Output logs as structured JSON rather than ANSI-colored plain text.

file_logging bool

Whether to write timestamped log files under log_dir.

log_dir str | Path

Directory destination when file_logging=True.

set_excepthook bool

Whether to install a custom exception hook for unhandled exceptions.

PokeLanceAsyncClient

PokeLanceAsyncClient(
    *,
    cache_size: int = 100,
    session: AsyncSession | None = None,
    **kwargs: Unpack[ClientConfig],
)

Bases: ClientBase[AsyncHttpClient]

Main asynchronous client to interact with the PokeAPI.

Parameters:

Name Type Description Default
cache_size int

The maximum cache size for the HTTP client.

100
session AsyncSession | None

An optional custom AsyncSession to use for requests.

None
**kwargs Unpack[ClientConfig]

Additional configuration options.

{}

Attributes:

Name Type Description
http AsyncHttpClient

The HTTP client used to make requests to the PokeAPI.

cache_endpoints bool

Whether to pre-populate endpoint caches. Defaults to True.

berry Berry

The berry extension.

contest Contest

The contest extension.

encounter Encounter

The encounter extension.

evolution Evolution

The evolution extension.

game Game

The game extension.

item Item

The item extension.

location Location

The location extension.

machine Machine

The machine extension.

move Move

The move extension.

pokemon Pokemon

The pokemon extension.

utility Utility

The utility extension.

Examples:

import asyncio
from pokelance import PokeLanceAsyncClient

async def main() -> None:
    async with PokeLanceAsyncClient() as client:
        pokemon = await client.pokemon.get_pokemon("pikachu")
        print(f"{pokemon.name} (ID: {pokemon.id})")

asyncio.run(main())
Source code in pokelance/client/async_client.py
def __init__(
    self,
    *,
    cache_size: int = 100,
    session: niquests.AsyncSession | None = None,
    **kwargs: Unpack[ClientConfig],
) -> None:
    super().__init__(
        http=AsyncHttpClient(client=self, session=session, cache_size=cache_size),
        **kwargs,
    )
    self.get_image.set_size(self._image_cache_size)
    self.get_audio.set_size(self._audio_cache_size)
    self.setup_hook("pokelance.ext._async")

ping async

ping() -> float

Pings the PokeAPI and returns the latency in seconds.

Returns:

Type Description
float

The round-trip latency in seconds.

Examples:

latency = await client.ping()
print(f"Latency: {latency * 1000:.1f}ms")
Source code in pokelance/client/async_client.py
async def ping(self) -> float:
    """Pings the PokeAPI and returns the latency in seconds.

    Returns
    -------
    float
        The round-trip latency in seconds.

    Examples
    --------
    ```python
    latency = await client.ping()
    print(f"Latency: {latency * 1000:.1f}ms")
    ```
    """
    return await self._http.ping()

close async

close() -> None

Closes the underlying HTTP client session.

Examples:

await client.close()
Source code in pokelance/client/async_client.py
async def close(self) -> None:
    """Closes the underlying HTTP client session.

    Examples
    --------
    ```python
    await client.close()
    ```
    """
    logger.warning("Closing session!")
    await self._http.close()

getch_data async

getch_data(
    ext: ExtensionEnum | ExtensionsL | str,
    category: str,
    id_: int | str | None = None,
) -> BaseModelT

Looks up an object from cache first, fetching from PokeAPI if not cached.

Parameters:

Name Type Description Default
ext ExtensionEnum | ExtensionsL | str

The extension name (e.g. 'pokemon', 'berry', 'item').

required
category str

The category name within the extension (e.g. 'pokemon', 'berry').

required
id_ int | str | None

The ID or name of the resource to look up.

None

Returns:

Type Description
BaseModelT

The retrieved model instance or sequence of models.

Examples:

from pokelance.constants import ExtensionEnum

# Using string identifiers
pokemon = await client.getch_data("pokemon", "pokemon", "pikachu")

# Using ExtensionEnum for type safety
berry = await client.getch_data(ExtensionEnum.Berry, "berry", 1)
Source code in pokelance/client/async_client.py
async def getch_data(
    self,
    ext: ExtensionEnum | ExtensionsL | str,
    category: str,
    id_: int | str | None = None,
) -> BaseModelT:  # pyright: ignore[reportInvalidTypeVarUse]
    """Looks up an object from cache first, fetching from PokeAPI if not cached.

    Parameters
    ----------
    ext : ExtensionEnum | ExtensionsL | str
        The extension name (e.g. 'pokemon', 'berry', 'item').
    category : str
        The category name within the extension (e.g. 'pokemon', 'berry').
    id_ : int | str | None, optional
        The ID or name of the resource to look up.

    Returns
    -------
    BaseModelT
        The retrieved model instance or sequence of models.

    Examples
    --------
    ```python
    from pokelance.constants import ExtensionEnum

    # Using string identifiers
    pokemon = await client.getch_data("pokemon", "pokemon", "pikachu")

    # Using ExtensionEnum for type safety
    berry = await client.getch_data(ExtensionEnum.Berry, "berry", 1)
    ```
    """
    ext_instance, resolved_category = self._resolve_extension_category(ext, category)
    get_ = getattr(ext_instance, f"get_{resolved_category}")
    fetch_ = getattr(ext_instance, f"fetch_{resolved_category}")
    params = (id_,) if id_ is not None else ()
    return t.cast("BaseModelT", get_(*params) or await fetch_(*params))

from_url async

from_url(url: str) -> BaseModelT

Constructs a request from any valid PokeAPI resource URL.

Parameters:

Name Type Description Default
url str

The PokeAPI resource URL (e.g. 'https://pokeapi.co/api/v2/pokemon/25/').

required

Returns:

Type Description
BaseModelT

The corresponding model instance for the URL resource.

Raises:

Type Description
ValueError

If the provided URL is not a valid PokeAPI endpoint.

Examples:

pokemon = await client.from_url("https://pokeapi.co/api/v2/pokemon/25/")
print(pokemon.name)  # pikachu
Source code in pokelance/client/async_client.py
async def from_url(self, url: str) -> BaseModelT:  # pyright: ignore[reportInvalidTypeVarUse]
    """Constructs a request from any valid PokeAPI resource URL.

    Parameters
    ----------
    url : str
        The PokeAPI resource URL (e.g. 'https://pokeapi.co/api/v2/pokemon/25/').

    Returns
    -------
    BaseModelT
        The corresponding model instance for the URL resource.

    Raises
    ------
    ValueError
        If the provided URL is not a valid PokeAPI endpoint.

    Examples
    --------
    ```python
    pokemon = await client.from_url("https://pokeapi.co/api/v2/pokemon/25/")
    print(pokemon.name)  # pikachu
    ```
    """
    if params := ExtensionEnum.validate_url(url):
        return await self.getch_data(params.extension, params.category, params.value)
    raise ValueError(f"Invalid URL: {url}")

get_image async

get_image(url: str) -> bytes

Downloads image sprite bytes from a URL with LRU caching.

Parameters:

Name Type Description Default
url str

The image sprite URL.

required

Returns:

Type Description
bytes

The raw image file bytes.

Examples:

import io

pokemon = await client.pokemon.get_pokemon("pikachu")
if pokemon.sprites.front_default:
    sprite_bytes = await client.get_image(pokemon.sprites.front_default)
    # Use in-memory buffer without blocking async IO
    buffer = io.BytesIO(sprite_bytes)
Source code in pokelance/client/async_client.py
@alru_cache(maxsize=128, typed=True)
async def get_image(self, /, url: str) -> bytes:
    """Downloads image sprite bytes from a URL with LRU caching.

    Parameters
    ----------
    url : str
        The image sprite URL.

    Returns
    -------
    bytes
        The raw image file bytes.

    Examples
    --------
    ```python
    import io

    pokemon = await client.pokemon.get_pokemon("pikachu")
    if pokemon.sprites.front_default:
        sprite_bytes = await client.get_image(pokemon.sprites.front_default)
        # Use in-memory buffer without blocking async IO
        buffer = io.BytesIO(sprite_bytes)
    ```
    """
    return await self._http.load_image(url)

get_audio async

get_audio(url: str) -> bytes

Downloads audio cry bytes from a URL with LRU caching.

Parameters:

Name Type Description Default
url str

The audio cry URL.

required

Returns:

Type Description
bytes

The raw audio file bytes.

Examples:

import io

pokemon = await client.pokemon.get_pokemon("pikachu")
if pokemon.cries.latest:
    cry_bytes = await client.get_audio(pokemon.cries.latest)
    # Use in-memory buffer without blocking async IO
    buffer = io.BytesIO(cry_bytes)
Source code in pokelance/client/async_client.py
@alru_cache(maxsize=128, typed=True)
async def get_audio(self, /, url: str) -> bytes:
    """Downloads audio cry bytes from a URL with LRU caching.

    Parameters
    ----------
    url : str
        The audio cry URL.

    Returns
    -------
    bytes
        The raw audio file bytes.

    Examples
    --------
    ```python
    import io

    pokemon = await client.pokemon.get_pokemon("pikachu")
    if pokemon.cries.latest:
        cry_bytes = await client.get_audio(pokemon.cries.latest)
        # Use in-memory buffer without blocking async IO
        buffer = io.BytesIO(cry_bytes)
    ```
    """
    return await self._http.load_audio(url)

wait_until_ready async

wait_until_ready() -> None

Waits until all background endpoint caches are pre-populated.

Examples:

client = PokeLanceAsyncClient()
await client.wait_until_ready()
# All background caches are now loaded
Source code in pokelance/client/async_client.py
async def wait_until_ready(self) -> None:
    """Waits until all background endpoint caches are pre-populated.

    Examples
    --------
    ```python
    client = PokeLanceAsyncClient()
    await client.wait_until_ready()
    # All background caches are now loaded
    ```
    """
    await self._http.connect()
    logger.info("Waiting until ready...")
    await self._http.loader.wait_until_ready()
    logger.info("Ready!")

PokeLanceSyncClient

PokeLanceSyncClient(
    *,
    cache_size: int = 100,
    session: Session | None = None,
    **kwargs: Unpack[ClientConfig],
)

Bases: ClientBase[SyncHttpClient]

Main synchronous client to interact with the PokeAPI.

Parameters:

Name Type Description Default
cache_size int

The maximum cache size for the HTTP client.

100
session Session | None

An optional custom Session to use for requests.

None
**kwargs Unpack[ClientConfig]

Additional configuration options.

{}

Attributes:

Name Type Description
http SyncHttpClient

The HTTP client used to make requests to the PokeAPI.

cache_endpoints bool

Whether to pre-populate endpoint caches. Defaults to True.

berry Berry

The berry extension.

contest Contest

The contest extension.

encounter Encounter

The encounter extension.

evolution Evolution

The evolution extension.

game Game

The game extension.

item Item

The item extension.

location Location

The location extension.

machine Machine

The machine extension.

move Move

The move extension.

pokemon Pokemon

The pokemon extension.

utility Utility

The utility extension.

Examples:

from pokelance import PokeLanceSyncClient

with PokeLanceSyncClient() as client:
    pokemon = client.pokemon.get_pokemon("pikachu")
    print(f"{pokemon.name} (ID: {pokemon.id})")
Source code in pokelance/client/sync_client.py
def __init__(
    self,
    *,
    cache_size: int = 100,
    session: niquests.Session | None = None,
    **kwargs: Unpack[ClientConfig],
) -> None:
    super().__init__(
        http=SyncHttpClient(client=self, session=session, cache_size=cache_size),
        **kwargs,
    )
    self._cached_get_image = functools.lru_cache(maxsize=self._image_cache_size)(self._http.load_image)
    self._cached_get_audio = functools.lru_cache(maxsize=self._audio_cache_size)(self._http.load_audio)
    self.setup_hook("pokelance.ext.sync")

ping

ping() -> float

Pings the PokeAPI and returns the latency in seconds.

Returns:

Type Description
float

The round-trip latency in seconds.

Examples:

latency = client.ping()
print(f"Latency: {latency * 1000:.1f}ms")
Source code in pokelance/client/sync_client.py
def ping(self) -> float:
    """Pings the PokeAPI and returns the latency in seconds.

    Returns
    -------
    float
        The round-trip latency in seconds.

    Examples
    --------
    ```python
    latency = client.ping()
    print(f"Latency: {latency * 1000:.1f}ms")
    ```
    """
    return self._http.ping()

close

close() -> None

Closes the underlying HTTP client session.

Examples:

client.close()
Source code in pokelance/client/sync_client.py
def close(self) -> None:
    """Closes the underlying HTTP client session.

    Examples
    --------
    ```python
    client.close()
    ```
    """
    logger.warning("Closing session!")
    self._http.close()

getch_data

getch_data(
    ext: ExtensionEnum | ExtensionsL | str,
    category: str,
    id_: int | str | None = None,
) -> BaseModelT

Looks up an object from cache first, fetching from PokeAPI if not cached.

Parameters:

Name Type Description Default
ext ExtensionEnum | ExtensionsL | str

The extension name (e.g. 'pokemon', 'berry', 'item').

required
category str

The category name within the extension (e.g. 'pokemon', 'berry').

required
id_ int | str | None

The ID or name of the resource to look up.

None

Returns:

Type Description
BaseModelT

The retrieved model instance or sequence of models.

Examples:

from pokelance.constants import ExtensionEnum

# Using string identifiers
pokemon = client.getch_data("pokemon", "pokemon", "pikachu")

# Using ExtensionEnum for type safety
berry = client.getch_data(ExtensionEnum.Berry, "berry", 1)
Source code in pokelance/client/sync_client.py
def getch_data(
    self,
    ext: ExtensionEnum | ExtensionsL | str,
    category: str,
    id_: int | str | None = None,
) -> BaseModelT:  # pyright: ignore[reportInvalidTypeVarUse]
    """Looks up an object from cache first, fetching from PokeAPI if not cached.

    Parameters
    ----------
    ext : ExtensionEnum | ExtensionsL | str
        The extension name (e.g. 'pokemon', 'berry', 'item').
    category : str
        The category name within the extension (e.g. 'pokemon', 'berry').
    id_ : int | str | None, optional
        The ID or name of the resource to look up.

    Returns
    -------
    BaseModelT
        The retrieved model instance or sequence of models.

    Examples
    --------
    ```python
    from pokelance.constants import ExtensionEnum

    # Using string identifiers
    pokemon = client.getch_data("pokemon", "pokemon", "pikachu")

    # Using ExtensionEnum for type safety
    berry = client.getch_data(ExtensionEnum.Berry, "berry", 1)
    ```
    """
    ext_instance, resolved_category = self._resolve_extension_category(ext, category)
    get_ = getattr(ext_instance, f"get_{resolved_category}")
    fetch_ = getattr(ext_instance, f"fetch_{resolved_category}")
    params = (id_,) if id_ is not None else ()
    return t.cast("BaseModelT", get_(*params) or fetch_(*params))

from_url

from_url(url: str) -> BaseModelT

Constructs a request from any valid PokeAPI resource URL.

Parameters:

Name Type Description Default
url str

The PokeAPI resource URL (e.g. 'https://pokeapi.co/api/v2/pokemon/25/').

required

Returns:

Type Description
BaseModelT

The corresponding model instance for the URL resource.

Raises:

Type Description
ValueError

If the provided URL is not a valid PokeAPI endpoint.

Examples:

pokemon = client.from_url("https://pokeapi.co/api/v2/pokemon/25/")
print(pokemon.name)  # pikachu
Source code in pokelance/client/sync_client.py
def from_url(self, url: str) -> BaseModelT:  # pyright: ignore[reportInvalidTypeVarUse]
    """Constructs a request from any valid PokeAPI resource URL.

    Parameters
    ----------
    url : str
        The PokeAPI resource URL (e.g. 'https://pokeapi.co/api/v2/pokemon/25/').

    Returns
    -------
    BaseModelT
        The corresponding model instance for the URL resource.

    Raises
    ------
    ValueError
        If the provided URL is not a valid PokeAPI endpoint.

    Examples
    --------
    ```python
    pokemon = client.from_url("https://pokeapi.co/api/v2/pokemon/25/")
    print(pokemon.name)  # pikachu
    ```
    """
    if params := ExtensionEnum.validate_url(url):
        return self.getch_data(params.extension, params.category, params.value)
    raise ValueError(f"Invalid URL: {url}")

get_image

get_image(url: str) -> bytes

Downloads image sprite bytes from a URL with LRU caching.

Parameters:

Name Type Description Default
url str

The image sprite URL.

required

Returns:

Type Description
bytes

The raw image file bytes.

Examples:

pokemon = client.pokemon.get_pokemon("pikachu")
if pokemon.sprites.front_default:
    image_bytes = client.get_image(pokemon.sprites.front_default)
Source code in pokelance/client/sync_client.py
def get_image(self, url: str) -> bytes:
    """Downloads image sprite bytes from a URL with LRU caching.

    Parameters
    ----------
    url : str
        The image sprite URL.

    Returns
    -------
    bytes
        The raw image file bytes.

    Examples
    --------
    ```python
    pokemon = client.pokemon.get_pokemon("pikachu")
    if pokemon.sprites.front_default:
        image_bytes = client.get_image(pokemon.sprites.front_default)
    ```
    """
    return self._cached_get_image(url)

get_audio

get_audio(url: str) -> bytes

Downloads audio cry bytes from a URL with LRU caching.

Parameters:

Name Type Description Default
url str

The audio cry URL.

required

Returns:

Type Description
bytes

The raw audio file bytes.

Examples:

pokemon = client.pokemon.get_pokemon("pikachu")
if pokemon.cries.latest:
    cry_bytes = client.get_audio(pokemon.cries.latest)
Source code in pokelance/client/sync_client.py
def get_audio(self, url: str) -> bytes:
    """Downloads audio cry bytes from a URL with LRU caching.

    Parameters
    ----------
    url : str
        The audio cry URL.

    Returns
    -------
    bytes
        The raw audio file bytes.

    Examples
    --------
    ```python
    pokemon = client.pokemon.get_pokemon("pikachu")
    if pokemon.cries.latest:
        cry_bytes = client.get_audio(pokemon.cries.latest)
    ```
    """
    return self._cached_get_audio(url)

wait_until_ready

wait_until_ready() -> None

Waits until all background endpoint caches are pre-populated.

Examples:

client = PokeLanceSyncClient()
client.wait_until_ready()
# All background caches are now loaded
Source code in pokelance/client/sync_client.py
def wait_until_ready(self) -> None:
    """Waits until all background endpoint caches are pre-populated.

    Examples
    --------
    ```python
    client = PokeLanceSyncClient()
    client.wait_until_ready()
    # All background caches are now loaded
    ```
    """
    self._http.connect()
    logger.info("Waiting until ready...")
    self._http.loader.wait_until_ready()
    logger.info("Ready!")

Comments