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

Metadata

Release files for timeseries-cache 0.1.0

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.0
File Size Uploaded Provenance
timeseries_cache-0.1.0.tar.gz 10.8 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 20.5 kB

Release files / timeseries_cache-0.1.0.tar.gz

Download URL timeseries_cache-0.1.0.tar.gz
Size 10.8 kB
Tags Source
SHA-256 checksum
How to use checksums
d31a32920d7ef5a6512e78db201366ba33b9cd117506b113174329dd6a64ffca
BLAKE2b-256 checksum
How to use checksums
97f98d09e5b44f6bd34f3e951664f85a602dfb53dbec4270e861e9cd1a590a4f
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.0-py3-none-any.whl

Download URL timeseries_cache-0.1.0-py3-none-any.whl
Size 9.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7ce5846b622104f4b80d6df01241f05b1e1e0c210ddf224d491cae0953b947f6
BLAKE2b-256 checksum
How to use checksums
6d33ecfababfe6ab33816940de920d27aaf793c69499d7e36d2381c24cd15798
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.0

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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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