Skip to main content

timeseries-cache

A persistent SQLite cache for time-series API data. It fetches only missing UTC date ranges and reuses saved rows across runs. The package itself uses only the Python standard library.

Install

Requires Python 3.10 or newer.

uv add timeseries-cache

Use the package

Declare a Schema with one timezone-aware datetime dimension, then create a Cache and call load(selection, start, end, fetcher). The fetcher receives (start, end, refresh) and returns rows with the declared dimensions and a value. load returns rows, a status (live, cache, stale, or unavailable), and any missing ranges. Pass refresh=True to fetch a range again. Cache files are stored in the directory passed to Cache.

Here is a runnable example using generated hourly observations. Replace the fetcher's body with your API call and return rows in the same format.

from datetime import datetime, timedelta, timezone

from timeseries_cache import Cache, Schema

schema = Schema({"timestamp": datetime, "sensor": str}, "timestamp")
cache = Cache("data/cache", schema)
selection = {"sensor": "A"}


def fetch(start, end, refresh):
    timestamp = start
    while timestamp < end:
        yield {"timestamp": timestamp, **selection, "value": 12.5}
        timestamp += timedelta(hours=1)


start = datetime(2024, 1, 1, tzinfo=timezone.utc)
end = start + timedelta(days=1)

first = cache.load(selection, start, end, fetch)
second = cache.load(selection, start, end, fetch)
print(first.status, second.status, len(second.rows))
# With an empty cache: live cache 24

The file data/cache/timeseries_cache.sqlite persists across Python sessions. Requesting a larger interval fetches only the uncovered parts. read() returns stored rows without fetching; missing() returns uncovered intervals.

Result status Meaning
live The requested fetches succeeded.
cache No fetch was needed.
stale Refreshing failed or was unavailable, but stored coverage exists.
unavailable Some interval remains uncovered.

Always inspect result.error and result.missing_ranges when a load is not successful. A failed fetch can still return previously cached rows.

Cache contract

  • One selection fixes every non-time dimension. For multiple series, call load for each selection.
  • A fetcher must return the complete response for [start, end), including all pages/chunks, or raise. An empty iterable means the interval was checked successfully. Missing observations alone cannot reveal a failed download.
  • Every row contains exactly the schema dimensions and value. Timestamps must be timezone-aware. Missing values use None; NaN and infinity are rejected.
  • Include inputs that affect results in options, such as provider URL, aggregation or model version. Use separate directories for separate accounts. The cache cannot identify which API a callback uses. JSON dictionaries must have string keys at every nesting level.
  • refresh=True reloads the whole interval. max_age=timedelta(hours=1) reloads only missing or expired intervals. Either option passes True to the fetcher when fetching, allowing it to bypass upstream caches.
  • If fetching cannot proceed, covered data returns stale; uncovered intervals return unavailable. missing_ranges describes absent coverage, independent of age. Successful zero-row responses still count as coverage.

By default, SQLite stores observations in cache_rows and fetched intervals in cache_ranges. Setting Schema.partition_dimension creates separate pairs of tables for each selected partition value.

Development

uv sync --extra test
uv run --extra test python -m pytest -q
uv run ruff check .
uv run ruff format --check .

Tests use temporary databases and mocked fetchers. No credentials or live API requests are needed.

Build the wheel and source archive with:

uv build --no-sources

License

Released under the MIT License. The full license text is included in the LICENSE file.

Metadata

Release files for timeseries-cache 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for timeseries-cache 0.1.1
File Size Uploaded Provenance
timeseries_cache-0.1.1.tar.gz 11.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for timeseries-cache 0.1.1
File Interpreter ABI Platform
timeseries_cache-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 22.2 kB

Release files / timeseries_cache-0.1.1.tar.gz

Download URL timeseries_cache-0.1.1.tar.gz
Size 11.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9a1bc0661bef6257228a67e641dbf3353713284b4d2834c8212e1e6ff180108c
BLAKE2b-256 checksum
How to use checksums
e088483467bfe4c19f94f4d183d19f70e7523be09afd7b7779d67dc9f27e1ca6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / timeseries_cache-0.1.1-py3-none-any.whl

Download URL timeseries_cache-0.1.1-py3-none-any.whl
Size 10.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b95343affd8465bdc3b715d45be488389695c61a15a634a1a85e1b6e7d6aba99
BLAKE2b-256 checksum
How to use checksums
c7dfa7aa19f53eb9d13b3b1ee75d1ef0fe175e9f728e17424bc52badc64f8e3e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Pop!_OS","version":"22.04","id":"jammy","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for timeseries-cache 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page