Skip to main content

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 to cache.

cache.set(content, cache_id)

Stores content under cache_id.

  • content can be str or bytes.
  • Calling set() again with the same cache_id overwrites the existing cached content.

cache.get(cache_id)

Returns the cached value for cache_id.

  • Returns str for text files.
  • Returns bytes for binary files.
  • Returns None when 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

unforgettable-0.2.0.tar.gz (7.5 kB view details)

Uploaded Source

Built Distribution

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

unforgettable-0.2.0-py3-none-any.whl (6.3 kB view details)

Uploaded Python 3

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

Hashes for unforgettable-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b68af07f7bdcbfee7d99141d1b058128199f0068cfd979aa5c867d3bfeebbf40
MD5 fb027de332080fda4e89dc960076d27f
BLAKE2b-256 2c395bb84a504a05aea6009d1f677e4de91393e00b1fb7b42419349c0731fc34

See more details on using hashes here.

Provenance

The following attestation bundles were made for unforgettable-0.2.0.tar.gz:

Publisher: publish-pypi.yml on bouli/unforgettable

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for unforgettable-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d3c486c227e49f72d405e2094436de38583c3d2690b3b31bbd7c675d694019f5
MD5 1801728156840fe92a3cc6597908bb0b
BLAKE2b-256 b27ee77fa2220dc59ad0e56d99b1cd3aa312d0df227c8a0c55c8e9facd7b1c42

See more details on using hashes here.

Provenance

The following attestation bundles were made for unforgettable-0.2.0-py3-none-any.whl:

Publisher: publish-pypi.yml on bouli/unforgettable

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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