Unforgettable is a simple cache you can used for tiny repetitive executions.
Project description
Unforgettable - v0.2.0
Unforgettable is a tiny file-backed cache for Python code that repeats small pieces of work. It is useful for local scripts, notebooks, tests, prototypes, and automation where a value is expensive or annoying to compute more than once.
The library has no runtime dependencies and exposes one main class:
unforgettable.
Installation
Install with uv:
uv add unforgettable
Or with pip:
pip install unforgettable
Unforgettable requires Python 3.11 or newer.
Quick Start
from unforgettable import unforgettable
cache = unforgettable()
cached_value = cache.get(cache_id="expensive-operation")
if cached_value is None:
cached_value = "computed result"
cache.set(content=cached_value, cache_id="expensive-operation")
print(cached_value)
get() returns the cached value when it exists. If there is no value for that
cache_id, it returns None.
Use list() to inspect the cache IDs currently available in a cache folder.
from unforgettable import unforgettable
cache = unforgettable()
cache.set(content="computed result", cache_id="expensive-operation")
assert cache.list() == ["expensive-operation"]
Cache Text
from unforgettable import unforgettable
cache = unforgettable()
cache.set(content="hello", cache_id="greeting")
assert cache.get(cache_id="greeting") == "hello"
Cache Bytes
from unforgettable import unforgettable
cache = unforgettable()
content = b"\x80\x81cached bytes"
cache.set(content=content, cache_id="binary-value")
assert cache.get(cache_id="binary-value") == content
Persistent Cache Folder
By default, each cache instance creates its own temporary directory with
tempfile. Use cache_folder when you want cached values to persist across
Python process runs.
import os
from unforgettable import unforgettable
cache_dir = os.environ.get("UNFORGETTABLE_CACHE_DIR", ".unforgettable-cache")
cache = unforgettable(cache_folder=cache_dir)
cache.set(content="saved between runs", cache_id="stable-key")
Creating a new cache instance with the same folder can read values written by the previous instance.
from unforgettable import unforgettable
first_cache = unforgettable(cache_folder=".unforgettable-cache")
first_cache.set(content="persisted", cache_id="example")
second_cache = unforgettable(cache_folder=".unforgettable-cache")
assert second_cache.get(cache_id="example") == "persisted"
Command Line
Installing the package exposes an unforgettable command.
CLI commands use .unforgettable-memory in the current working directory by
default, so you can run commands without passing --cache-folder:
unforgettable set greeting "hello"
unforgettable get greeting
Pass --cache-folder to use a different persistent cache folder:
unforgettable --cache-folder .unforgettable-cache list
When an explicitly selected cache folder does not exist, the CLI asks before
creating it. Answer y or yes to create the folder and continue; any other
answer exits without creating the folder or changing cache contents.
The list command prints one cache ID per line and prints nothing when the
selected cache folder has no user-created entries.
Store text under a cache ID:
unforgettable --cache-folder .unforgettable-cache set greeting "hello"
Retrieve cached text:
unforgettable --cache-folder .unforgettable-cache get greeting
Clean the selected cache folder:
unforgettable --cache-folder .unforgettable-cache clean
get exits with status code 1 when the requested cache ID is missing.
Custom Cache File Extension
Cache content files use the cache extension by default. You can choose a
different extension when creating the cache instance.
from unforgettable import unforgettable
cache = unforgettable(
cache_folder=".unforgettable-cache",
cache_files_extension="txt",
)
cache.set(content="inspectable text", cache_id="example")
Cleaning A Cache
Call clean() on a cache instance to remove the files in that instance's cache
folder.
from unforgettable import unforgettable
cache = unforgettable(cache_folder=".unforgettable-cache")
cache.set(content="temporary", cache_id="example")
cache.clean()
HTTP Request Example
This example caches successful HTTP responses by URL. Failed requests are not cached.
import requests
from unforgettable import unforgettable
cache = unforgettable(cache_folder=".request-cache")
def requests_get(url: str) -> bytes | None:
cached_response = cache.get(cache_id=url)
if cached_response is not None:
return cached_response
response = requests.get(url=url, timeout=5)
if response.status_code != 200:
return None
cache.set(content=response.content, cache_id=url)
return response.content
url = "https://github.com/bouli/unforgettable"
first_response = requests_get(url)
second_response = requests_get(url)
API Reference
unforgettable(cache_folder=None, cache_files_extension=None)
Creates a cache instance.
cache_folder: optional folder for cache files. When omitted, the instance uses a temporary directory.cache_files_extension: optional extension for stored cache content files. Defaults tocache.
cache.set(content, cache_id)
Stores content under cache_id.
contentcan bestrorbytes.- Calling
set()again with the samecache_idoverwrites the existing cached content.
cache.get(cache_id)
Returns the cached value for cache_id.
- Returns
strfor text files. - Returns
bytesfor binary files. - Returns
Nonewhen the cache entry does not exist.
cache.list()
Returns a list[str] containing user-created cache IDs available in the cache
folder.
- Returns an empty list when no user cache entries exist.
- Omits internal cache index bookkeeping.
- Preserves cache IDs with spaces and punctuation.
cache.clean()
Removes files from the cache instance's folder.
Development
Install dependencies:
uv sync --dev
Run tests:
make tests
Run the coverage report:
make report
Build the package:
make build
See Also
License
This package is distributed under the MIT license.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file unforgettable-0.2.0.tar.gz.
File metadata
- Download URL: unforgettable-0.2.0.tar.gz
- Upload date:
- Size: 7.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b68af07f7bdcbfee7d99141d1b058128199f0068cfd979aa5c867d3bfeebbf40
|
|
| MD5 |
fb027de332080fda4e89dc960076d27f
|
|
| BLAKE2b-256 |
2c395bb84a504a05aea6009d1f677e4de91393e00b1fb7b42419349c0731fc34
|
Provenance
The following attestation bundles were made for unforgettable-0.2.0.tar.gz:
Publisher:
publish-pypi.yml on bouli/unforgettable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
unforgettable-0.2.0.tar.gz -
Subject digest:
b68af07f7bdcbfee7d99141d1b058128199f0068cfd979aa5c867d3bfeebbf40 - Sigstore transparency entry: 1735745273
- Sigstore integration time:
-
Permalink:
bouli/unforgettable@4ab5edc5630491331a0d2ca90b9da91dcc8e9419 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bouli
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@4ab5edc5630491331a0d2ca90b9da91dcc8e9419 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file unforgettable-0.2.0-py3-none-any.whl.
File metadata
- Download URL: unforgettable-0.2.0-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d3c486c227e49f72d405e2094436de38583c3d2690b3b31bbd7c675d694019f5
|
|
| MD5 |
1801728156840fe92a3cc6597908bb0b
|
|
| BLAKE2b-256 |
b27ee77fa2220dc59ad0e56d99b1cd3aa312d0df227c8a0c55c8e9facd7b1c42
|
Provenance
The following attestation bundles were made for unforgettable-0.2.0-py3-none-any.whl:
Publisher:
publish-pypi.yml on bouli/unforgettable
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
unforgettable-0.2.0-py3-none-any.whl -
Subject digest:
d3c486c227e49f72d405e2094436de38583c3d2690b3b31bbd7c675d694019f5 - Sigstore transparency entry: 1735745347
- Sigstore integration time:
-
Permalink:
bouli/unforgettable@4ab5edc5630491331a0d2ca90b9da91dcc8e9419 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bouli
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@4ab5edc5630491331a0d2ca90b9da91dcc8e9419 -
Trigger Event:
workflow_dispatch
-
Statement type: