[Python-modules-commits] [python-cachetools] 01/03: Import python-cachetools_1.1.5.orig.tar.gz
Christian Kastner
ckk at moszumanska.debian.org
Thu Nov 5 18:04:01 UTC 2015
This is an automated email from the git hooks/post-receive script.
ckk pushed a commit to branch master
in repository python-cachetools.
commit 8adefe855ba29bf8b6415c216e45da4cb20c0a7d
Author: Christian Kastner <ckk at kvr.at>
Date: Tue Nov 3 12:31:14 2015 +0100
Import python-cachetools_1.1.5.orig.tar.gz
---
.travis.yml | 3 +-
CHANGES.rst | 20 +++++++
cachetools/__init__.py | 4 +-
cachetools/{base.py => cache.py} | 41 +++++++++-----
cachetools/lfu.py | 2 +-
cachetools/lru.py | 84 +++++++++++-----------------
cachetools/rr.py | 2 +-
cachetools/ttl.py | 118 +++++++++++++++++++--------------------
docs/index.rst | 30 ++++++----
9 files changed, 162 insertions(+), 142 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index b8561a7..ed67c83 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,4 @@
+sudo: false
language: python
python:
- 2.7
@@ -6,7 +7,7 @@ python:
- 3.4
- 3.5-dev
install:
-- pip install . coverage coveralls flake8 flake8-import-order nose
+- pip install . "coverage<4" coveralls flake8 flake8-import-order nose
script:
- flake8
- nosetests
diff --git a/CHANGES.rst b/CHANGES.rst
index d83e8fa..dd8b751 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -1,3 +1,23 @@
+v1.1.5 (2015-10-25)
+-------------------
+
+- Refactor ``Cache`` base class. Note that this will break pickle
+ compatibility with previous versions.
+
+- Clean up ``LRUCache`` and ``TTLCache`` implementations.
+
+
+v1.1.4 (2015-10-24)
+-------------------
+
+- Refactor ``LRUCache`` and ``TTLCache`` implementations. Note that
+ this will break pickle compatibility with previous versions.
+
+- Document pending removal of deprecated features.
+
+- Minor documentation improvements.
+
+
v1.1.3 (2015-09-15)
-------------------
diff --git a/cachetools/__init__.py b/cachetools/__init__.py
index d90a28d..66d5735 100644
--- a/cachetools/__init__.py
+++ b/cachetools/__init__.py
@@ -3,7 +3,7 @@
import functools
import warnings
-from .base import Cache
+from .cache import Cache
from .func import lfu_cache, lru_cache, rr_cache, ttl_cache
from .keys import hashkey, typedkey
from .lfu import LFUCache
@@ -18,7 +18,7 @@ __all__ = (
'lfu_cache', 'lru_cache', 'rr_cache', 'ttl_cache',
)
-__version__ = '1.1.3'
+__version__ = '1.1.5'
_default = [] # evaluates to False
diff --git a/cachetools/base.py b/cachetools/cache.py
similarity index 79%
rename from cachetools/base.py
rename to cachetools/cache.py
index f0f8d5c..fbebbbe 100644
--- a/cachetools/base.py
+++ b/cachetools/cache.py
@@ -1,17 +1,31 @@
import collections
+class _DefaultSize(object):
+ def __getitem__(self, _):
+ return 1
+
+ def __setitem__(self, _, value):
+ assert value == 1
+
+ def pop(self, _):
+ return 1
+
+
class Cache(collections.MutableMapping):
"""Mutable mapping to serve as a simple cache or cache base class."""
+ __size = _DefaultSize()
+
def __init__(self, maxsize, missing=None, getsizeof=None):
- self.__data = dict()
- self.__currsize = 0
- self.__maxsize = maxsize
if missing:
self.__missing = missing
if getsizeof:
self.__getsizeof = getsizeof
+ self.__size = dict()
+ self.__data = dict()
+ self.__currsize = 0
+ self.__maxsize = maxsize
def __repr__(self):
return '%s(%r, maxsize=%d, currsize=%d)' % (
@@ -23,37 +37,38 @@ class Cache(collections.MutableMapping):
def __getitem__(self, key):
try:
- return self.__data[key][0]
+ return self.__data[key]
except KeyError:
return self.__missing__(key)
def __setitem__(self, key, value):
- data = self.__data
maxsize = self.__maxsize
size = self.getsizeof(value)
if size > maxsize:
raise ValueError('value too large')
- if key not in data or data[key][1] < size:
+ if key not in self.__data or self.__size[key] < size:
while self.__currsize + size > maxsize:
self.popitem()
- if key in data:
- diffsize = size - data[key][1]
+ if key in self.__data:
+ diffsize = size - self.__size[key]
else:
diffsize = size
- data[key] = (value, size)
+ self.__data[key] = value
+ self.__size[key] = size
self.__currsize += diffsize
def __delitem__(self, key):
- _, size = self.__data.pop(key)
+ size = self.__size.pop(key)
+ del self.__data[key]
self.__currsize -= size
def __contains__(self, key):
return key in self.__data
def __missing__(self, key):
- self.__setitem__(key, self.__missing(key))
- # return value as stored in data
- return self.__data[key][0]
+ value = self.__missing(key)
+ self.__setitem__(key, value)
+ return value
def __iter__(self):
return iter(self.__data)
diff --git a/cachetools/lfu.py b/cachetools/lfu.py
index 26a8b1e..d163cba 100644
--- a/cachetools/lfu.py
+++ b/cachetools/lfu.py
@@ -1,7 +1,7 @@
import collections
import operator
-from .base import Cache
+from .cache import Cache
class LFUCache(Cache):
diff --git a/cachetools/lru.py b/cachetools/lru.py
index 5cf52b1..f18f0b2 100644
--- a/cachetools/lru.py
+++ b/cachetools/lru.py
@@ -1,18 +1,23 @@
-from .base import Cache
+from .cache import Cache
class _Link(object):
- __slots__ = 'key', 'value', 'prev', 'next'
+ __slots__ = 'key', 'prev', 'next'
def __getstate__(self):
if hasattr(self, 'key'):
- return (self.key, self.value)
+ return (self.key,)
else:
return None
def __setstate__(self, state):
- self.key, self.value = state
+ self.key, = state
+
+ def insert(self, next):
+ self.next = next
+ self.prev = prev = next.prev
+ prev.next = next.prev = self
def unlink(self):
next = self.next
@@ -26,56 +31,42 @@ class LRUCache(Cache):
def __init__(self, maxsize, missing=None, getsizeof=None):
Cache.__init__(self, maxsize, missing, getsizeof)
- root = self.__root = _Link()
+ self.__root = root = _Link()
root.prev = root.next = root
+ self.__links = {}
def __repr__(self, cache_getitem=Cache.__getitem__):
# prevent item reordering
return '%s(%r, maxsize=%d, currsize=%d)' % (
self.__class__.__name__,
- [(key, cache_getitem(self, key).value) for key in self],
+ [(key, cache_getitem(self, key)) for key in self],
self.maxsize,
self.currsize,
)
def __getitem__(self, key, cache_getitem=Cache.__getitem__):
- link = cache_getitem(self, key)
- next = link.next
- prev = link.prev
- prev.next = next
- next.prev = prev
- link.next = root = self.__root
- link.prev = tail = root.prev
- tail.next = root.prev = link
- return link.value
-
- def __setitem__(self, key, value,
- cache_contains=Cache.__contains__,
- cache_getitem=Cache.__getitem__,
- cache_setitem=Cache.__setitem__):
- if cache_contains(self, key):
- oldlink = cache_getitem(self, key)
+ value = cache_getitem(self, key)
+ link = self.__links[key]
+ link.unlink()
+ link.insert(self.__root)
+ return value
+
+ def __setitem__(self, key, value, cache_setitem=Cache.__setitem__):
+ cache_setitem(self, key, value)
+ try:
+ link = self.__links[key]
+ except KeyError:
+ link = self.__links[key] = _Link()
else:
- oldlink = None
- link = _Link()
+ link.unlink()
link.key = key
- link.value = value
- cache_setitem(self, key, link)
- if oldlink:
- oldlink.unlink()
- link.next = root = self.__root
- link.prev = tail = root.prev
- tail.next = root.prev = link
-
- def __delitem__(self, key,
- cache_contains=Cache.__contains__,
- cache_getitem=Cache.__getitem__,
- cache_delitem=Cache.__delitem__):
- if not cache_contains(self, key):
- raise KeyError(key)
- link = cache_getitem(self, key)
+ link.insert(self.__root)
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
cache_delitem(self, key)
- link.unlink()
+ links = self.__links
+ links[key].unlink()
+ del links[key]
def __getstate__(self):
state = self.__dict__.copy()
@@ -95,20 +86,11 @@ class LRUCache(Cache):
link.next = links[(index + 1) % count]
self.__dict__.update(state)
- def getsizeof(self, value):
- """Return the size of a cache element's value."""
- if isinstance(value, _Link):
- return Cache.getsizeof(self, value.value)
- else:
- return Cache.getsizeof(self, value)
-
def popitem(self):
"""Remove and return the `(key, value)` pair least recently used."""
root = self.__root
link = root.next
if link is root:
- raise KeyError('cache is empty')
+ raise KeyError('%s is empty' % self.__class__.__name__)
key = link.key
- Cache.__delitem__(self, key)
- link.unlink()
- return (key, link.value)
+ return (key, self.pop(key))
diff --git a/cachetools/rr.py b/cachetools/rr.py
index 4b3bcc6..143223b 100644
--- a/cachetools/rr.py
+++ b/cachetools/rr.py
@@ -1,6 +1,6 @@
import random
-from .base import Cache
+from .cache import Cache
class RRCache(Cache):
diff --git a/cachetools/ttl.py b/cachetools/ttl.py
index e65a3a3..57c8f9c 100644
--- a/cachetools/ttl.py
+++ b/cachetools/ttl.py
@@ -1,37 +1,56 @@
import functools
import time
-from .base import Cache
+from .cache import Cache
class _Link(object):
__slots__ = (
- 'key', 'value', 'expire', 'size',
+ 'key', 'expire', 'size',
'ttl_prev', 'ttl_next',
'lru_prev', 'lru_next'
)
def __getstate__(self):
if hasattr(self, 'key'):
- return (self.key, self.value, self.expire, self.size)
+ return (self.key, self.expire, self.size)
else:
return None
def __setstate__(self, state):
- self.key, self.value, self.expire, self.size = state
+ self.key, self.expire, self.size = state
- def unlink(self):
- ttl_next = self.ttl_next
- ttl_prev = self.ttl_prev
- ttl_prev.ttl_next = ttl_next
- ttl_next.ttl_prev = ttl_prev
+ def insert_lru(self, next):
+ self.lru_next = next
+ self.lru_prev = prev = next.lru_prev
+ prev.lru_next = next.lru_prev = self
+ def insert_ttl(self, next):
+ self.ttl_next = next
+ self.ttl_prev = prev = next.ttl_prev
+ prev.ttl_next = next.ttl_prev = self
+
+ def insert(self, next):
+ self.insert_lru(next)
+ self.insert_ttl(next)
+
+ def unlink_lru(self):
lru_next = self.lru_next
lru_prev = self.lru_prev
lru_prev.lru_next = lru_next
lru_next.lru_prev = lru_prev
+ def unlink_ttl(self):
+ ttl_next = self.ttl_next
+ ttl_prev = self.ttl_prev
+ ttl_prev.ttl_next = ttl_next
+ ttl_next.ttl_prev = ttl_prev
+
+ def unlink(self):
+ self.unlink_lru()
+ self.unlink_ttl()
+
class _NestedTimer(object):
@@ -70,9 +89,10 @@ class TTLCache(Cache):
def __init__(self, maxsize, ttl, timer=time.time, missing=None,
getsizeof=None):
Cache.__init__(self, maxsize, missing, getsizeof)
- root = self.__root = _Link()
+ self.__root = root = _Link()
root.ttl_prev = root.ttl_next = root
root.lru_prev = root.lru_next = root
+ self.__links = {}
self.__timer = _NestedTimer(timer)
self.__ttl = ttl
@@ -80,7 +100,7 @@ class TTLCache(Cache):
# prevent item reordering/expiration
return '%s(%r, maxsize=%d, currsize=%d)' % (
self.__class__.__name__,
- [(key, cache_getitem(self, key).value) for key in self],
+ [(key, cache_getitem(self, key)) for key in self],
self.maxsize,
self.currsize,
)
@@ -89,63 +109,44 @@ class TTLCache(Cache):
cache_getitem=Cache.__getitem__,
cache_missing=Cache.__missing__):
with self.__timer as time:
- link = cache_getitem(self, key)
+ value = cache_getitem(self, key)
+ link = self.__links[key]
if link.expire < time:
- return cache_missing(self, key).value
- next = link.lru_next
- prev = link.lru_prev
- prev.lru_next = next
- next.lru_prev = prev
- link.lru_next = root = self.__root
- link.lru_prev = tail = root.lru_prev
- tail.lru_next = root.lru_prev = link
- return link.value
+ return cache_missing(self, key)
+ link.unlink_lru()
+ link.insert_lru(self.__root)
+ return value
def __setitem__(self, key, value,
- cache_contains=Cache.__contains__,
- cache_getitem=Cache.__getitem__,
cache_setitem=Cache.__setitem__,
cache_getsizeof=Cache.getsizeof):
with self.__timer as time:
self.expire(time)
- if cache_contains(self, key):
- oldlink = cache_getitem(self, key)
+ cache_setitem(self, key, value)
+ try:
+ link = self.__links[key]
+ except KeyError:
+ link = self.__links[key] = _Link()
else:
- oldlink = None
- link = _Link()
+ link.unlink()
link.key = key
- link.value = value
link.expire = time + self.__ttl
link.size = cache_getsizeof(self, value)
- cache_setitem(self, key, link)
- if oldlink:
- oldlink.unlink()
- link.ttl_next = root = self.__root
- link.ttl_prev = tail = root.ttl_prev
- tail.ttl_next = root.ttl_prev = link
- link.lru_next = root
- link.lru_prev = tail = root.lru_prev
- tail.lru_next = root.lru_prev = link
-
- def __delitem__(self, key,
- cache_contains=Cache.__contains__,
- cache_getitem=Cache.__getitem__,
- cache_delitem=Cache.__delitem__):
+ link.insert(self.__root)
+
+ def __delitem__(self, key, cache_delitem=Cache.__delitem__):
with self.__timer as time:
self.expire(time)
- if not cache_contains(self, key):
- raise KeyError(key)
- link = cache_getitem(self, key)
cache_delitem(self, key)
- link.unlink()
+ links = self.__links
+ links[key].unlink()
+ del links[key]
- def __contains__(self, key,
- cache_contains=Cache.__contains__,
- cache_getitem=Cache.__getitem__):
+ def __contains__(self, key):
with self.__timer as time:
- if not cache_contains(self, key):
+ if key not in self.__links:
return False
- elif cache_getitem(self, key).expire < time:
+ elif self.__links[key].expire < time:
return False
else:
return True
@@ -216,20 +217,15 @@ class TTLCache(Cache):
time = self.__timer()
root = self.__root
head = root.ttl_next
+ links = self.__links
cache_delitem = Cache.__delitem__
while head is not root and head.expire < time:
cache_delitem(self, head.key)
+ del links[head.key]
next = head.ttl_next
head.unlink()
head = next
- def getsizeof(self, value):
- """Return the size of a cache element's value."""
- if isinstance(value, _Link):
- return value.size
- else:
- return Cache.getsizeof(self, value)
-
def popitem(self):
"""Remove and return the `(key, value)` pair least recently used that
has not already expired.
@@ -240,11 +236,9 @@ class TTLCache(Cache):
root = self.__root
link = root.lru_next
if link is root:
- raise KeyError('cache is empty')
+ raise KeyError('%s is empty' % self.__class__.__name__)
key = link.key
- Cache.__delitem__(self, key)
- link.unlink()
- return (key, link.value)
+ return (key, self.pop(key))
# mixin methods
diff --git a/docs/index.rst b/docs/index.rst
index 83a1559..9c209b7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -21,6 +21,14 @@ Multiple cache classes based on different caching algorithms are
implemented, and decorators for easily memoizing function and method
calls are provided, too.
+.. note::
+
+ Several features are now marked as deprecated and will be removed
+ in the next major release, :mod:`cachetools` version 2.0. If you
+ happen to rely on any of these features, it is highly recommended
+ to specify your module dependencies accordingly, for example
+ ``cachetools ~= 1.1`` when using :mod:`setuptools`.
+
.. versionchanged:: 1.1
Moved :func:`functools.lru_cache` compatible decorators to the
@@ -144,7 +152,7 @@ of one argument used to retrieve the size of an item's value.
Decorators
------------------------------------------------------------------------
-The :mod:`cachetools` module provides decorators for easily caching
+The :mod:`cachetools` module provides decorators for memoizing
function and method calls. This can save time when a function is
often called with the same arguments::
@@ -204,8 +212,8 @@ often called with the same arguments::
lock = RLock()
@cached(cache, lock=lock)
- def foo(n):
- return n + 1 # expensive operation here...
+ def fib(n):
+ return n if n < 2 else fib(n - 1) + fib(n - 2)
# make sure access to cache is synchronized
with lock:
@@ -221,16 +229,16 @@ often called with the same arguments::
cache = LRUCache(maxsize=100)
- @cached(cache, key=partial(hashkey, 'foo'))
- def foo(n):
- return n + n
+ @cached(cache, key=partial(hashkey, 'fib'))
+ def fib(n):
+ return n if n < 2 else fib(n - 1) + fib(n - 2)
- @cached(cache, key=partial(hashkey, 'bar'))
- def bar(n):
- return n * n
+ @cached(cache, key=partial(hashkey, 'fac'))
+ def fac(n):
+ return 1 if n == 0 else n * fac(n - 1)
- foo(42)
- bar(42)
+ print(fib(42))
+ print(fac(42))
print(cache)
.. versionadded:: 1.1
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-cachetools.git
More information about the Python-modules-commits
mailing list