Skip to content

Async API

Largely motivated by its integration with Python Liquid, Python JSONPath offers an asynchronous API that allows for items in a target data structure to be "fetched" lazily.

findall_async() and finditer_async() are asyncio equivalents to findall() and finditer(). By default, any class implementing the mapping or sequence interfaces, and a __getitem_async__() method, will have __getitem_async__() awaited instead of calling __getitem__() when resolving mapping keys or sequence indices.

Example

In this example, showing a lazy-loading collections of Player objects, only the "A" team's players are fetched from the database, and only when they are first accessed.

from collections import abc
from dataclasses import dataclass
from typing import Dict
from typing import Iterator
from typing import List

import jsonpath


@dataclass
class Player:
    name: str
    pid: int
    rank: int


class LazyPlayers(abc.Mapping[str, Player]):
    def __init__(self, names: List[str]):
        self.names = names
        self.cached_players: Dict[str, Player] = {}

    def __len__(self) -> int:
        return len(self.names)

    def __iter__(self) -> Iterator[str]:
        return iter(self.names)

    def __getitem__(self, k: str) -> Player:
        if self.cached_players is None:
            # Blocking IO here
            self.cached_players = get_stuff_from_database()
        return self.cached_players[k]

    async def __getitem_async__(self, k: str) -> Player:
        if self.cached_players is None:
            # Do async IO here.
            self.cached_players = await get_stuff_from_database_async()
        return self.cached_players[k]


data = {
    "teams": {
        "A Team": LazyPlayers(["Sue", "Bob"]),
        "B Team": LazyPlayers(["Sally", "Frank"]),
    }
}

best_a_team_players = jsonpath.findall_async("$.teams['A Team'][?rank >= 8]", data)

Custom Async Item Getting

TODO: