Skip to main content

UCROE (Use Cached Results On Exception)

UCROE (Use Cached Results On Exception) provides Python decorators that cache a function’s return value and reuse it if the function raises an exception on subsequent calls.

Features:

  • decorators to cache function return values and return them if subsequent calls raise an exception
  • multiple built-in cache backends (supports cachetools, Django)
  • compatible with tenacity, a retry library
  • configurable via decorator parameters, environment variables, and Django settings (if available)

UCROE is a standalone library. It doesn't require Django but works well with it.

To be implemented:

  • support async functions
  • support methods

Getting Started

Installation

pip install ucroe

Basic Usage

from ucroe import cached_result_on_exception


@cached_result_on_exception
def f1(): ...

Expected Behaviour When Cached Value Is Present

from ucroe import cached_result_on_exception
from unittest.mock import MagicMock

mock_http_call = MagicMock(side_effect=[1, 2, ValueError, 3, 4])


@cached_result_on_exception
def f():
    return mock_http_call()


assert f() == 1
assert f() == 2
assert f() == 2  # cached value is returned
assert f() == 3
assert f() == 4

Expected Behaviour When There Is No Cached Value

from unittest.mock import MagicMock

from ucroe import cached_result_on_exception

gen_fn = MagicMock(side_effect=[ValueError])  # raises during the 1st invocation


@cached_result_on_exception
def f():
    return gen_fn()


f()  # raises ValueError

Supported Configuration

UCROE supports the following configs, they can be configured as environment variables or Django settings, if available. In case of conflict, Django settings will take precedence.

  • UCROE_LOG_EXCEPTION_BY_DEFAULT: (default: False) when set, exception raised within the wrapped function will be logged with log level warning.
  • UCROE_BACKEND: (default: ucroe.cache_backend.cachetools.LRUBackend) the cache backend to use
  • UCROE_BACKEND_CONFIG: (default: '{"maxsize": 100}') JSON serialized string that will be used to instantiate the cache backend

Configuring Cache Backend

By default, @cached_result_on_exception uses ucroe.cache_backend.cachetools.LRUBackend, which itself is a wrapper of cachetools.LRUCache.

UCROE comes with a set of built-in backends:

  • ucroe.cache_backend.cachetools.FIFOBackend
  • ucroe.cache_backend.cachetools.LFUBackend
  • ucroe.cache_backend.cachetools.LRUBackend
  • ucroe.cache_backend.cachetools.RRBackend
  • ucroe.cache_backend.cachetools.TTLBackend
  • ucroe.cache_backend.cachetools.TLRUBackend
  • ucroe.cache_backend.django.DjangoBackend

Each cachetools backend is merely a wrapper to the corresponding cache provided by cachetools.

Using Django Backend

This library can be configured to use Django cache framework. To do so, simple specify ucroe.cache_backend.django.DjangoBackend as the cache backend. Eg:

# in your Django settings 
CACHES = {
    "default": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
    },
    "ucroe": {
        "BACKEND": "django.core.cache.backends.locmem.LocMemCache",
        "KEY_PREFIX": "ucroe_",
    },
}

# Add the following settings:
UCROE_BACKEND = "ucroe.cache_backend.django.DjangoBackend"
# Optionally, you can also specify the Django cache to use.
# When unspecified, the `default` cache will be used
UCROE_BACKEND_CONFIG = {"cache_name": "ucroe"}

In other parts of your code, simple import and decorate your functions with @cached_results_on_exception:

from ucroe import cached_result_on_exception


@cached_result_on_exception
def my_func(*args):
    ...

Using the decorators

It can be used with or without parenthesis

from ucroe import cached_result_on_exception


@cached_result_on_exception
def f1(): ...


@cached_result_on_exception()
def f2(): ...

It also accepts the following parameters:

  • log_exception: bool: when set to True, a warning log will emit when the wrapped function raises an exception
    from ucroe import cached_result_on_exception
    
    @cached_result_on_exception(log_exception=True)
    def f1(): ...
    
  • on_exception: Callable[[Exception], None]: a hook that will be called when the wrapped function raises
    import logging
    from ucroe import cached_result_on_exception
    
    logger = logging.getLogger(__name__)
    
    
    def on_exception(exc):
        logger.error("BOOM!", exc_info=exc)
    
    
    @cached_result_on_exception(on_exception=on_exception)
    def f1(): ...
    
    
    f1()  # If f1() raises, a log with message `error: BOOM!` and the stack trace will be emitted.
    

Metadata

Release files for ucroe 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 ucroe 0.1.0
File Size Uploaded Provenance
ucroe-0.1.0.tar.gz 7.5 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 15.6 kB

Release files / ucroe-0.1.0.tar.gz

Download URL ucroe-0.1.0.tar.gz
Size 7.5 kB
Tags Source
SHA-256 checksum
How to use checksums
21d49a49553b18bd121978d22abf683dcff41d9e7641562d9c6797e1398d7301
BLAKE2b-256 checksum
How to use checksums
88aa98f86cd25cdd33dcdca30ca60ace2b93e9eeeaaa892e92c89ac99e2d7262
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.4 CPython/3.10.12 Linux/6.5.0-1025-azure

Release files / ucroe-0.1.0-py3-none-any.whl

Download URL ucroe-0.1.0-py3-none-any.whl
Size 8.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
79f95c032c385e19ec5fc425f545910cf97650740ad82aa84575aaa2c65b769c
BLAKE2b-256 checksum
How to use checksums
40e7698e6458f281ae2f535b15933e0cf3337b01513cac3ce3a5a83686249bcc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.8.4 CPython/3.10.12 Linux/6.5.0-1025-azure

Security for ucroe 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.

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