ucroe


Nameucroe JSON
Version 0.1.0 PyPI version JSON
download
home_pageNone
Summarya Python decorator that caches a function’s return value and reuses it if the function raises an exception on subsequent calls
upload_time2024-10-22 02:02:17
maintainerNone
docs_urlNone
authorMelvin Koh
requires_python<4.0,>=3.10
licenseMIT
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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](https://tenacity.readthedocs.io/en/latest/), 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

```shell
pip install ucroe
```

## Basic Usage

```python
from ucroe import cached_result_on_exception


@cached_result_on_exception
def f1(): ...
```

### Expected Behaviour When Cached Value Is Present

```python
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

```python
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`](https://cachetools.readthedocs.io/en/latest/#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:

```python
# 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`:

```python
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

```python
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
  ```python
  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
  ```python
  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.
  ```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "ucroe",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0,>=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Melvin Koh",
    "author_email": "melvinkcx@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/88/aa/98f86cd25cdd33dcdca30ca60ace2b93e9eeeaaa892e92c89ac99e2d7262/ucroe-0.1.0.tar.gz",
    "platform": null,
    "description": "# UCROE (Use Cached Results On Exception)\n\nUCROE (Use Cached Results On Exception) provides Python decorators that cache a function\u2019s return value and reuse it if\nthe\nfunction raises an exception on subsequent calls.\n\nFeatures:\n\n- decorators to cache function return values and return them if subsequent calls raise an exception\n- multiple built-in cache backends (supports cachetools, Django)\n- compatible with [tenacity](https://tenacity.readthedocs.io/en/latest/), a retry library\n- configurable via decorator parameters, environment variables, and Django settings (if available)\n\n> UCROE is a standalone library. It doesn't require Django but works well with it.\n\nTo be implemented:\n\n- support async functions\n- support methods\n\n---\n\n# Getting Started\n\n## Installation\n\n```shell\npip install ucroe\n```\n\n## Basic Usage\n\n```python\nfrom ucroe import cached_result_on_exception\n\n\n@cached_result_on_exception\ndef f1(): ...\n```\n\n### Expected Behaviour When Cached Value Is Present\n\n```python\nfrom ucroe import cached_result_on_exception\nfrom unittest.mock import MagicMock\n\nmock_http_call = MagicMock(side_effect=[1, 2, ValueError, 3, 4])\n\n\n@cached_result_on_exception\ndef f():\n    return mock_http_call()\n\n\nassert f() == 1\nassert f() == 2\nassert f() == 2  # cached value is returned\nassert f() == 3\nassert f() == 4\n```\n\n### Expected Behaviour When There Is No Cached Value\n\n```python\nfrom unittest.mock import MagicMock\n\nfrom ucroe import cached_result_on_exception\n\ngen_fn = MagicMock(side_effect=[ValueError])  # raises during the 1st invocation\n\n\n@cached_result_on_exception\ndef f():\n    return gen_fn()\n\n\nf()  # raises ValueError\n```\n\n## Supported Configuration\n\nUCROE supports the following configs, they can be configured as environment variables or Django settings, if available.\nIn case of conflict, Django settings will take precedence.\n\n- `UCROE_LOG_EXCEPTION_BY_DEFAULT`: (default: `False`) when set, exception raised within the wrapped function will be\n  logged with log level `warning`.\n- `UCROE_BACKEND`: (default: `ucroe.cache_backend.cachetools.LRUBackend`) the cache backend to use\n- `UCROE_BACKEND_CONFIG`: (default: `'{\"maxsize\": 100}'`) JSON serialized string that will be used to instantiate the\n  cache backend\n\n## Configuring Cache Backend\n\nBy default, `@cached_result_on_exception` uses `ucroe.cache_backend.cachetools.LRUBackend`, which itself is a wrapper\nof [`cachetools.LRUCache`](https://cachetools.readthedocs.io/en/latest/#cachetools.LRUCache).\n\nUCROE comes with a set of built-in backends:\n\n- `ucroe.cache_backend.cachetools.FIFOBackend`\n- `ucroe.cache_backend.cachetools.LFUBackend`\n- `ucroe.cache_backend.cachetools.LRUBackend`\n- `ucroe.cache_backend.cachetools.RRBackend`\n- `ucroe.cache_backend.cachetools.TTLBackend`\n- `ucroe.cache_backend.cachetools.TLRUBackend`\n- `ucroe.cache_backend.django.DjangoBackend`\n\nEach cachetools backend is merely a wrapper to the corresponding cache provided by cachetools.\n\n### Using Django Backend\n\nThis library can be configured to use Django cache framework.\nTo do so, simple specify `ucroe.cache_backend.django.DjangoBackend` as the cache backend. Eg:\n\n```python\n# in your Django settings \nCACHES = {\n    \"default\": {\n        \"BACKEND\": \"django.core.cache.backends.locmem.LocMemCache\",\n    },\n    \"ucroe\": {\n        \"BACKEND\": \"django.core.cache.backends.locmem.LocMemCache\",\n        \"KEY_PREFIX\": \"ucroe_\",\n    },\n}\n\n# Add the following settings:\nUCROE_BACKEND = \"ucroe.cache_backend.django.DjangoBackend\"\n# Optionally, you can also specify the Django cache to use.\n# When unspecified, the `default` cache will be used\nUCROE_BACKEND_CONFIG = {\"cache_name\": \"ucroe\"}\n```\n\nIn other parts of your code, simple import and decorate your functions with `@cached_results_on_exception`:\n\n```python\nfrom ucroe import cached_result_on_exception\n\n\n@cached_result_on_exception\ndef my_func(*args):\n    ...\n```\n\n## Using the decorators\n\nIt can be used with or without parenthesis\n\n```python\nfrom ucroe import cached_result_on_exception\n\n\n@cached_result_on_exception\ndef f1(): ...\n\n\n@cached_result_on_exception()\ndef f2(): ...\n```\n\nIt also accepts the following parameters:\n\n- `log_exception: bool`: when set to `True`, a warning log will emit when the wrapped function raises an exception\n  ```python\n  from ucroe import cached_result_on_exception\n  \n  @cached_result_on_exception(log_exception=True)\n  def f1(): ...\n  ```\n- `on_exception: Callable[[Exception], None]`: a hook that will be called when the wrapped function raises\n  ```python\n  import logging\n  from ucroe import cached_result_on_exception\n  \n  logger = logging.getLogger(__name__)\n  \n  \n  def on_exception(exc):\n      logger.error(\"BOOM!\", exc_info=exc)\n  \n  \n  @cached_result_on_exception(on_exception=on_exception)\n  def f1(): ...\n  \n  \n  f1()  # If f1() raises, a log with message `error: BOOM!` and the stack trace will be emitted.\n  ```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "a Python decorator that caches a function\u2019s return value and reuses it if the function raises an exception on subsequent calls",
    "version": "0.1.0",
    "project_urls": null,
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "40e7698e6458f281ae2f535b15933e0cf3337b01513cac3ce3a5a83686249bcc",
                "md5": "8b98c74aa954faf2b1ce92c760c723aa",
                "sha256": "79f95c032c385e19ec5fc425f545910cf97650740ad82aa84575aaa2c65b769c"
            },
            "downloads": -1,
            "filename": "ucroe-0.1.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8b98c74aa954faf2b1ce92c760c723aa",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0,>=3.10",
            "size": 8155,
            "upload_time": "2024-10-22T02:02:15",
            "upload_time_iso_8601": "2024-10-22T02:02:15.802639Z",
            "url": "https://files.pythonhosted.org/packages/40/e7/698e6458f281ae2f535b15933e0cf3337b01513cac3ce3a5a83686249bcc/ucroe-0.1.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "88aa98f86cd25cdd33dcdca30ca60ace2b93e9eeeaaa892e92c89ac99e2d7262",
                "md5": "4254f1dfa05803cde6209b5d70484293",
                "sha256": "21d49a49553b18bd121978d22abf683dcff41d9e7641562d9c6797e1398d7301"
            },
            "downloads": -1,
            "filename": "ucroe-0.1.0.tar.gz",
            "has_sig": false,
            "md5_digest": "4254f1dfa05803cde6209b5d70484293",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0,>=3.10",
            "size": 7492,
            "upload_time": "2024-10-22T02:02:17",
            "upload_time_iso_8601": "2024-10-22T02:02:17.246206Z",
            "url": "https://files.pythonhosted.org/packages/88/aa/98f86cd25cdd33dcdca30ca60ace2b93e9eeeaaa892e92c89ac99e2d7262/ucroe-0.1.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-10-22 02:02:17",
    "github": false,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "lcname": "ucroe"
}
        
Elapsed time: 9.64298s