Metadata-Version: 2.1
Name: autottlcache
Version: 1.0.0
Summary: Time-to-live (TTL) cache with auto-expiry
Home-page: https://github.com/sixty-north/autottlcache
Author: Sixty North AS
Author-email: rob@sixty-north.com
License: MIT License
Keywords: caching
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.7
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: cachetools
Provides-Extra: dev
Requires-Dist: check-manifest ; extra == 'dev'
Requires-Dist: wheel ; extra == 'dev'
Requires-Dist: bumpversion ; extra == 'dev'
Provides-Extra: doc
Requires-Dist: sphinx ; extra == 'doc'
Requires-Dist: sphinx-rtd-theme ; extra == 'doc'
Provides-Extra: test
Requires-Dist: coverage ; extra == 'test'
Requires-Dist: hypothesis ; extra == 'test'
Requires-Dist: pytest ; extra == 'test'

# autottlcache

A time-to-live (TTL) cache dictionary with auto-expiry.

# Installation

To install from PyPI:

  $ pip install autottlcache


# Usage


The TTL cache behaves very much like a dictionary. In fact, it is a `MutableMapping` so supports the
dictionary interface. It has one important difference though, which is that the items within it will
expire and automatically be removed.

Let's create an `AutoTTLCache` with a a maximum size of twelve entires, and a TTL of 30 seconds:

    >>> from autottlcache import AutoTTLCache
    >>> a = AutoTTLCache(maxsize=12, ttl=30.0)

We can add entries to the cache:

   >>> a[1] = 56
   >>> a[2] = 89
   >>> a[3] = 99
   >>> a[4] = 10
   >>> a[5] = 20

And watch them expire, by repeatedly asking the cache to list its keys:

    >>> list(a.keys())
    [2, 3, 4, 5]

We took long enough adding the keys that the first one had already expired:

    >>> list(a.keys())
    [3, 4, 5]

Now the second one has gone too:

    >>> list(a.keys())
    [3, 4, 5]

This time we're quick enough to get in before the third one expires:

    >>> list(a.keys())
    [3, 4, 5]
    >>> list(a.keys())
    [3, 4, 5]
    >>> list(a.keys())
    [3, 4, 5]
    >>> list(a.keys())
    [4, 5]
    >>> list(a.keys())
    [4, 5]
    >>> list(a.keys())
    [4, 5]
    >>> list(a.keys())
    [5]
    >>> list(a.keys())
    [5]
    >>> list(a.keys())
    [5]
    >>> list(a.keys())
    [5]
    >>> list(a.keys())
    [5]
    >>> list(a.keys())
    []

All gone.

Stale items are removed from the cache either when an operation on the cache object is invoked, such
as when an item is retrieved, or by a continuously running background thread that periodically
removes expired items. The cache will be checked with a frequency of ten times the TTL period, so
an item in a cache with a TTL of 30 seconds should live no longer than 33 seconds.

## Programming style

Owing to the fact that items will auto-expire, to avoid race conditions you should strongly prefer
an _Easier to Ask for Forgiveness than Permission_ (EAFP) programming style, rather than a _Look
Before You Leap_ (LBYL) style.

Risky race-condition:

    from autottlcache import AutoTTLCache
    cache = AutoTTLCache(maxsize=100, ttl=30)
    cache["daffodils"] = Image("daffodils-3280x2040.png")

    # ...

    if "daffodils" in cache:
        # What happens if "daffodils" expires here?
        image = cache["daffodils"]  # This could raise a key error which is unhandled
    else:
        print("No flowers for you!")


Better to use a single operation to retrieve an object, and handle the failure:

    from autottlcache import AutoTTLCache
    cache = AutoTTLCache(maxsize=100, ttl=30)
    cache["daffodils"] = Image("daffodils-3280x2040.png")

    # ...

    try:
        image = cache["daffodils"]
    except KeyError:
        print("No flowers for you!")
    else:
        display(image)


## Resource use

A single additional thread will be running during any periods for which one or more `AutoTTLCache`
objects are extant. The thread will start when the first `AutoTTLCache` is created, and will
terminate shortly after the last `AutoTTLCache` is finalized.


