cacheout
********
|version| |build| |coveralls| |license|
A caching library for Python.
Links
=====
- Project: https://github.com/dgilland/cacheout
- Documentation: https://cacheout.readthedocs.io
- PyPI: https://pypi.python.org/pypi/cacheout/
- Github Actions: https://github.com/dgilland/cacheout/actions
Features
========
- In-memory caching using dictionary backend
- Cache manager for easily accessing multiple cache objects
- Reconfigurable cache settings for runtime setup when using module-level cache objects
- Maximum cache size enforcement
- Default cache TTL (time-to-live) as well as custom TTLs per cache entry
- Bulk set, get, and delete operations
- Bulk get and delete operations filtered by string, regex, or function
- Memoization decorators
- Thread safe
- Multiple cache implementations:
- FIFO (First In, First Out)
- LIFO (Last In, First Out)
- LRU (Least Recently Used)
- MRU (Most Recently Used)
- LFU (Least Frequently Used)
- RR (Random Replacement)
Roadmap
=======
- Layered caching (multi-level caching)
Requirements
============
- Python >= 3.7
Quickstart
==========
Install using pip:
::
pip install cacheout
Let's start with some basic caching by creating a cache object:
.. code-block:: python
from cacheout import Cache
cache = Cache()
By default the ``cache`` object will have a maximum size of ``256``, default TTL (time-to-live) expiration turned off, TTL timer that uses ``time.time`` (meaning TTL is in seconds), and the default for missing keys as ``None``. These values can be set with:
.. code-block:: python
cache = Cache(maxsize=256, ttl=0, timer=time.time, default=None) # defaults
Set a cache key using ``cache.set()``:
.. code-block:: python
cache.set(1, 'foobar')
Get the value of a cache key with ``cache.get()``:
.. code-block:: python
assert cache.get(1) == 'foobar'
Get a default value when cache key isn't set:
.. code-block:: python
assert cache.get(2) is None
assert cache.get(2, default=False) is False
assert 2 not in cache
Provide cache values using a default callable:
.. code-block:: python
assert 2 not in cache
assert cache.get(2, default=lambda key: key) == 2
assert cache.get(2) == 2
assert 2 in cache
Provide a global default:
.. code-block:: python
cache2 = Cache(default=True)
assert cache2.get('missing') is True
assert 'missing' not in cache2
cache3 = Cache(default=lambda key: key)
assert cache3.get('missing') == 'missing'
assert 'missing' in cache3
Set the TTL (time-to-live) expiration per entry (default TTL units are in seconds when ``Cache.timer`` is set to the default ``time.time``; otherwise, the units are determined by the custom timer function):
.. code-block:: python
cache.set(3, {'data': {}}, ttl=1)
assert cache.get(3) == {'data': {}}
time.sleep(1)
assert cache.get(3) is None
Memoize a function where cache keys are generated from the called function parameters:
.. code-block:: python
@cache.memoize()
def func(a, b):
pass
Provide a TTL for the memoized function and incorporate argument types into generated cache keys:
.. code-block:: python
@cache.memoize(ttl=5, typed=True)
def func(a, b):
pass
# func(1, 2) has different cache key than func(1.0, 2.0), whereas,
# with "typed=False" (the default), they would have the same key
Access the original memoized function:
.. code-block:: python
@cache.memoize()
def func(a, b):
pass
func.uncached(1, 2)
Get a copy of the entire cache with ``cache.copy()``:
.. code-block:: python
assert cache.copy() == {1: 'foobar', 2: ('foo', 'bar', 'baz')}
Delete a cache key with ``cache.delete()``:
.. code-block:: python
cache.delete(1)
assert cache.get(1) is None
Clear the entire cache with ``cache.clear()``:
.. code-block:: python
cache.clear()
assert len(cache) == 0
Perform bulk operations with ``cache.set_many()``, ``cache.get_many()``, and ``cache.delete_many()``:
.. code-block:: python
cache.set_many({'a': 1, 'b': 2, 'c': 3})
assert cache.get_many(['a', 'b', 'c']) == {'a': 1, 'b': 2, 'c': 3}
cache.delete_many(['a', 'b', 'c'])
assert cache.count() == 0
Use complex filtering in ``cache.get_many()`` and ``cache.delete_many()``:
.. code-block:: python
import re
cache.set_many({'a_1': 1, 'a_2': 2, '123': 3, 'b': 4})
cache.get_many('a_*') == {'a_1': 1, 'a_2': 2}
cache.get_many(re.compile(r'\d')) == {'123': 3}
cache.get_many(lambda key: '2' in key) == {'a_2': 2, '123': 3}
cache.delete_many('a_*')
assert dict(cache.items()) == {'123': 3, 'b': 4}
Reconfigure the cache object after creation with ``cache.configure()``:
.. code-block:: python
cache.configure(maxsize=1000, ttl=5 * 60)
Get keys, values, and items from the cache with ``cache.keys()``, ``cache.values()``, and ``cache.items()``:
.. code-block:: python
cache.set_many({'a': 1, 'b': 2, 'c': 3})
assert list(cache.keys()) == ['a', 'b', 'c']
assert list(cache.values()) == [1, 2, 3]
assert list(cache.items()) == [('a', 1), ('b', 2), ('c', 3)]
Iterate over cache keys:
.. code-block:: python
for key in cache:
print(key, cache.get(key))
# 'a' 1
# 'b' 2
# 'c' 3
Check if key exists with ``cache.has()`` and ``key in cache``:
.. code-block:: python
assert cache.has('a')
assert 'a' in cache
Use callbacks to be notified of on-get, on-set, and on-delete events:
.. code-block:: python
def on_get(key, value, exists):
pass
def on_set(key, new_value, old_value):
pass
def on_delete(key, value, cause):
pass
Enable cache statistics:
.. code-block:: python
cache_with_stats = Cache(enable_stats=True)
# Or via configure()
cache.configure(enable_stats=True)
# Or directly via Cache.stats
cache.stats.enable()
Get cache statistics:
.. code-block:: python
print(cache.stats.info())
Manage tracking of statistics:
.. code-block:: python
# Pause tracking (collected stats will not be affected)
cache.stats.pause()
# Resume tracking
cache.stats.resume()
# Reset stats
cache.stats.reset()
# Disable stats (WARNING: This resets stats)
cache.stats.disable()
# Disable via configure() (WARNING: This resets stats)
cache.configure(enable_stats=False)
Manage multiple caches using ``CacheManager``:
.. code-block:: python
from cacheout import CacheManager
cacheman = CacheManager({'a': {'maxsize': 100},
'b': {'maxsize': 200, 'ttl': 900},
'c': {})
cacheman['a'].set('key1', 'value1')
value = cacheman['a'].get('key')
cacheman['b'].set('key2', 'value2')
assert cacheman['b'].maxsize == 200
assert cacheman['b'].ttl == 900
cacheman['c'].set('key3', 'value3')
cacheman.clear_all()
for name, cache in cacheman:
assert name in cacheman
assert len(cache) == 0
For more details, see the full documentation at https://cacheout.readthedocs.io.
.. |version| image:: https://img.shields.io/pypi/v/cacheout.svg?style=flat-square
:target: https://pypi.python.org/pypi/cacheout/
.. |build| image:: https://img.shields.io/github/actions/workflow/status/dgilland/cacheout/main.yml?branch=master&style=flat-square
:target: https://github.com/dgilland/cacheout/actions
.. |coveralls| image:: https://img.shields.io/coveralls/dgilland/cacheout/master.svg?style=flat-square
:target: https://coveralls.io/r/dgilland/cacheout
.. |license| image:: https://img.shields.io/pypi/l/cacheout.svg?style=flat-square
:target: https://pypi.python.org/pypi/cacheout/
Changelog
=========
v0.16.0 (2023-12-22)
--------------------
- Add ``Cache.on_get`` callback hook. Thanks uncle-lv_!
- Add ``Cache.on_set`` callback hook. Thanks uncle-lv_!
v0.15.0 (2023-11-03)
--------------------
- Add cache statistics. Thanks uncle-lv_!
- Add ``Cache.get_ttl``. Thanks uncle-lv_!
- Add ``Cache.on_delete`` callback hook. Thanks uncle-lv_!
- Add support for Python 3.11 and 3.12.
v0.14.1 (2022-08-16)
--------------------
- Set minimum Python version to 3.7 in setup.cfg.
v0.14.0 (2022-08-16)
--------------------
- Add support for Python 3.10.
- Drop support for Python 3.6. Minimum supported version is 3.7.
- Clarify docs around TTL to make it explicit what time units it uses by default.
v0.13.1 (2021-04-28)
--------------------
- Minor optimization in ``Cache.get_many|delete_many``.
v0.13.0 (2021-04-27)
--------------------
- Add ``cache_key`` attribute to memoized functions that can be used to generate the cache key used for a given set of function arguments. Thanks johnbergvall_!
- Fix bug in ``Cache.full`` that would result in an exception if cache created with ``maxsize=None`` like ``Cache(maxsize=None)``. Thanks AllinolCP_!
- Fix bug in ``Cache.get_many`` that resulted in ``RuntimeError: OrderedDict mutated during iteration`` when cache keys expire during the ``get_many`` call.
- Remove ``default`` argument from ``Cache.get_many``. A default value on missing cache key was only ever returned if a list of keys was passed in and those keys happened to expire during the ``get_many`` call. **breaking change**
v0.12.1 (2021-04-19)
--------------------
- Fix regression in ``0.12.0`` that resulted in missing docstrings for some methods of ``LFUCache`` and ``LRUCache``.
v0.12.0 (2021-04-19)
--------------------
- Fix bug in ``Cache.__contains__`` where it would return ``True`` for an expired key.
- Add type annotations.
- Add official support for Python 3.8 and 3.9.
- Drop support for Python 3.4 and 3.5.
v0.11.2 (2019-09-30)
--------------------
- Fix bug in ``LFUCache`` that would result cache growing beyond ``maxsize`` limit.
v0.11.1 (2019-01-09)
--------------------
- Fix issue with asyncio support in memoization decorators that caused a ``RuntimeError: await wasn't used with future`` when certain types of async functions were used inside the memoized function.
v0.11.0 (2018-10-19)
--------------------
- Add asyncio support to memoization decorators so they can decorate coroutines.
v0.10.3 (2018-08-01)
--------------------
- Expose ``typed`` argument of underlying ``*Cache.memoize()`` in ``memoize()`` and ``*_memoize()`` decorators.
v0.10.2 (2018-07-31)
--------------------
- Fix bug in ``LRUCache.get()`` where supplying a ``default`` value would result in a ``KeyError``.
v0.10.1 (2018-07-15)
--------------------
- Support Python 3.7.
v0.10.0 (2018-04-03)
--------------------
- Modify behavior of ``default`` argument to ``Cache.get()`` so that if ``default`` is a callable and the cache key is missing, then it will be called and its return value will be used as the value for cache key and subsequently be set as the value for the key in the cache. (**breaking change**)
- Add ``default`` argument to ``Cache()`` that can be used to override the value for ``default`` in ``Cache.get()``.
v0.9.0 (2018-03-31)
-------------------
- Merge functionality of ``Cache.get_many_by()`` into ``Cache.get_many()`` and remove ``Cache.get_many_by()``. (**breaking change**).
- Merge functionality of ``Cache.delete_many_by()`` into ``Cache.delete_many()`` and remove ``Cache.delete_many_by()``. (**breaking change**).
v0.8.0 (2018-03-30)
-------------------
- Add ``Cache.get_many_by()``.
- Add ``Cache.delete_many_by()``.
- Make ``Cache.keys()`` and ``Cache.values()`` return dictionary view objects instead of yielding items. (**breaking change**)
v0.7.0 (2018-02-22)
-------------------
- Changed default cache ``maxsize`` from ``300`` to ``256``. (**breaking change**)
- Add ``Cache.memoize()`` decorator.
- Add standalone memoization decorators:
- ``memoize``
- ``fifo_memoize``
- ``lfu_memoize``
- ``lifo_memoize``
- ``lru_memoize``
- ``mru_memoize``
- ``rr_memoize``
v0.6.0 (2018-02-05)
-------------------
- Add ``LIFOCache``
- Add ``FIFOCache`` as an alias of ``Cache``.
v0.5.0 (2018-02-04)
-------------------
- Add ``LFUCache``
- Delete expired items before popping an item in ``Cache.popitem()``.
v0.4.0 (2018-02-02)
-------------------
- Add ``MRUCache``
- Add ``RRCache``
- Add ``Cache.popitem()``.
- Rename ``Cache.expirations()`` to ``Cache.expire_times()``. (**breaking change**)
- Rename ``Cache.count()`` to ``Cache.size()``. (**breaking change**)
- Remove ``minimum`` arguement from ``Cache.evict()``. (**breaking change**)
v0.3.0 (2018-01-31)
-------------------
- Add ``LRUCache``.
- Add ``CacheManager.__repr__()``.
- Make threading lock usage in ``Cache`` more fine-grained and eliminate redundant locking.
- Fix missing thread-safety in ``Cache.__len__()`` and ``Cache.__contains__()``.
v0.2.0 (2018-01-30)
-------------------
- Rename ``Cache.setup()`` to ``Cache.configure()``. (**breaking change**)
- Add ``CacheManager`` class.
v0.1.0 (2018-01-28)
-------------------
- Add ``Cache`` class.
.. _johnbergvall: https://github.com/johnbergvall
.. _AllinolCP: https://github.com/AllinolCP
.. _uncle-lv: https://github.com/uncle-lv
MIT License
Copyright (c) 2020 Derrick Gilland
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Raw data
{
"_id": null,
"home_page": "https://github.com/dgilland/cacheout",
"name": "cacheout",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "cacheout cache caching memoize memoization fifo lifo lfu lru mru",
"author": "Derrick Gilland",
"author_email": "dgilland@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/d1/60/ed4c4b27b2131a0b2cc461789be2cf06866644ca462cb34a5d8fca114c15/cacheout-0.16.0.tar.gz",
"platform": null,
"description": "cacheout\n********\n\n|version| |build| |coveralls| |license|\n\n\nA caching library for Python.\n\n\nLinks\n=====\n\n- Project: https://github.com/dgilland/cacheout\n- Documentation: https://cacheout.readthedocs.io\n- PyPI: https://pypi.python.org/pypi/cacheout/\n- Github Actions: https://github.com/dgilland/cacheout/actions\n\n\nFeatures\n========\n\n- In-memory caching using dictionary backend\n- Cache manager for easily accessing multiple cache objects\n- Reconfigurable cache settings for runtime setup when using module-level cache objects\n- Maximum cache size enforcement\n- Default cache TTL (time-to-live) as well as custom TTLs per cache entry\n- Bulk set, get, and delete operations\n- Bulk get and delete operations filtered by string, regex, or function\n- Memoization decorators\n- Thread safe\n- Multiple cache implementations:\n\n - FIFO (First In, First Out)\n - LIFO (Last In, First Out)\n - LRU (Least Recently Used)\n - MRU (Most Recently Used)\n - LFU (Least Frequently Used)\n - RR (Random Replacement)\n\n\nRoadmap\n=======\n\n- Layered caching (multi-level caching)\n\n\nRequirements\n============\n\n- Python >= 3.7\n\n\nQuickstart\n==========\n\nInstall using pip:\n\n\n::\n\n pip install cacheout\n\n\nLet's start with some basic caching by creating a cache object:\n\n.. code-block:: python\n\n from cacheout import Cache\n\n cache = Cache()\n\n\nBy default the ``cache`` object will have a maximum size of ``256``, default TTL (time-to-live) expiration turned off, TTL timer that uses ``time.time`` (meaning TTL is in seconds), and the default for missing keys as ``None``. These values can be set with:\n\n.. code-block:: python\n\n cache = Cache(maxsize=256, ttl=0, timer=time.time, default=None) # defaults\n\n\nSet a cache key using ``cache.set()``:\n\n.. code-block:: python\n\n cache.set(1, 'foobar')\n\n\nGet the value of a cache key with ``cache.get()``:\n\n.. code-block:: python\n\n assert cache.get(1) == 'foobar'\n\n\nGet a default value when cache key isn't set:\n\n.. code-block:: python\n\n assert cache.get(2) is None\n assert cache.get(2, default=False) is False\n assert 2 not in cache\n\n\nProvide cache values using a default callable:\n\n.. code-block:: python\n\n assert 2 not in cache\n assert cache.get(2, default=lambda key: key) == 2\n assert cache.get(2) == 2\n assert 2 in cache\n\n\nProvide a global default:\n\n.. code-block:: python\n\n cache2 = Cache(default=True)\n assert cache2.get('missing') is True\n assert 'missing' not in cache2\n\n cache3 = Cache(default=lambda key: key)\n assert cache3.get('missing') == 'missing'\n assert 'missing' in cache3\n\n\nSet the TTL (time-to-live) expiration per entry (default TTL units are in seconds when ``Cache.timer`` is set to the default ``time.time``; otherwise, the units are determined by the custom timer function):\n\n.. code-block:: python\n\n cache.set(3, {'data': {}}, ttl=1)\n assert cache.get(3) == {'data': {}}\n time.sleep(1)\n assert cache.get(3) is None\n\n\nMemoize a function where cache keys are generated from the called function parameters:\n\n.. code-block:: python\n\n @cache.memoize()\n def func(a, b):\n pass\n\n\nProvide a TTL for the memoized function and incorporate argument types into generated cache keys:\n\n.. code-block:: python\n\n @cache.memoize(ttl=5, typed=True)\n def func(a, b):\n pass\n\n # func(1, 2) has different cache key than func(1.0, 2.0), whereas,\n # with \"typed=False\" (the default), they would have the same key\n\n\nAccess the original memoized function:\n\n.. code-block:: python\n\n @cache.memoize()\n def func(a, b):\n pass\n\n func.uncached(1, 2)\n\n\nGet a copy of the entire cache with ``cache.copy()``:\n\n.. code-block:: python\n\n assert cache.copy() == {1: 'foobar', 2: ('foo', 'bar', 'baz')}\n\n\nDelete a cache key with ``cache.delete()``:\n\n.. code-block:: python\n\n cache.delete(1)\n assert cache.get(1) is None\n\n\nClear the entire cache with ``cache.clear()``:\n\n.. code-block:: python\n\n cache.clear()\n assert len(cache) == 0\n\n\nPerform bulk operations with ``cache.set_many()``, ``cache.get_many()``, and ``cache.delete_many()``:\n\n.. code-block:: python\n\n cache.set_many({'a': 1, 'b': 2, 'c': 3})\n assert cache.get_many(['a', 'b', 'c']) == {'a': 1, 'b': 2, 'c': 3}\n cache.delete_many(['a', 'b', 'c'])\n assert cache.count() == 0\n\n\nUse complex filtering in ``cache.get_many()`` and ``cache.delete_many()``:\n\n.. code-block:: python\n\n import re\n cache.set_many({'a_1': 1, 'a_2': 2, '123': 3, 'b': 4})\n\n cache.get_many('a_*') == {'a_1': 1, 'a_2': 2}\n cache.get_many(re.compile(r'\\d')) == {'123': 3}\n cache.get_many(lambda key: '2' in key) == {'a_2': 2, '123': 3}\n\n cache.delete_many('a_*')\n assert dict(cache.items()) == {'123': 3, 'b': 4}\n\n\nReconfigure the cache object after creation with ``cache.configure()``:\n\n.. code-block:: python\n\n cache.configure(maxsize=1000, ttl=5 * 60)\n\n\nGet keys, values, and items from the cache with ``cache.keys()``, ``cache.values()``, and ``cache.items()``:\n\n.. code-block:: python\n\n cache.set_many({'a': 1, 'b': 2, 'c': 3})\n assert list(cache.keys()) == ['a', 'b', 'c']\n assert list(cache.values()) == [1, 2, 3]\n assert list(cache.items()) == [('a', 1), ('b', 2), ('c', 3)]\n\n\nIterate over cache keys:\n\n.. code-block:: python\n\n for key in cache:\n print(key, cache.get(key))\n # 'a' 1\n # 'b' 2\n # 'c' 3\n\n\nCheck if key exists with ``cache.has()`` and ``key in cache``:\n\n.. code-block:: python\n\n assert cache.has('a')\n assert 'a' in cache\n\n\nUse callbacks to be notified of on-get, on-set, and on-delete events:\n\n.. code-block:: python\n\n def on_get(key, value, exists):\n pass\n\n def on_set(key, new_value, old_value):\n pass\n\n def on_delete(key, value, cause):\n pass\n\n\nEnable cache statistics:\n\n.. code-block:: python\n\n cache_with_stats = Cache(enable_stats=True)\n\n # Or via configure()\n cache.configure(enable_stats=True)\n\n # Or directly via Cache.stats\n cache.stats.enable()\n\n\nGet cache statistics:\n\n.. code-block:: python\n\n print(cache.stats.info())\n\n\nManage tracking of statistics:\n\n.. code-block:: python\n\n # Pause tracking (collected stats will not be affected)\n cache.stats.pause()\n\n # Resume tracking\n cache.stats.resume()\n\n # Reset stats\n cache.stats.reset()\n\n # Disable stats (WARNING: This resets stats)\n cache.stats.disable()\n\n # Disable via configure() (WARNING: This resets stats)\n cache.configure(enable_stats=False)\n\n\nManage multiple caches using ``CacheManager``:\n\n.. code-block:: python\n\n from cacheout import CacheManager\n\n cacheman = CacheManager({'a': {'maxsize': 100},\n 'b': {'maxsize': 200, 'ttl': 900},\n 'c': {})\n\n cacheman['a'].set('key1', 'value1')\n value = cacheman['a'].get('key')\n\n cacheman['b'].set('key2', 'value2')\n assert cacheman['b'].maxsize == 200\n assert cacheman['b'].ttl == 900\n\n cacheman['c'].set('key3', 'value3')\n\n cacheman.clear_all()\n for name, cache in cacheman:\n assert name in cacheman\n assert len(cache) == 0\n\n\nFor more details, see the full documentation at https://cacheout.readthedocs.io.\n\n\n\n.. |version| image:: https://img.shields.io/pypi/v/cacheout.svg?style=flat-square\n :target: https://pypi.python.org/pypi/cacheout/\n\n.. |build| image:: https://img.shields.io/github/actions/workflow/status/dgilland/cacheout/main.yml?branch=master&style=flat-square\n :target: https://github.com/dgilland/cacheout/actions\n\n.. |coveralls| image:: https://img.shields.io/coveralls/dgilland/cacheout/master.svg?style=flat-square\n :target: https://coveralls.io/r/dgilland/cacheout\n\n.. |license| image:: https://img.shields.io/pypi/l/cacheout.svg?style=flat-square\n :target: https://pypi.python.org/pypi/cacheout/\n\nChangelog\n=========\n\n\nv0.16.0 (2023-12-22)\n--------------------\n\n- Add ``Cache.on_get`` callback hook. Thanks uncle-lv_!\n- Add ``Cache.on_set`` callback hook. Thanks uncle-lv_!\n\n\nv0.15.0 (2023-11-03)\n--------------------\n\n- Add cache statistics. Thanks uncle-lv_!\n- Add ``Cache.get_ttl``. Thanks uncle-lv_!\n- Add ``Cache.on_delete`` callback hook. Thanks uncle-lv_!\n- Add support for Python 3.11 and 3.12.\n\n\nv0.14.1 (2022-08-16)\n--------------------\n\n- Set minimum Python version to 3.7 in setup.cfg.\n\n\nv0.14.0 (2022-08-16)\n--------------------\n\n- Add support for Python 3.10.\n- Drop support for Python 3.6. Minimum supported version is 3.7.\n- Clarify docs around TTL to make it explicit what time units it uses by default.\n\n\nv0.13.1 (2021-04-28)\n--------------------\n\n- Minor optimization in ``Cache.get_many|delete_many``.\n\n\nv0.13.0 (2021-04-27)\n--------------------\n\n- Add ``cache_key`` attribute to memoized functions that can be used to generate the cache key used for a given set of function arguments. Thanks johnbergvall_!\n- Fix bug in ``Cache.full`` that would result in an exception if cache created with ``maxsize=None`` like ``Cache(maxsize=None)``. Thanks AllinolCP_!\n- Fix bug in ``Cache.get_many`` that resulted in ``RuntimeError: OrderedDict mutated during iteration`` when cache keys expire during the ``get_many`` call.\n- Remove ``default`` argument from ``Cache.get_many``. A default value on missing cache key was only ever returned if a list of keys was passed in and those keys happened to expire during the ``get_many`` call. **breaking change**\n\n\nv0.12.1 (2021-04-19)\n--------------------\n\n- Fix regression in ``0.12.0`` that resulted in missing docstrings for some methods of ``LFUCache`` and ``LRUCache``.\n\n\nv0.12.0 (2021-04-19)\n--------------------\n\n- Fix bug in ``Cache.__contains__`` where it would return ``True`` for an expired key.\n- Add type annotations.\n- Add official support for Python 3.8 and 3.9.\n- Drop support for Python 3.4 and 3.5.\n\n\nv0.11.2 (2019-09-30)\n--------------------\n\n- Fix bug in ``LFUCache`` that would result cache growing beyond ``maxsize`` limit.\n\n\nv0.11.1 (2019-01-09)\n--------------------\n\n- Fix issue with asyncio support in memoization decorators that caused a ``RuntimeError: await wasn't used with future`` when certain types of async functions were used inside the memoized function.\n\n\nv0.11.0 (2018-10-19)\n--------------------\n\n- Add asyncio support to memoization decorators so they can decorate coroutines.\n\n\nv0.10.3 (2018-08-01)\n--------------------\n\n- Expose ``typed`` argument of underlying ``*Cache.memoize()`` in ``memoize()`` and ``*_memoize()`` decorators.\n\n\nv0.10.2 (2018-07-31)\n--------------------\n\n- Fix bug in ``LRUCache.get()`` where supplying a ``default`` value would result in a ``KeyError``.\n\n\nv0.10.1 (2018-07-15)\n--------------------\n\n- Support Python 3.7.\n\n\nv0.10.0 (2018-04-03)\n--------------------\n\n- Modify behavior of ``default`` argument to ``Cache.get()`` so that if ``default`` is a callable and the cache key is missing, then it will be called and its return value will be used as the value for cache key and subsequently be set as the value for the key in the cache. (**breaking change**)\n- Add ``default`` argument to ``Cache()`` that can be used to override the value for ``default`` in ``Cache.get()``.\n\n\nv0.9.0 (2018-03-31)\n-------------------\n\n- Merge functionality of ``Cache.get_many_by()`` into ``Cache.get_many()`` and remove ``Cache.get_many_by()``. (**breaking change**).\n- Merge functionality of ``Cache.delete_many_by()`` into ``Cache.delete_many()`` and remove ``Cache.delete_many_by()``. (**breaking change**).\n\n\nv0.8.0 (2018-03-30)\n-------------------\n\n- Add ``Cache.get_many_by()``.\n- Add ``Cache.delete_many_by()``.\n- Make ``Cache.keys()`` and ``Cache.values()`` return dictionary view objects instead of yielding items. (**breaking change**)\n\n\nv0.7.0 (2018-02-22)\n-------------------\n\n- Changed default cache ``maxsize`` from ``300`` to ``256``. (**breaking change**)\n- Add ``Cache.memoize()`` decorator.\n- Add standalone memoization decorators:\n\n - ``memoize``\n - ``fifo_memoize``\n - ``lfu_memoize``\n - ``lifo_memoize``\n - ``lru_memoize``\n - ``mru_memoize``\n - ``rr_memoize``\n\n\nv0.6.0 (2018-02-05)\n-------------------\n\n- Add ``LIFOCache``\n- Add ``FIFOCache`` as an alias of ``Cache``.\n\n\nv0.5.0 (2018-02-04)\n-------------------\n\n- Add ``LFUCache``\n- Delete expired items before popping an item in ``Cache.popitem()``.\n\n\nv0.4.0 (2018-02-02)\n-------------------\n\n- Add ``MRUCache``\n- Add ``RRCache``\n- Add ``Cache.popitem()``.\n- Rename ``Cache.expirations()`` to ``Cache.expire_times()``. (**breaking change**)\n- Rename ``Cache.count()`` to ``Cache.size()``. (**breaking change**)\n- Remove ``minimum`` arguement from ``Cache.evict()``. (**breaking change**)\n\n\nv0.3.0 (2018-01-31)\n-------------------\n\n- Add ``LRUCache``.\n- Add ``CacheManager.__repr__()``.\n- Make threading lock usage in ``Cache`` more fine-grained and eliminate redundant locking.\n- Fix missing thread-safety in ``Cache.__len__()`` and ``Cache.__contains__()``.\n\n\nv0.2.0 (2018-01-30)\n-------------------\n\n- Rename ``Cache.setup()`` to ``Cache.configure()``. (**breaking change**)\n- Add ``CacheManager`` class.\n\n\nv0.1.0 (2018-01-28)\n-------------------\n\n- Add ``Cache`` class.\n\n\n.. _johnbergvall: https://github.com/johnbergvall\n.. _AllinolCP: https://github.com/AllinolCP\n.. _uncle-lv: https://github.com/uncle-lv\n\nMIT License\n\nCopyright (c) 2020 Derrick Gilland\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
"bugtrack_url": null,
"license": "MIT License",
"summary": "A caching library for Python",
"version": "0.16.0",
"project_urls": {
"Homepage": "https://github.com/dgilland/cacheout"
},
"split_keywords": [
"cacheout",
"cache",
"caching",
"memoize",
"memoization",
"fifo",
"lifo",
"lfu",
"lru",
"mru"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "7214a89bb55107b8a9b586c8878f47d0b7750c3688c209f05f915e70de74880d",
"md5": "3c22164ce46d429847280009d248817a",
"sha256": "1a52d9aa8b1e9720d8453b061348f15795578231f9ec4ad376fec49e717d0ed8"
},
"downloads": -1,
"filename": "cacheout-0.16.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "3c22164ce46d429847280009d248817a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 21837,
"upload_time": "2023-12-22T17:44:31",
"upload_time_iso_8601": "2023-12-22T17:44:31.556969Z",
"url": "https://files.pythonhosted.org/packages/72/14/a89bb55107b8a9b586c8878f47d0b7750c3688c209f05f915e70de74880d/cacheout-0.16.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d160ed4c4b27b2131a0b2cc461789be2cf06866644ca462cb34a5d8fca114c15",
"md5": "2d50305f83647958293d15d4cef0563b",
"sha256": "ee264897cbaa089ae5f406da11952697d99fa7f3583cfab69fe8a00ff8e1952d"
},
"downloads": -1,
"filename": "cacheout-0.16.0.tar.gz",
"has_sig": false,
"md5_digest": "2d50305f83647958293d15d4cef0563b",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 42050,
"upload_time": "2023-12-22T17:44:33",
"upload_time_iso_8601": "2023-12-22T17:44:33.290383Z",
"url": "https://files.pythonhosted.org/packages/d1/60/ed4c4b27b2131a0b2cc461789be2cf06866644ca462cb34a5d8fca114c15/cacheout-0.16.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-12-22 17:44:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "dgilland",
"github_project": "cacheout",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"tox": true,
"lcname": "cacheout"
}