Skip to main content

Python decorators for caching functions returning iterators

Project description

Cacheable Iterators

A simple tool to assist caching iterators response (lazy computations remain lazy). Supports computations for the following return types:

  • Iterator[T]
  • Awaitable[Iterator[T]]
  • AsyncIterator[T]

Read full documentation online.

For simple or asynchronous iterators it can use either built-in functools.cache (or its replacement cacheable_iter.helpers.simple_cache), functools.lru_cache, or any other appropriate cache engine. For awaitable iterators it should use coroutine-compatible caches, the default (bundled) solution is async_lru.alru_cache (PyPI: async_lru).

Also works for methods and/or class methods, as well as with bound methods, as long as the caching engine supports them.

Usage

To make generator-like function be cacheable, simply decorate it with one of the following functions:

  • cacheable_iter.core.iter_cache or cacheable_iter.core.lru_iter_cache - for functions those return Iterator[T]
  • cacheable_iter.core.alru_iter_cache - for functions those return Awaitable[Iterator[T]]
  • cacheable_iter.core.lru_async_iter_cache - for functions those return AsyncIterator[T]

Caching Simple Iterator

from typing import *
from cacheable_iter import iter_cache

@iter_cache
def iterator_function(n: int) -> Iterator[int]:
    yield from range(n)

Caching Awaitable Iterator

import asyncio
from typing import *
from cacheable_iter import alru_iter_cache

@alru_iter_cache
async def awaitable_iterator_function(n: int) -> Iterator[int]:
    gen = iterator_function(n)
    await asyncio.sleep(0.5)
    return gen

Caching Asynchronous Iterator

import asyncio
from typing import *
from cacheable_iter import lru_async_iter_cache

@lru_async_iter_cache
async def async_iterator_function(n: int) -> AsyncIterator[int]:
    for _ in await awaitable_iterator_function(n):
        yield _
        await asyncio.sleep(0.5)

Example

This package provides a few decorators to wrap iterators. They all support lazy computations, so if an iterator is not iterated, the values are not computed. (This is safe to use with infinite or endless iterators like counters.)

from typing import *
from cacheable_iter import iter_cache

@iter_cache
def my_iter(n: int) -> Iterator[int]:
    print(" * my_iter called")
    for i in range(n):
        print(f" * my_iter step {i}")
        yield i

gen1 = my_iter(4)
print("Creating an iterator...")
print(f"The first value of gen1 is {next(gen1)}")
print(f"The second value of gen1 is {next(gen1)}")

gen2 = my_iter(4)
print("Creating an iterator...")
print(f"The first value of gen2 is {next(gen2)}")
print(f"The second value of gen2 is {next(gen2)}")
print(f"The third value of gen2 is {next(gen2)}")

The code snippet above would print the following:

Creating an iterator...
 * my_iter called
 * my_iter step 0
The first value of gen1 is 0
 * my_iter step 1
The second value of gen1 is 1
Creating an iterator...
The first value of gen2 is 0
The second value of gen2 is 1
 * my_iter step 2
The third value of gen2 is 2

Principe of Work

Like in caching, the function is wrapped around with the new one which, however, instead of checking the function arguments, transforms the result into a special helper class (either CachedIterable[T] or CachedAsyncIterable[T]).

Then the caching happens -- instead of storing the iterator itself it stores wrapper over it. When the cache value is extracted, both CachedIterable[T] and CachedAsyncIterable[T] are transformed into CachedIterator[T] or CachedAsyncIterator[T] respectively. (This is done by calling their __iter__ and __aiter__ methods.)

So, the client always receive an Iterator[T] (or analogue) rather then Iterable[T]. When the client reads from the iterator wrapper, the iterator checks the internal CachedIterable/CachedAsyncIterable cache and, if nothing found, asks the next value of the parent iterator which is then saved. CachedIterable/CachedAsyncIterable classes also take note when the iterator is ended to prevent ask an ended stream.

For Simple Iterators

  • Call function => Iterator[T]
  • Wrap result to CachedIterable[T]
  • Save result to the cache
  • Transform CachedIterable[T] to CachedIterator[T]
  • Iterate

Decorate with: cacheable_iter.core.iter_cache or cacheable_iter.core.lru_iter_cache.

For Awaitable Iterators

  • Call function => Awaitable[Iterator[T]]
  • Wrap result to Awaitable[CachedIterable[T]]
  • Save result to async cache
  • Transform Awaitable[CachedIterable[T]] to Awaitable[CachedIterator[T]]
  • Await
  • Iterate

Decorate with: cacheable_iter.core.alru_iter_cache.

For Asynchronous Iterators

  • Call function => AsyncIterator[T]
  • Wrap result to CachedAsyncIterable[T]
  • Save result to async cache
  • Transform CachedAsyncIterable[T] to CachedAsyncIterator[T]
  • Asynchronously iterate

Decorate with: cacheable_iter.core.lru_async_iter_cache.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cacheable_iterators-0.1.1-py3-none-any.whl (8.6 kB view details)

Uploaded Python 3

File details

Details for the file cacheable_iterators-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: cacheable_iterators-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 8.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/3.4.1 importlib_metadata/4.5.0 pkginfo/1.7.0 requests/2.25.1 requests-toolbelt/0.9.1 tqdm/4.61.1 CPython/3.9.5

File hashes

Hashes for cacheable_iterators-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 df213c27fa7460cdd31ec3a67649bb796eace2f9ea4d5780cf1b049da629f3b2
MD5 099649d33bc97d0bcc2cda58e295ea16
BLAKE2b-256 19f0bf161753105c3e16a76e670a48fa0a4a400e2c6b09aea9107af2bc880f2b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page