philiprehberger-cache-kit
Lightweight in-memory cache with TTL, LRU eviction, and tag-based invalidation.
Installation
pip install philiprehberger-cache-kit
Usage
Basic Cache
from philiprehberger_cache_kit import Cache
cache: Cache[str] = Cache(max_size=1000)
cache.set("key", "value")
print(cache.get("key")) # "value"
TTL (Time-to-Live)
cache = Cache(default_ttl=60.0) # 60 seconds default
cache.set("session", "abc123") # uses default TTL
cache.set("temp", "data", ttl=5.0) # expires in 5 seconds
cache.set("permanent", "data", ttl=None) # no expiry when default is set
LRU Eviction
cache = Cache(max_size=100)
# When full, least recently used entries are evicted first
# Expired entries are evicted before non-expired ones
for i in range(200):
cache.set(f"key-{i}", f"value-{i}")
print(cache.size) # 100
Tag-Based Invalidation
cache.set("user:1", user_data, tags={"users", "team-a"})
cache.set("user:2", user_data, tags={"users", "team-b"})
cache.set("post:1", post_data, tags={"posts", "team-a"})
# Invalidate all entries tagged "team-a"
removed = cache.invalidate_by_tag("team-a")
print(removed) # 2
# Invalidate everything tagged "team-a" OR "team-b" in one pass
removed = cache.invalidate_by_tags(["team-a", "team-b"])
Lazy load with get_or_compute
from philiprehberger_cache_kit import Cache
cache: Cache[dict] = Cache(max_size=1000)
def fetch_user(user_id: int) -> dict:
# Expensive lookup (DB, HTTP, etc.) — only called on cache miss.
return {"id": user_id, "name": "Ada"}
# First call: computes, caches with TTL/tags, returns the value (miss).
user = cache.get_or_compute(
"user:1",
lambda: fetch_user(1),
ttl=60.0,
tags=["users"],
)
# Second call within TTL: returns cached value, compute_fn is NOT invoked (hit).
user = cache.get_or_compute("user:1", lambda: fetch_user(1))
Batch Operations
# Set multiple entries at once
cache.set_many({"a": 1, "b": 2, "c": 3}, ttl=30.0)
# Get multiple entries at once (skips missing/expired)
results = cache.get_many(["a", "b", "missing"])
print(results) # {"a": 1, "b": 2}
Cache Statistics
from philiprehberger_cache_kit import Cache, CacheStats
cache: Cache[str] = Cache(max_size=100)
cache.set("x", "hello")
cache.get("x") # hit
cache.get("missing") # miss
stats = cache.stats()
print(stats.hits) # 1
print(stats.misses) # 1
print(stats.hit_rate) # 0.5
print(stats.evictions) # 0
print(stats.expired) # 0
cache.reset_stats() # zero out all counters
Other Operations
cache.has("key") # check existence
"key" in cache # same as has()
cache.delete("key") # delete single entry
cache.keys() # list all non-expired keys
len(cache) # count of non-expired entries
cache.get_entry("key") # get CacheEntry with tags, expires_at
cache.clear() # remove everything
API
| Function / Class | Description |
|---|---|
Cache(max_size=1000, default_ttl=None) |
Create a new cache |
.set(key, value, ttl=None, tags=None) |
Store a value |
.get(key, default=None) |
Retrieve a value |
.get_or_compute(key, compute_fn, ttl=None, tags=None) |
Return cached value, or compute and cache it on miss |
.get_many(keys) |
Retrieve multiple values, skip missing/expired |
.set_many(items, ttl=None) |
Store multiple values |
.has(key) |
Check if key exists and is not expired |
.delete(key) |
Remove a key |
.invalidate_by_tag(tag) |
Remove all entries with a tag |
.invalidate_by_tags(tags) |
Remove all entries matching any tag in tags (single pass) |
.clear() |
Remove all entries |
.keys() |
List non-expired keys |
.get_entry(key) |
Get CacheEntry object (value, expires_at, tags) |
.stats() |
Get CacheStats (hits, misses, evictions, expired, hit_rate) |
.reset_stats() |
Zero out all stat counters |
.size |
Number of stored entries |
len(cache) |
Number of non-expired entries |
key in cache |
Check key existence |
CacheStats |
Dataclass with hits, misses, evictions, expired, hit_rate |
Development
pip install -e .
python -m pytest tests/ -v
Support
If you find this project useful:
License
Metadata
Release files for philiprehberger-cache-kit 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| philiprehberger_cache_kit-0.5.0.tar.gz | 191.8 kB | Without provenance | Details for philiprehberger_cache_kit-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| philiprehberger_cache_kit-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for philiprehberger_cache_kit-0.5.0-py3-none-any.whl |
Total release size: 198.3 kB
Release files / philiprehberger_cache_kit-0.5.0.tar.gz
| Download URL | philiprehberger_cache_kit-0.5.0.tar.gz |
|---|---|
| Size | 191.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ce9bcb7b48b7683e25ee4500389711d33fe80cff3ed70052c694ee2c90c16b30
|
|
BLAKE2b-256 checksum How to use checksums |
081ed082bed500efb6ceba00a36c0caa6b1c17af4e8617107ada6375e8f9eee8
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Release files / philiprehberger_cache_kit-0.5.0-py3-none-any.whl
| Download URL | philiprehberger_cache_kit-0.5.0-py3-none-any.whl |
|---|---|
| Size | 6.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ef2ff65a6776d493f9e5fe13f5df0c5d508ef910b21473940c804fa2942f2af5
|
|
BLAKE2b-256 checksum How to use checksums |
2767c7baf94f42d90b4dc7ef1a7f30c32083a6aa7f073dfdcb780b1939945362
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.13
|
Security for philiprehberger-cache-kit 0.5.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.