GitHub

API reference for Cache.

Make one with Cache.make(lookup, capacity=...).

Attributes

AttributeTypeDescription
capacityint | None

The most entries the cache keeps, or None for no limit.

Functions

__init__

__init__(lookup, context, capacity, time_to_live) -> None
ParameterTypeDescription
lookupCallable[[K], Effect[A, E, Any]]
contextContext
capacityint | None
time_to_liveCallable[[Exit[A, E], K], Seconds]
def __init__(
    self,
    lookup: Callable[[K], Effect[A, E, Any]],
    context: Context,
    capacity: int | None,
    time_to_live: Callable[[Exit[A, E], K], Seconds],
) -> None:
    self._lookup = lookup
    self._context = context
    self._capacity = capacity
    self._time_to_live = time_to_live
    # Least recently used first.
    self._entries: dict[K, _Entry[A, E]] = {}

make

make(lookup, *, capacity, time_to_live=None, require_services_at='construction') -> Effect[Cache[Any, Any, Any, Any], Never, Any]

A cache that looks keys up with lookup, keeping at most capacity entries (None: no limit). time_to_live is a duration, or a function of the lookup's Exit and the key; the default is forever, and zero keeps nothing. Lookups see the services of the context made in, overridden by the caller's; require_services_at="lookup" makes get require them.

ParameterTypeDescription
lookupCallable[[Any], Effect[Any, Any, Any]]
capacityint | None
time_to_liveTimeToLive[Any, Any, Any] | None = None
require_services_atRequireServicesAt = 'construction'

Returns Effect[Cache[Any, Any, Any, Any], Never, Any]

@staticmethod
def make(
    lookup: Callable[[Any], Effect[Any, Any, Any]],
    *,
    capacity: int | None,
    time_to_live: TimeToLive[Any, Any, Any] | None = None,
    require_services_at: RequireServicesAt = "construction",
) -> Effect[Cache[Any, Any, Any, Any], Never, Any]:
    """A cache that looks keys up with ``lookup``, keeping at most
    ``capacity`` entries (``None``: no limit). ``time_to_live`` is a
    duration, or a function of the lookup's ``Exit`` and the key; the
    default is forever, and zero keeps nothing. Lookups see the
    services of the context made in, overridden by the caller's;
    ``require_services_at="lookup"`` makes ``get`` require them."""
    bound = checked_capacity(capacity)
    ttl = time_to_live_of(time_to_live)
    return _WithFiber(lambda fiber: _Succeed(Cache(lookup, fiber._context, bound, ttl)))

get

get(key) -> Effect[A, E, R]

The value for key: cached, joined while another caller looks it up, or looked up now. A lookup runs on a fiber of its own, so it lives on while anyone waits for it; when the last waiter leaves, it is interrupted and forgotten.

ParameterTypeDescription
keyK

Returns Effect[A, E, R]

def get(self, key: K) -> Effect[A, E, R]:
    """The value for ``key``: cached, joined while another caller looks
    it up, or looked up now. A lookup runs on a fiber of its own, so it
    lives on while anyone waits for it; when the last waiter leaves, it
    is interrupted and forgotten."""
    return _WithFiber(lambda fiber: self._get(fiber, key))

get_option

get_option(key) -> Effect[Option[A], E]

Some value for a cached key (waiting for a lookup in progress), None for a missing or expired one. Never looks up.

ParameterTypeDescription
keyK

Returns Effect[Option[A], E]

def get_option(self, key: K) -> Effect[Option[A], E]:
    """``Some`` value for a cached key (waiting for a lookup in
    progress), ``None`` for a missing or expired one. Never looks up."""

    def body(fiber: Fiber[Any, Any]) -> Effect[Option[A], E]:
        entry = self._find(fiber, key, touch=True)
        return _Succeed(None) if entry is None else entry.await_from(fiber).map(Some)

    return _WithFiber(body)

get_success

get_success(key) -> Effect[Option[A]]

Some value for a key whose lookup has succeeded, else None. Never waits.

ParameterTypeDescription
keyK

Returns Effect[Option[A]]

def get_success(self, key: K) -> Effect[Option[A]]:
    """``Some`` value for a key whose lookup has succeeded, else
    ``None``. Never waits."""

    def body(fiber: Fiber[Any, Any]) -> Effect[Option[A]]:
        entry = self._find(fiber, key, touch=True)
        ex = None if entry is None else entry.fiber.unsafe_poll()
        return _Succeed(Some(ex.value) if isinstance(ex, Success) else None)

    return _WithFiber(body)

set

set(key, value) -> Effect[None]

Cache value for key with the time to live of a successful lookup.

ParameterTypeDescription
keyK
valueA

Returns Effect[None]

def set(self, key: K, value: A) -> Effect[None]:
    """Cache ``value`` for ``key`` with the time to live of a successful
    lookup."""

    def body(fiber: Fiber[Any, Any]) -> Effect[None]:
        ex: Exit[A, E] = Success(value)
        ttl = self._time_to_live(ex, key)
        if ttl == 0:
            self._discard(key)
            return _VOID
        entry = _Entry[A, E](_finished(fiber, ex))
        entry.expires_at = deadline(clock_of(fiber), ttl)
        self._entries[key] = entry
        self._evict_overflow()
        return _VOID

    return _WithFiber(body)

has

has(key) -> Effect[bool]

Whether key is cached and unexpired (a lookup in progress counts). Does not count as a use.

ParameterTypeDescription
keyK

Returns Effect[bool]

def has(self, key: K) -> Effect[bool]:
    """Whether ``key`` is cached and unexpired (a lookup in progress
    counts). Does not count as a use."""
    return _WithFiber(lambda fiber: _Succeed(self._find(fiber, key, touch=False) is not None))

invalidate

invalidate(key) -> Effect[None]

Forget key. A lookup in progress goes on for its waiters.

ParameterTypeDescription
keyK

Returns Effect[None]

def invalidate(self, key: K) -> Effect[None]:
    """Forget ``key``. A lookup in progress goes on for its waiters."""
    return _Sync(lambda: self._discard(key))

invalidate_when

invalidate_when(key, predicate) -> Effect[bool]

Forget key if its value (waited for if still being looked up) passes predicate. False if it did not, if the lookup failed, or if the entry was replaced meanwhile.

ParameterTypeDescription
keyK
predicateCallable[[A], bool]

Returns Effect[bool]

def invalidate_when(self, key: K, predicate: Callable[[A], bool]) -> Effect[bool]:
    """Forget ``key`` if its value (waited for if still being looked up)
    passes ``predicate``. ``False`` if it did not, if the lookup failed,
    or if the entry was replaced meanwhile."""

    def body(fiber: Fiber[Any, Any]) -> Effect[bool]:
        entry = self._find(fiber, key, touch=False)
        if entry is None:
            return _Succeed(False)

        def check(value: A) -> bool:
            if not predicate(value) or self._entries.get(key) is not entry:
                return False
            del self._entries[key]
            return True

        return entry.await_from(fiber).map(check).catch_cause(lambda _: _Succeed(False))

    return _WithFiber(body)

refresh

refresh(key) -> Effect[A, E, R]

Look key up again. A cached value keeps serving get until the new lookup succeeds or fails; a missing key is cached at once, as get would.

ParameterTypeDescription
keyK

Returns Effect[A, E, R]

def refresh(self, key: K) -> Effect[A, E, R]:
    """Look ``key`` up again. A cached value keeps serving ``get`` until
    the new lookup succeeds or fails; a missing key is cached at once,
    as ``get`` would."""
    return _WithFiber(lambda fiber: self._refresh(fiber, key))

invalidate_all

invalidate_all() -> Effect[None]

Forget every key.

Returns Effect[None]

def invalidate_all(self) -> Effect[None]:
    """Forget every key."""
    return _Sync(self._entries.clear)

size

size() -> Effect[int]

How many entries the cache holds, expired ones included until something reads them.

Returns Effect[int]

def size(self) -> Effect[int]:
    """How many entries the cache holds, expired ones included until
    something reads them."""
    return _Sync(lambda: len(self._entries))

keys

keys() -> Effect[list[K]]

The unexpired keys, least recently used first. Drops the expired ones.

Returns Effect[list[K]]

def keys(self) -> Effect[list[K]]:
    """The unexpired keys, least recently used first. Drops the
    expired ones."""
    return _WithFiber(lambda fiber: _Succeed([key for key, _ in self._live(fiber)]))

values

values() -> Effect[list[A]]

The values of the unexpired, successful lookups.

Returns Effect[list[A]]

def values(self) -> Effect[list[A]]:
    """The values of the unexpired, successful lookups."""
    return self.entries().map(lambda pairs: [value for _, value in pairs])

entries

entries() -> Effect[list[tuple[K, A]]]

The keys and values of the unexpired, successful lookups. Drops the expired entries.

Returns Effect[list[tuple[K, A]]]

def entries(self) -> Effect[list[tuple[K, A]]]:
    """The keys and values of the unexpired, successful lookups. Drops
    the expired entries."""

    def body(fiber: Fiber[Any, Any]) -> Effect[list[tuple[K, A]]]:
        pairs: list[tuple[K, A]] = []
        for key, entry in self._live(fiber):
            ex = entry.fiber.unsafe_poll()
            if isinstance(ex, Success):
                pairs.append((key, ex.value))
        return _Succeed(pairs)

    return _WithFiber(body)