[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