Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Fixed #21012 -- New API to access cache backends.

Thanks Curtis Malony and Florian Apolloner.

Squashed commit of the following:

commit 3380495
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date:   Sat Nov 23 14:18:07 2013 +0100

    Looked up the template_fragments cache at runtime.

commit 905a74f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date:   Sat Nov 23 14:19:48 2013 +0100

    Removed all uses of create_cache.

    Refactored the cache tests significantly.

    Made it safe to override the CACHES setting.

commit 35e289f
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date:   Sat Nov 23 12:23:57 2013 +0100

    Removed create_cache function.

commit 8e274f7
Author: Aymeric Augustin <aymeric.augustin@m4x.org>
Date:   Sat Nov 23 12:04:52 2013 +0100

    Updated docs to describe a simplified cache backend API.

commit ee7eb0f
Author: Curtis Maloney <curtis@tinbrain.net>
Date:   Sat Oct 19 09:49:24 2013 +1100

    Fixed #21012 -- Thread-local caches, like databases.
  • Loading branch information...
commit ffc37e2343a93cf6d44247e20cd263b41f931716 1 parent 3ca0815
@funkybob funkybob authored aaugustin committed
View
4 django/contrib/sessions/backends/cache.py
@@ -1,6 +1,6 @@
from django.conf import settings
from django.contrib.sessions.backends.base import SessionBase, CreateError
-from django.core.cache import get_cache
+from django.core.cache import caches
from django.utils.six.moves import xrange
KEY_PREFIX = "django.contrib.sessions.cache"
@@ -11,7 +11,7 @@ class SessionStore(SessionBase):
A cache-based session store.
"""
def __init__(self, session_key=None):
- self._cache = get_cache(settings.SESSION_CACHE_ALIAS)
+ self._cache = caches[settings.SESSION_CACHE_ALIAS]
super(SessionStore, self).__init__(session_key)
@property
View
4 django/contrib/sessions/backends/cached_db.py
@@ -6,7 +6,7 @@
from django.conf import settings
from django.contrib.sessions.backends.db import SessionStore as DBStore
-from django.core.cache import get_cache
+from django.core.cache import caches
from django.core.exceptions import SuspiciousOperation
from django.utils import timezone
from django.utils.encoding import force_text
@@ -20,7 +20,7 @@ class SessionStore(DBStore):
"""
def __init__(self, session_key=None):
- self._cache = get_cache(settings.SESSION_CACHE_ALIAS)
+ self._cache = caches[settings.SESSION_CACHE_ALIAS]
super(SessionStore, self).__init__(session_key)
@property
View
11 django/contrib/sessions/tests.py
@@ -15,7 +15,7 @@
from django.contrib.sessions.backends.signed_cookies import SessionStore as CookieSession
from django.contrib.sessions.models import Session
from django.contrib.sessions.middleware import SessionMiddleware
-from django.core.cache import get_cache
+from django.core.cache import caches
from django.core.cache.backends.base import InvalidCacheBackendError
from django.core import management
from django.core.exceptions import ImproperlyConfigured
@@ -140,7 +140,7 @@ def test_clear(self):
self.assertTrue(self.session.modified)
def test_save(self):
- if (hasattr(self.session, '_cache') and'DummyCache' in
+ if (hasattr(self.session, '_cache') and 'DummyCache' in
settings.CACHES[settings.SESSION_CACHE_ALIAS]['BACKEND']):
raise unittest.SkipTest("Session saving tests require a real cache backend")
self.session.save()
@@ -481,7 +481,7 @@ def test_load_overlong_key(self):
def test_default_cache(self):
self.session.save()
- self.assertNotEqual(get_cache('default').get(self.session.cache_key), None)
+ self.assertNotEqual(caches['default'].get(self.session.cache_key), None)
@override_settings(CACHES={
'default': {
@@ -489,6 +489,7 @@ def test_default_cache(self):
},
'sessions': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
+ 'LOCATION': 'session',
},
}, SESSION_CACHE_ALIAS='sessions')
def test_non_default_cache(self):
@@ -496,8 +497,8 @@ def test_non_default_cache(self):
self.session = self.backend()
self.session.save()
- self.assertEqual(get_cache('default').get(self.session.cache_key), None)
- self.assertNotEqual(get_cache('sessions').get(self.session.cache_key), None)
+ self.assertEqual(caches['default'].get(self.session.cache_key), None)
+ self.assertNotEqual(caches['sessions'].get(self.session.cache_key), None)
class SessionMiddlewareTests(unittest.TestCase):
View
4 django/contrib/staticfiles/storage.py
@@ -7,7 +7,7 @@
import re
from django.conf import settings
-from django.core.cache import (get_cache, InvalidCacheBackendError,
+from django.core.cache import (caches, InvalidCacheBackendError,
cache as default_cache)
from django.core.exceptions import ImproperlyConfigured
from django.core.files.base import ContentFile
@@ -56,7 +56,7 @@ class CachedFilesMixin(object):
def __init__(self, *args, **kwargs):
super(CachedFilesMixin, self).__init__(*args, **kwargs)
try:
- self.cache = get_cache('staticfiles')
+ self.cache = caches['staticfiles']
except InvalidCacheBackendError:
# Use the default backend
self.cache = default_cache
View
76 django/core/cache/__init__.py
@@ -6,14 +6,15 @@
may be pickled -- identified by string keys. For the complete API, see
the abstract BaseCache class in django.core.cache.backends.base.
-Client code should not access a cache backend directly; instead it should
-either use the "cache" variable made available here, or it should use the
-get_cache() function made available here. get_cache() takes a CACHES alias or a
-backend path and config parameters, and returns an instance of a backend cache
-class.
+Client code should use the `cache` variable defined here to access the default
+cache backend and look up non-default cache backends in the `caches` dict-like
+object.
See docs/topics/cache.txt for information on the public API.
"""
+from threading import local
+import warnings
+
from django.conf import settings
from django.core import signals
from django.core.cache.backends.base import (
@@ -35,14 +36,14 @@
def get_cache(backend, **kwargs):
"""
- Function to load a cache backend dynamically. This is flexible by design
+ Function to create a cache backend dynamically. This is flexible by design
to allow different use cases:
To load a backend that is pre-defined in the settings::
cache = get_cache('default')
- To load a backend with its dotted import path,
+ To create a backend with its dotted import path,
including arbitrary options::
cache = get_cache('django.core.cache.backends.memcached.MemcachedCache', **{
@@ -50,6 +51,12 @@ def get_cache(backend, **kwargs):
})
"""
+ warnings.warn("'get_cache' is deprecated in favor of 'caches'.",
+ PendingDeprecationWarning, stacklevel=2)
+ return _create_cache(backend, **kwargs)
+
+
+def _create_cache(backend, **kwargs):
try:
# Try to get the CACHES entry for the given backend name first
try:
@@ -79,4 +86,57 @@ def get_cache(backend, **kwargs):
signals.request_finished.connect(cache.close)
return cache
-cache = get_cache(DEFAULT_CACHE_ALIAS)
+
+class CacheHandler(object):
+ """
+ A Cache Handler to manage access to Cache instances.
+
+ Ensures only one instance of each alias exists per thread.
+ """
+ def __init__(self):
+ self._caches = local()
+
+ def __getitem__(self, alias):
+ try:
+ return getattr(self._caches, alias)
+ except AttributeError:
+ pass
+
+ if alias not in settings.CACHES:
+ raise InvalidCacheBackendError(
+ "Could not find config for '%s' in settings.CACHES" % alias
+ )
+
+ cache = _create_cache(alias)
+ setattr(self._caches, alias, cache)
+
+ return cache
+
+caches = CacheHandler()
+
+class DefaultCacheProxy(object):
+ """
+ Proxy access to the default Cache object's attributes.
+
+ This allows the legacy `cache` object to be thread-safe using the new
+ ``caches`` API.
+ """
+ def __getattr__(self, name):
+ return getattr(caches[DEFAULT_CACHE_ALIAS], name)
+
+ def __setattr__(self, name, value):
+ return setattr(caches[DEFAULT_CACHE_ALIAS], name, value)
+
+ def __delattr__(self, name):
+ return delattr(caches[DEFAULT_CACHE_ALIAS], name)
+
+ def __contains__(self, key):
+ return key in caches[DEFAULT_CACHE_ALIAS]
+
+ def __eq__(self, other):
+ return caches[DEFAULT_CACHE_ALIAS] == other
+
+ def __ne__(self, other):
+ return caches[DEFAULT_CACHE_ALIAS] != other
+
+cache = DefaultCacheProxy()
View
14 django/core/cache/backends/memcached.py
@@ -2,13 +2,13 @@
import time
import pickle
-from threading import local
from django.core.cache.backends.base import BaseCache, DEFAULT_TIMEOUT
from django.utils import six
from django.utils.deprecation import RenameMethodsBase
from django.utils.encoding import force_str
+from django.utils.functional import cached_property
class BaseMemcachedCacheMethods(RenameMethodsBase):
@@ -177,24 +177,14 @@ class PyLibMCCache(BaseMemcachedCache):
"An implementation of a cache binding using pylibmc"
def __init__(self, server, params):
import pylibmc
- self._local = local()
super(PyLibMCCache, self).__init__(server, params,
library=pylibmc,
value_not_found_exception=pylibmc.NotFound)
- @property
+ @cached_property
def _cache(self):
- # PylibMC uses cache options as the 'behaviors' attribute.
- # It also needs to use threadlocals, because some versions of
- # PylibMC don't play well with the GIL.
- client = getattr(self._local, 'client', None)
- if client:
- return client
-
client = self._lib.Client(self._servers)
if self._options:
client.behaviors = self._options
- self._local.client = client
-
return client
View
4 django/core/management/commands/createcachetable.py
@@ -1,7 +1,7 @@
from optparse import make_option
from django.conf import settings
-from django.core.cache import get_cache
+from django.core.cache import caches
from django.core.cache.backends.db import BaseDatabaseCache
from django.core.management.base import BaseCommand, CommandError
from django.db import connections, router, transaction, models, DEFAULT_DB_ALIAS
@@ -30,7 +30,7 @@ def handle(self, *tablenames, **options):
self.create_table(db, tablename)
else:
for cache_alias in settings.CACHES:
- cache = get_cache(cache_alias)
+ cache = caches[cache_alias]
if isinstance(cache, BaseDatabaseCache):
self.create_table(db, cache._table)
View
48 django/middleware/cache.py
@@ -46,7 +46,7 @@
import warnings
from django.conf import settings
-from django.core.cache import get_cache, DEFAULT_CACHE_ALIAS
+from django.core.cache import caches, DEFAULT_CACHE_ALIAS
from django.utils.cache import get_cache_key, learn_cache_key, patch_response_headers, get_max_age
@@ -64,7 +64,7 @@ def __init__(self):
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
- self.cache = get_cache(self.cache_alias)
+ self.cache = caches[self.cache_alias]
def _session_accessed(self, request):
try:
@@ -122,10 +122,9 @@ class FetchFromCacheMiddleware(object):
MIDDLEWARE_CLASSES so that it'll get called last during the request phase.
"""
def __init__(self):
- self.cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
- self.cache = get_cache(self.cache_alias)
+ self.cache = caches[self.cache_alias]
def process_request(self, request):
"""
@@ -169,39 +168,32 @@ def __init__(self, cache_timeout=None, cache_anonymous_only=None, **kwargs):
# we fall back to system defaults. If it is not provided at all,
# we need to use middleware defaults.
- cache_kwargs = {}
-
try:
- self.key_prefix = kwargs['key_prefix']
- if self.key_prefix is not None:
- cache_kwargs['KEY_PREFIX'] = self.key_prefix
- else:
- self.key_prefix = ''
+ key_prefix = kwargs['key_prefix']
+ if key_prefix is None:
+ key_prefix = ''
except KeyError:
- self.key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
- cache_kwargs['KEY_PREFIX'] = self.key_prefix
+ key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
+ self.key_prefix = key_prefix
try:
- self.cache_alias = kwargs['cache_alias']
- if self.cache_alias is None:
- self.cache_alias = DEFAULT_CACHE_ALIAS
- if cache_timeout is not None:
- cache_kwargs['TIMEOUT'] = cache_timeout
+ cache_alias = kwargs['cache_alias']
+ if cache_alias is None:
+ cache_alias = DEFAULT_CACHE_ALIAS
except KeyError:
- self.cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
- if cache_timeout is None:
- cache_kwargs['TIMEOUT'] = settings.CACHE_MIDDLEWARE_SECONDS
- else:
- cache_kwargs['TIMEOUT'] = cache_timeout
+ cache_alias = settings.CACHE_MIDDLEWARE_ALIAS
+ self.cache_alias = cache_alias
+
+ if cache_timeout is None:
+ cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
+ self.cache_timeout = cache_timeout
if cache_anonymous_only is None:
- self.cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
- else:
- self.cache_anonymous_only = cache_anonymous_only
+ cache_anonymous_only = getattr(settings, 'CACHE_MIDDLEWARE_ANONYMOUS_ONLY', False)
+ self.cache_anonymous_only = cache_anonymous_only
if self.cache_anonymous_only:
msg = "CACHE_MIDDLEWARE_ANONYMOUS_ONLY has been deprecated and will be removed in Django 1.8."
warnings.warn(msg, DeprecationWarning, stacklevel=1)
- self.cache = get_cache(self.cache_alias, **cache_kwargs)
- self.cache_timeout = self.cache.default_timeout
+ self.cache = caches[self.cache_alias]
View
19 django/templatetags/cache.py
@@ -1,16 +1,11 @@
from __future__ import unicode_literals
-from django.core.cache import get_cache, InvalidCacheBackendError
+from django.core.cache import cache, caches, InvalidCacheBackendError
from django.core.cache.utils import make_template_fragment_key
from django.template import Library, Node, TemplateSyntaxError, VariableDoesNotExist
register = Library()
-try:
- default_cache = get_cache('template_fragments')
-except InvalidCacheBackendError:
- from django.core.cache import cache as default_cache
-
class CacheNode(Node):
def __init__(self, nodelist, expire_time_var, fragment_name, vary_on, cache_name):
@@ -35,17 +30,21 @@ def render(self, context):
except VariableDoesNotExist:
raise TemplateSyntaxError('"cache" tag got an unknown variable: %r' % self.cache_name.var)
try:
- cache = get_cache(cache_name)
+ fragment_cache = caches[cache_name]
except InvalidCacheBackendError:
raise TemplateSyntaxError('Invalid cache name specified for cache tag: %r' % cache_name)
else:
- cache = default_cache
+ try:
+ fragment_cache = caches['template_fragments']
+ except InvalidCacheBackendError:
+ fragment_cache = caches['default']
+
vary_on = [var.resolve(context) for var in self.vary_on]
cache_key = make_template_fragment_key(self.fragment_name, vary_on)
- value = cache.get(cache_key)
+ value = fragment_cache.get(cache_key)
if value is None:
value = self.nodelist.render(context)
- cache.set(cache_key, value, expire_time)
+ fragment_cache.set(cache_key, value, expire_time)
return value
View
8 django/test/signals.py
@@ -1,5 +1,6 @@
import os
import time
+import threading
import warnings
from django.conf import settings
@@ -20,6 +21,13 @@
@receiver(setting_changed)
+def clear_cache_handlers(**kwargs):
+ if kwargs['setting'] == 'CACHES':
+ from django.core.cache import caches
+ caches._caches = threading.local()
+
+
+@receiver(setting_changed)
def update_connections_time_zone(**kwargs):
if kwargs['setting'] == 'TIME_ZONE':
# Reset process time zone
View
6 django/utils/cache.py
@@ -23,7 +23,7 @@
import time
from django.conf import settings
-from django.core.cache import get_cache
+from django.core.cache import caches
from django.utils.encoding import iri_to_uri, force_bytes, force_text
from django.utils.http import http_date
from django.utils.timezone import get_current_timezone_name
@@ -219,7 +219,7 @@ def get_cache_key(request, key_prefix=None, method='GET', cache=None):
key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
cache_key = _generate_cache_header_key(key_prefix, request)
if cache is None:
- cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
+ cache = caches[settings.CACHE_MIDDLEWARE_ALIAS]
headerlist = cache.get(cache_key, None)
if headerlist is not None:
return _generate_cache_key(request, method, headerlist, key_prefix)
@@ -246,7 +246,7 @@ def learn_cache_key(request, response, cache_timeout=None, key_prefix=None, cach
cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
cache_key = _generate_cache_header_key(key_prefix, request)
if cache is None:
- cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
+ cache = caches[settings.CACHE_MIDDLEWARE_ALIAS]
if response.has_header('Vary'):
is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N
# If i18n or l10n are used, the generated cache key will be suffixed
View
5 docs/internals/deprecation.txt
@@ -114,7 +114,7 @@ these changes.
no longer appears to be actively maintained & does not work on Python 3.
You are advised to install `Pillow`_, which should be used instead.
-.. _`Pillow`: https://pypi.python.org/pypi/Pillow
+ .. _`Pillow`: https://pypi.python.org/pypi/Pillow
* The following private APIs will be removed:
@@ -215,6 +215,9 @@ these changes.
* The internal ``django.utils.functional.memoize`` will be removed.
+* ``django.core.cache.get_cache`` will be removed. Add suitable entries
+ to :setting:`CACHES` and use :data:`django.core.cache.caches` instead.
+
2.0
---
View
18 docs/releases/1.7.txt
@@ -269,6 +269,18 @@ Minor features
allowing the ``published`` element to be included in the feed (which
relies on ``pubdate``).
+Cache
+^^^^^
+
+* Access to caches configured in :setting:`CACHES` is now available via
+ :data:`django.core.cache.caches`. This dict-like object provides a different
+ instance per thread. It supersedes :func:`django.core.cache.get_cache` which
+ is now deprecated.
+
+* If you instanciate cache backends directly, be aware that they aren't
+ thread-safe any more, as :data:`django.core.cache.caches` now yields
+ differend instances per thread.
+
Email
^^^^^
@@ -643,6 +655,12 @@ Miscellaneous
Features deprecated in 1.7
==========================
+``django.core.cache.get_cache``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:func:`django.core.cache.get_cache` has been supplanted by
+:data:`django.core.cache.caches`.
+
``django.utils.dictconfig``/``django.utils.importlib``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
View
48 docs/topics/cache.txt
@@ -703,22 +703,50 @@ pickling.)
Accessing the cache
-------------------
-.. function:: django.core.cache.get_cache(backend, **kwargs)
+.. data:: django.core.cache.caches
-The cache module, ``django.core.cache``, has a ``cache`` object that's
-automatically created from the ``'default'`` entry in the :setting:`CACHES`
-setting::
+ .. versionadded:: 1.7
- >>> from django.core.cache import cache
+ You can access the caches configured in the :setting:`CACHES` setting
+ through a dict-like object: ``django.core.cache.caches``. Repeated
+ requests for the same alias in the same thread will return the same
+ object.
+
+ >>> from django.core.cache import caches
+ >>> cache1 = caches['myalias']
+ >>> cache2 = caches['myalias']
+ >>> cache1 is cache2
+ True
+
+ If the named key does not exist, ``InvalidCacheBackendError`` will be
+ raised.
+
+ To provide thread-safety, a different instance of the cache backend will
+ be returned for each thread.
-If you have multiple caches defined in :setting:`CACHES`, then you can use
-:func:`django.core.cache.get_cache` to retrieve a cache object for any key::
+.. data:: django.core.cache.cache
+
+ As a shortcut, the default cache is available as
+ ``django.core.cache.cache``::
+
+ >>> from django.core.cache import cache
+
+ This object is equivalent to ``caches['default']``.
+
+.. function:: django.core.cache.get_cache(backend, **kwargs)
- >>> from django.core.cache import get_cache
- >>> cache = get_cache('alternate')
+ .. deprecated:: 1.7
+ This function has been deprecated in favour of
+ :data:`~django.core.cache.caches`.
-If the named key does not exist, ``InvalidCacheBackendError`` will be raised.
+ Before Django 1.7 this function was the canonical way to obtain a cache
+ instance. It could also be used to create a new cache instance with a
+ different configuration.
+ >>> from django.core.cache import get_cache
+ >>> get_cache('default')
+ >>> get_cache('django.core.cache.backends.memcached.MemcachedCache', LOCATION='127.0.0.2')
+ >>> get_cache('default', TIMEOUT=300)
Basic usage
-----------
View
1,080 tests/cache/tests.py
@@ -8,17 +8,17 @@
import pickle
import random
import re
+import shutil
import string
import tempfile
+import threading
import time
import unittest
import warnings
from django.conf import settings
from django.core import management
-from django.core.cache import get_cache
-from django.core.cache.backends.base import (CacheKeyWarning,
- InvalidCacheBackendError)
+from django.core.cache import cache, caches, CacheKeyWarning, InvalidCacheBackendError
from django.db import connection, router, transaction
from django.core.cache.utils import make_template_fragment_key
from django.http import HttpResponse, StreamingHttpResponse
@@ -27,7 +27,8 @@
from django.template import Template
from django.template.response import TemplateResponse
from django.test import TestCase, TransactionTestCase, RequestFactory
-from django.test.utils import override_settings, IgnoreDeprecationWarningsMixin
+from django.test.utils import (override_settings, IgnoreDeprecationWarningsMixin,
+ IgnorePendingDeprecationWarningsMixin)
from django.utils import six
from django.utils import timezone
from django.utils import translation
@@ -49,72 +50,73 @@ def m(n):
return 24
-class DummyCacheTests(unittest.TestCase):
+@override_settings(CACHES={
+ 'default': {
+ 'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
+ }
+})
+class DummyCacheTests(TestCase):
# The Dummy cache backend doesn't really behave like a test backend,
- # so it has different test requirements.
- backend_name = 'django.core.cache.backends.dummy.DummyCache'
-
- def setUp(self):
- self.cache = get_cache(self.backend_name)
+ # so it has its own test case.
def test_simple(self):
"Dummy cache backend ignores cache set calls"
- self.cache.set("key", "value")
- self.assertEqual(self.cache.get("key"), None)
+ cache.set("key", "value")
+ self.assertEqual(cache.get("key"), None)
def test_add(self):
"Add doesn't do anything in dummy cache backend"
- self.cache.add("addkey1", "value")
- result = self.cache.add("addkey1", "newvalue")
+ cache.add("addkey1", "value")
+ result = cache.add("addkey1", "newvalue")
self.assertEqual(result, True)
- self.assertEqual(self.cache.get("addkey1"), None)
+ self.assertEqual(cache.get("addkey1"), None)
def test_non_existent(self):
"Non-existent keys aren't found in the dummy cache backend"
- self.assertEqual(self.cache.get("does_not_exist"), None)
- self.assertEqual(self.cache.get("does_not_exist", "bang!"), "bang!")
+ self.assertEqual(cache.get("does_not_exist"), None)
+ self.assertEqual(cache.get("does_not_exist", "bang!"), "bang!")
def test_get_many(self):
"get_many returns nothing for the dummy cache backend"
- self.cache.set('a', 'a')
- self.cache.set('b', 'b')
- self.cache.set('c', 'c')
- self.cache.set('d', 'd')
- self.assertEqual(self.cache.get_many(['a', 'c', 'd']), {})
- self.assertEqual(self.cache.get_many(['a', 'b', 'e']), {})
+ cache.set('a', 'a')
+ cache.set('b', 'b')
+ cache.set('c', 'c')
+ cache.set('d', 'd')
+ self.assertEqual(cache.get_many(['a', 'c', 'd']), {})
+ self.assertEqual(cache.get_many(['a', 'b', 'e']), {})
def test_delete(self):
"Cache deletion is transparently ignored on the dummy cache backend"
- self.cache.set("key1", "spam")
- self.cache.set("key2", "eggs")
- self.assertEqual(self.cache.get("key1"), None)
- self.cache.delete("key1")
- self.assertEqual(self.cache.get("key1"), None)
- self.assertEqual(self.cache.get("key2"), None)
+ cache.set("key1", "spam")
+ cache.set("key2", "eggs")
+ self.assertEqual(cache.get("key1"), None)
+ cache.delete("key1")
+ self.assertEqual(cache.get("key1"), None)
+ self.assertEqual(cache.get("key2"), None)
def test_has_key(self):
"The has_key method doesn't ever return True for the dummy cache backend"
- self.cache.set("hello1", "goodbye1")
- self.assertEqual(self.cache.has_key("hello1"), False)
- self.assertEqual(self.cache.has_key("goodbye1"), False)
+ cache.set("hello1", "goodbye1")
+ self.assertEqual(cache.has_key("hello1"), False)
+ self.assertEqual(cache.has_key("goodbye1"), False)
def test_in(self):
"The in operator doesn't ever return True for the dummy cache backend"
- self.cache.set("hello2", "goodbye2")
- self.assertEqual("hello2" in self.cache, False)
- self.assertEqual("goodbye2" in self.cache, False)
+ cache.set("hello2", "goodbye2")
+ self.assertEqual("hello2" in cache, False)
+ self.assertEqual("goodbye2" in cache, False)
def test_incr(self):
"Dummy cache values can't be incremented"
- self.cache.set('answer', 42)
- self.assertRaises(ValueError, self.cache.incr, 'answer')
- self.assertRaises(ValueError, self.cache.incr, 'does_not_exist')
+ cache.set('answer', 42)
+ self.assertRaises(ValueError, cache.incr, 'answer')
+ self.assertRaises(ValueError, cache.incr, 'does_not_exist')
def test_decr(self):
"Dummy cache values can't be decremented"
- self.cache.set('answer', 42)
- self.assertRaises(ValueError, self.cache.decr, 'answer')
- self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
+ cache.set('answer', 42)
+ self.assertRaises(ValueError, cache.decr, 'answer')
+ self.assertRaises(ValueError, cache.decr, 'does_not_exist')
def test_data_types(self):
"All data types are ignored equally by the dummy cache"
@@ -127,21 +129,21 @@ def test_data_types(self):
'function': f,
'class': C,
}
- self.cache.set("stuff", stuff)
- self.assertEqual(self.cache.get("stuff"), None)
+ cache.set("stuff", stuff)
+ self.assertEqual(cache.get("stuff"), None)
def test_expiration(self):
"Expiration has no effect on the dummy cache"
- self.cache.set('expire1', 'very quickly', 1)
- self.cache.set('expire2', 'very quickly', 1)
- self.cache.set('expire3', 'very quickly', 1)
+ cache.set('expire1', 'very quickly', 1)
+ cache.set('expire2', 'very quickly', 1)
+ cache.set('expire3', 'very quickly', 1)
time.sleep(2)
- self.assertEqual(self.cache.get("expire1"), None)
+ self.assertEqual(cache.get("expire1"), None)
- self.cache.add("expire2", "newvalue")
- self.assertEqual(self.cache.get("expire2"), None)
- self.assertEqual(self.cache.has_key("expire3"), False)
+ cache.add("expire2", "newvalue")
+ self.assertEqual(cache.get("expire2"), None)
+ self.assertEqual(cache.has_key("expire3"), False)
def test_unicode(self):
"Unicode values are ignored by the dummy cache"
@@ -152,33 +154,57 @@ def test_unicode(self):
'ascii2': {'x': 1}
}
for (key, value) in stuff.items():
- self.cache.set(key, value)
- self.assertEqual(self.cache.get(key), None)
+ cache.set(key, value)
+ self.assertEqual(cache.get(key), None)
def test_set_many(self):
"set_many does nothing for the dummy cache backend"
- self.cache.set_many({'a': 1, 'b': 2})
- self.cache.set_many({'a': 1, 'b': 2}, timeout=2, version='1')
+ cache.set_many({'a': 1, 'b': 2})
+ cache.set_many({'a': 1, 'b': 2}, timeout=2, version='1')
def test_delete_many(self):
"delete_many does nothing for the dummy cache backend"
- self.cache.delete_many(['a', 'b'])
+ cache.delete_many(['a', 'b'])
def test_clear(self):
"clear does nothing for the dummy cache backend"
- self.cache.clear()
+ cache.clear()
def test_incr_version(self):
"Dummy cache versions can't be incremented"
- self.cache.set('answer', 42)
- self.assertRaises(ValueError, self.cache.incr_version, 'answer')
- self.assertRaises(ValueError, self.cache.incr_version, 'does_not_exist')
+ cache.set('answer', 42)
+ self.assertRaises(ValueError, cache.incr_version, 'answer')
+ self.assertRaises(ValueError, cache.incr_version, 'does_not_exist')
def test_decr_version(self):
"Dummy cache versions can't be decremented"
- self.cache.set('answer', 42)
- self.assertRaises(ValueError, self.cache.decr_version, 'answer')
- self.assertRaises(ValueError, self.cache.decr_version, 'does_not_exist')
+ cache.set('answer', 42)
+ self.assertRaises(ValueError, cache.decr_version, 'answer')
+ self.assertRaises(ValueError, cache.decr_version, 'does_not_exist')
+
+
+def custom_key_func(key, key_prefix, version):
+ "A customized cache key function"
+ return 'CUSTOM-' + '-'.join([key_prefix, str(version), key])
+
+
+_caches_setting_base = {
+ 'default': {},
+ 'prefix': {'KEY_PREFIX': 'cacheprefix'},
+ 'v2': {'VERSION': 2},
+ 'custom_key': {'KEY_FUNCTION': custom_key_func},
+ 'custom_key2': {'KEY_FUNCTION': 'cache.tests.custom_key_func'},
+ 'cull': {'OPTIONS': {'MAX_ENTRIES': 30}},
+ 'zero_cull': {'OPTIONS': {'CULL_FREQUENCY': 0, 'MAX_ENTRIES': 30}},
+ 'other': {'LOCATION': 'other'},
+}
+
+
+def caches_setting_for_tests(**params):
+ setting = dict((k, v.copy()) for k, v in _caches_setting_base.items())
+ for cache_params in setting.values():
+ cache_params.update(params)
+ return setting
class BaseCacheTests(object):
@@ -187,89 +213,92 @@ class BaseCacheTests(object):
def setUp(self):
self.factory = RequestFactory()
+ def tearDown(self):
+ cache.clear()
+
def test_simple(self):
# Simple cache set/get works
- self.cache.set("key", "value")
- self.assertEqual(self.cache.get("key"), "value")
+ cache.set("key", "value")
+ self.assertEqual(cache.get("key"), "value")
def test_add(self):
# A key can be added to a cache
- self.cache.add("addkey1", "value")
- result = self.cache.add("addkey1", "newvalue")
+ cache.add("addkey1", "value")
+ result = cache.add("addkey1", "newvalue")
self.assertEqual(result, False)
- self.assertEqual(self.cache.get("addkey1"), "value")
+ self.assertEqual(cache.get("addkey1"), "value")
def test_prefix(self):
# Test for same cache key conflicts between shared backend
- self.cache.set('somekey', 'value')
+ cache.set('somekey', 'value')
# should not be set in the prefixed cache
- self.assertFalse(self.prefix_cache.has_key('somekey'))
+ self.assertFalse(caches['prefix'].has_key('somekey'))
- self.prefix_cache.set('somekey', 'value2')
+ caches['prefix'].set('somekey', 'value2')
- self.assertEqual(self.cache.get('somekey'), 'value')
- self.assertEqual(self.prefix_cache.get('somekey'), 'value2')
+ self.assertEqual(cache.get('somekey'), 'value')
+ self.assertEqual(caches['prefix'].get('somekey'), 'value2')
def test_non_existent(self):
# Non-existent cache keys return as None/default
# get with non-existent keys
- self.assertEqual(self.cache.get("does_not_exist"), None)
- self.assertEqual(self.cache.get("does_not_exist", "bang!"), "bang!")
+ self.assertEqual(cache.get("does_not_exist"), None)
+ self.assertEqual(cache.get("does_not_exist", "bang!"), "bang!")
def test_get_many(self):
# Multiple cache keys can be returned using get_many
- self.cache.set('a', 'a')
- self.cache.set('b', 'b')
- self.cache.set('c', 'c')
- self.cache.set('d', 'd')
- self.assertEqual(self.cache.get_many(['a', 'c', 'd']), {'a': 'a', 'c': 'c', 'd': 'd'})
- self.assertEqual(self.cache.get_many(['a', 'b', 'e']), {'a': 'a', 'b': 'b'})
+ cache.set('a', 'a')
+ cache.set('b', 'b')
+ cache.set('c', 'c')
+ cache.set('d', 'd')
+ self.assertEqual(cache.get_many(['a', 'c', 'd']), {'a': 'a', 'c': 'c', 'd': 'd'})
+ self.assertEqual(cache.get_many(['a', 'b', 'e']), {'a': 'a', 'b': 'b'})
def test_delete(self):
# Cache keys can be deleted
- self.cache.set("key1", "spam")
- self.cache.set("key2", "eggs")
- self.assertEqual(self.cache.get("key1"), "spam")
- self.cache.delete("key1")
- self.assertEqual(self.cache.get("key1"), None)
- self.assertEqual(self.cache.get("key2"), "eggs")
+ cache.set("key1", "spam")
+ cache.set("key2", "eggs")
+ self.assertEqual(cache.get("key1"), "spam")
+ cache.delete("key1")
+ self.assertEqual(cache.get("key1"), None)
+ self.assertEqual(cache.get("key2"), "eggs")
def test_has_key(self):
# The cache can be inspected for cache keys
- self.cache.set("hello1", "goodbye1")
- self.assertEqual(self.cache.has_key("hello1"), True)
- self.assertEqual(self.cache.has_key("goodbye1"), False)
+ cache.set("hello1", "goodbye1")
+ self.assertEqual(cache.has_key("hello1"), True)
+ self.assertEqual(cache.has_key("goodbye1"), False)
def test_in(self):
# The in operator can be used to inspect cache contents
- self.cache.set("hello2", "goodbye2")
- self.assertEqual("hello2" in self.cache, True)
- self.assertEqual("goodbye2" in self.cache, False)
+ cache.set("hello2", "goodbye2")
+ self.assertEqual("hello2" in cache, True)
+ self.assertEqual("goodbye2" in cache, False)
def test_incr(self):
# Cache values can be incremented
- self.cache.set('answer', 41)
- self.assertEqual(self.cache.incr('answer'), 42)
- self.assertEqual(self.cache.get('answer'), 42)
- self.assertEqual(self.cache.incr('answer', 10), 52)
- self.assertEqual(self.cache.get('answer'), 52)
- self.assertEqual(self.cache.incr('answer', -10), 42)
- self.assertRaises(ValueError, self.cache.incr, 'does_not_exist')
+ cache.set('answer', 41)
+ self.assertEqual(cache.incr('answer'), 42)
+ self.assertEqual(cache.get('answer'), 42)
+ self.assertEqual(cache.incr('answer', 10), 52)
+ self.assertEqual(cache.get('answer'), 52)
+ self.assertEqual(cache.incr('answer', -10), 42)
+ self.assertRaises(ValueError, cache.incr, 'does_not_exist')
def test_decr(self):
# Cache values can be decremented
- self.cache.set('answer', 43)
- self.assertEqual(self.cache.decr('answer'), 42)
- self.assertEqual(self.cache.get('answer'), 42)
- self.assertEqual(self.cache.decr('answer', 10), 32)
- self.assertEqual(self.cache.get('answer'), 32)
- self.assertEqual(self.cache.decr('answer', -10), 42)
- self.assertRaises(ValueError, self.cache.decr, 'does_not_exist')
+ cache.set('answer', 43)
+ self.assertEqual(cache.decr('answer'), 42)
+ self.assertEqual(cache.get('answer'), 42)
+ self.assertEqual(cache.decr('answer', 10), 32)
+ self.assertEqual(cache.get('answer'), 32)
+ self.assertEqual(cache.decr('answer', -10), 42)
+ self.assertRaises(ValueError, cache.decr, 'does_not_exist')
def test_close(self):
- self.assertTrue(hasattr(self.cache, 'close'))
- self.cache.close()
+ self.assertTrue(hasattr(cache, 'close'))
+ cache.close()
def test_data_types(self):
# Many different data types can be cached
@@ -282,8 +311,8 @@ def test_data_types(self):
'function': f,
'class': C,
}
- self.cache.set("stuff", stuff)
- self.assertEqual(self.cache.get("stuff"), stuff)
+ cache.set("stuff", stuff)
+ self.assertEqual(cache.get("stuff"), stuff)
def test_cache_read_for_model_instance(self):
# Don't want fields with callable as default to be called on cache read
@@ -292,8 +321,8 @@ def test_cache_read_for_model_instance(self):
my_poll = Poll.objects.create(question="Well?")
self.assertEqual(Poll.objects.count(), 1)
pub_date = my_poll.pub_date
- self.cache.set('question', my_poll)
- cached_poll = self.cache.get('question')
+ cache.set('question', my_poll)
+ cached_poll = cache.get('question')
self.assertEqual(cached_poll.pub_date, pub_date)
# We only want the default expensive calculation run once
self.assertEqual(expensive_calculation.num_runs, 1)
@@ -307,7 +336,7 @@ def test_cache_write_for_model_instance_with_deferred(self):
defer_qs = Poll.objects.all().defer('question')
self.assertEqual(defer_qs.count(), 1)
self.assertEqual(expensive_calculation.num_runs, 1)
- self.cache.set('deferred_queryset', defer_qs)
+ cache.set('deferred_queryset', defer_qs)
# cache set should not re-evaluate default functions
self.assertEqual(expensive_calculation.num_runs, 1)
@@ -319,25 +348,25 @@ def test_cache_read_for_model_instance_with_deferred(self):
self.assertEqual(expensive_calculation.num_runs, 1)
defer_qs = Poll.objects.all().defer('question')
self.assertEqual(defer_qs.count(), 1)
- self.cache.set('deferred_queryset', defer_qs)
+ cache.set('deferred_queryset', defer_qs)
self.assertEqual(expensive_calculation.num_runs, 1)
runs_before_cache_read = expensive_calculation.num_runs
- self.cache.get('deferred_queryset')
+ cache.get('deferred_queryset')
# We only want the default expensive calculation run on creation and set
self.assertEqual(expensive_calculation.num_runs, runs_before_cache_read)
def test_expiration(self):
# Cache values can be set to expire
- self.cache.set('expire1', 'very quickly', 1)
- self.cache.set('expire2', 'very quickly', 1)
- self.cache.set('expire3', 'very quickly', 1)
+ cache.set('expire1', 'very quickly', 1)
+ cache.set('expire2', 'very quickly', 1)
+ cache.set('expire3', 'very quickly', 1)
time.sleep(2)
- self.assertEqual(self.cache.get("expire1"), None)
+ self.assertEqual(cache.get("expire1"), None)
- self.cache.add("expire2", "newvalue")
- self.assertEqual(self.cache.get("expire2"), "newvalue")
- self.assertEqual(self.cache.has_key("expire3"), False)
+ cache.add("expire2", "newvalue")
+ self.assertEqual(cache.get("expire2"), "newvalue")
+ self.assertEqual(cache.has_key("expire3"), False)
def test_unicode(self):
# Unicode values can be cached
@@ -349,21 +378,21 @@ def test_unicode(self):
}
# Test `set`
for (key, value) in stuff.items():
- self.cache.set(key, value)
- self.assertEqual(self.cache.get(key), value)
+ cache.set(key, value)
+ self.assertEqual(cache.get(key), value)
# Test `add`
for (key, value) in stuff.items():
- self.cache.delete(key)
- self.cache.add(key, value)
- self.assertEqual(self.cache.get(key), value)
+ cache.delete(key)
+ cache.add(key, value)
+ self.assertEqual(cache.get(key), value)
# Test `set_many`
for (key, value) in stuff.items():
- self.cache.delete(key)
- self.cache.set_many(stuff)
+ cache.delete(key)
+ cache.set_many(stuff)
for (key, value) in stuff.items():
- self.assertEqual(self.cache.get(key), value)
+ self.assertEqual(cache.get(key), value)
def test_binary_string(self):
# Binary strings should be cacheable
@@ -372,53 +401,53 @@ def test_binary_string(self):
compressed_value = compress(value.encode())
# Test set
- self.cache.set('binary1', compressed_value)
- compressed_result = self.cache.get('binary1')
+ cache.set('binary1', compressed_value)
+ compressed_result = cache.get('binary1')
self.assertEqual(compressed_value, compressed_result)
self.assertEqual(value, decompress(compressed_result).decode())
# Test add
- self.cache.add('binary1-add', compressed_value)
- compressed_result = self.cache.get('binary1-add')
+ cache.add('binary1-add', compressed_value)
+ compressed_result = cache.get('binary1-add')
self.assertEqual(compressed_value, compressed_result)
self.assertEqual(value, decompress(compressed_result).decode())
# Test set_many
- self.cache.set_many({'binary1-set_many': compressed_value})
- compressed_result = self.cache.get('binary1-set_many')
+ cache.set_many({'binary1-set_many': compressed_value})
+ compressed_result = cache.get('binary1-set_many')
self.assertEqual(compressed_value, compressed_result)
self.assertEqual(value, decompress(compressed_result).decode())
def test_set_many(self):
# Multiple keys can be set using set_many
- self.cache.set_many({"key1": "spam", "key2": "eggs"})
- self.assertEqual(self.cache.get("key1"), "spam")
- self.assertEqual(self.cache.get("key2"), "eggs")
+ cache.set_many({"key1": "spam", "key2": "eggs"})
+ self.assertEqual(cache.get("key1"), "spam")
+ self.assertEqual(cache.get("key2"), "eggs")
def test_set_many_expiration(self):
# set_many takes a second ``timeout`` parameter
- self.cache.set_many({"key1": "spam", "key2": "eggs"}, 1)
+ cache.set_many({"key1": "spam", "key2": "eggs"}, 1)
time.sleep(2)
- self.assertEqual(self.cache.get("key1"), None)
- self.assertEqual(self.cache.get("key2"), None)
+ self.assertEqual(cache.get("key1"), None)
+ self.assertEqual(cache.get("key2"), None)
def test_delete_many(self):
# Multiple keys can be deleted using delete_many
- self.cache.set("key1", "spam")
- self.cache.set("key2", "eggs")
- self.cache.set("key3", "ham")
- self.cache.delete_many(["key1", "key2"])
- self.assertEqual(self.cache.get("key1"), None)
- self.assertEqual(self.cache.get("key2"), None)
- self.assertEqual(self.cache.get("key3"), "ham")
+ cache.set("key1", "spam")
+ cache.set("key2", "eggs")
+ cache.set("key3", "ham")
+ cache.delete_many(["key1", "key2"])
+ self.assertEqual(cache.get("key1"), None)
+ self.assertEqual(cache.get("key2"), None)
+ self.assertEqual(cache.get("key3"), "ham")
def test_clear(self):
# The cache can be emptied using clear
- self.cache.set("key1", "spam")
- self.cache.set("key2", "eggs")
- self.cache.clear()
- self.assertEqual(self.cache.get("key1"), None)
- self.assertEqual(self.cache.get("key2"), None)
+ cache.set("key1", "spam")
+ cache.set("key2", "eggs")
+ cache.clear()
+ self.assertEqual(cache.get("key1"), None)
+ self.assertEqual(cache.get("key2"), None)
def test_long_timeout(self):
'''
@@ -426,63 +455,67 @@ def test_long_timeout(self):
it is an absolute expiration timestamp instead of a relative
offset. Test that we honour this convention. Refs #12399.
'''
- self.cache.set('key1', 'eggs', 60 * 60 * 24 * 30 + 1) # 30 days + 1 second
- self.assertEqual(self.cache.get('key1'), 'eggs')
+ cache.set('key1', 'eggs', 60 * 60 * 24 * 30 + 1) # 30 days + 1 second
+ self.assertEqual(cache.get('key1'), 'eggs')
- self.cache.add('key2', 'ham', 60 * 60 * 24 * 30 + 1)
- self.assertEqual(self.cache.get('key2'), 'ham')
+ cache.add('key2', 'ham', 60 * 60 * 24 * 30 + 1)
+ self.assertEqual(cache.get('key2'), 'ham')
- self.cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 60 * 60 * 24 * 30 + 1)
- self.assertEqual(self.cache.get('key3'), 'sausage')
- self.assertEqual(self.cache.get('key4'), 'lobster bisque')
+ cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 60 * 60 * 24 * 30 + 1)
+ self.assertEqual(cache.get('key3'), 'sausage')
+ self.assertEqual(cache.get('key4'), 'lobster bisque')
def test_forever_timeout(self):
'''
Passing in None into timeout results in a value that is cached forever
'''
- self.cache.set('key1', 'eggs', None)
- self.assertEqual(self.cache.get('key1'), 'eggs')
+ cache.set('key1', 'eggs', None)
+ self.assertEqual(cache.get('key1'), 'eggs')
- self.cache.add('key2', 'ham', None)
- self.assertEqual(self.cache.get('key2'), 'ham')
+ cache.add('key2', 'ham', None)
+ self.assertEqual(cache.get('key2'), 'ham')
- self.cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, None)
- self.assertEqual(self.cache.get('key3'), 'sausage')
- self.assertEqual(self.cache.get('key4'), 'lobster bisque')
+ cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, None)
+ self.assertEqual(cache.get('key3'), 'sausage')
+ self.assertEqual(cache.get('key4'), 'lobster bisque')
def test_zero_timeout(self):
'''
Passing in None into timeout results in a value that is cached forever
'''
- self.cache.set('key1', 'eggs', 0)
- self.assertEqual(self.cache.get('key1'), None)
+ cache.set('key1', 'eggs', 0)
+ self.assertEqual(cache.get('key1'), None)
- self.cache.add('key2', 'ham', 0)
- self.assertEqual(self.cache.get('key2'), None)
+ cache.add('key2', 'ham', 0)
+ self.assertEqual(cache.get('key2'), None)
- self.cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 0)
- self.assertEqual(self.cache.get('key3'), None)
- self.assertEqual(self.cache.get('key4'), None)
+ cache.set_many({'key3': 'sausage', 'key4': 'lobster bisque'}, 0)
+ self.assertEqual(cache.get('key3'), None)
+ self.assertEqual(cache.get('key4'), None)
def test_float_timeout(self):
# Make sure a timeout given as a float doesn't crash anything.
- self.cache.set("key1", "spam", 100.2)
- self.assertEqual(self.cache.get("key1"), "spam")
-
- def perform_cull_test(self, initial_count, final_count):
- """This is implemented as a utility method, because only some of the backends
- implement culling. The culling algorithm also varies slightly, so the final
- number of entries will vary between backends"""
- # Create initial cache key entries. This will overflow the cache, causing a cull
+ cache.set("key1", "spam", 100.2)
+ self.assertEqual(cache.get("key1"), "spam")
+
+ def _perform_cull_test(self, cull_cache, initial_count, final_count):
+ # Create initial cache key entries. This will overflow the cache,
+ # causing a cull.
for i in range(1, initial_count):
- self.cache.set('cull%d' % i, 'value', 1000)
+ cull_cache.set('cull%d' % i, 'value', 1000)
count = 0
# Count how many keys are left in the cache.
for i in range(1, initial_count):
- if self.cache.has_key('cull%d' % i):
+ if cull_cache.has_key('cull%d' % i):
count = count + 1
self.assertEqual(count, final_count)
+ def test_cull(self):
+ self._perform_cull_test(caches['cull'], 50, 29)
+
+ def test_zero_cull(self):
+ self._perform_cull_test(caches['zero_cull'], 50, 19)
+
def test_invalid_keys(self):
"""
All the builtin backends (except memcached, see below) should warn on
@@ -496,302 +529,302 @@ def test_invalid_keys(self):
def func(key, *args):
return key
- old_func = self.cache.key_func
- self.cache.key_func = func
+ old_func = cache.key_func
+ cache.key_func = func
try:
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
# memcached does not allow whitespace or control characters in keys
- self.cache.set('key with spaces', 'value')
+ cache.set('key with spaces', 'value')
self.assertEqual(len(w), 2)
self.assertIsInstance(w[0].message, CacheKeyWarning)
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always")
# memcached limits key length to 250
- self.cache.set('a' * 251, 'value')
+ cache.set('a' * 251, 'value')
self.assertEqual(len(w), 1)
self.assertIsInstance(w[0].message, CacheKeyWarning)
finally:
- self.cache.key_func = old_func
+ cache.key_func = old_func
def test_cache_versioning_get_set(self):
# set, using default version = 1
- self.cache.set('answer1', 42)
- self.assertEqual(self.cache.get('answer1'), 42)
- self.assertEqual(self.cache.get('answer1', version=1), 42)
- self.assertEqual(self.cache.get('answer1', version=2), None)
+ cache.set('answer1', 42)
+ self.assertEqual(cache.get('answer1'), 42)
+ self.assertEqual(cache.get('answer1', version=1), 42)
+ self.assertEqual(cache.get('answer1', version=2), None)
- self.assertEqual(self.v2_cache.get('answer1'), None)
- self.assertEqual(self.v2_cache.get('answer1', version=1), 42)
- self.assertEqual(self.v2_cache.get('answer1', version=2), None)
+ self.assertEqual(caches['v2'].get('answer1'), None)
+ self.assertEqual(caches['v2'].get('answer1', version=1), 42)
+ self.assertEqual(caches['v2'].get('answer1', version=2), None)
# set, default version = 1, but manually override version = 2
- self.cache.set('answer2', 42, version=2)
- self.assertEqual(self.cache.get('answer2'), None)
- self.assertEqual(self.cache.get('answer2', version=1), None)
- self.assertEqual(self.cache.get('answer2', version=2), 42)
+ cache.set('answer2', 42, version=2)
+ self.assertEqual(cache.get('answer2'), None)
+ self.assertEqual(cache.get('answer2', version=1), None)
+ self.assertEqual(cache.get('answer2', version=2), 42)
- self.assertEqual(self.v2_cache.get('answer2'), 42)
- self.assertEqual(self.v2_cache.get('answer2', version=1), None)
- self.assertEqual(self.v2_cache.get('answer2', version=2), 42)
+ self.assertEqual(caches['v2'].get('answer2'), 42)
+ self.assertEqual(caches['v2'].get('answer2', version=1), None)
+ self.assertEqual(caches['v2'].get('answer2', version=2), 42)
# v2 set, using default version = 2
- self.v2_cache.set('answer3', 42)
- self.assertEqual(self.cache.get('answer3'), None)
- self.assertEqual(self.cache.get('answer3', version=1), None)
- self.assertEqual(self.cache.get('answer3', version=2), 42)
+ caches['v2'].set('answer3', 42)
+ self.assertEqual(cache.get('answer3'), None)
+ self.assertEqual(cache.get('answer3', version=1), None)
+ self.assertEqual(cache.get('answer3', version=2), 42)
- self.assertEqual(self.v2_cache.get('answer3'), 42)
- self.assertEqual(self.v2_cache.get('answer3', version=1), None)
- self.assertEqual(self.v2_cache.get('answer3', version=2), 42)
+ self.assertEqual(caches['v2'].get('answer3'), 42)
+ self.assertEqual(caches['v2'].get('answer3', version=1), None)
+ self.assertEqual(caches['v2'].get('answer3', version=2), 42)
# v2 set, default version = 2, but manually override version = 1
- self.v2_cache.set('answer4', 42, version=1)
- self.assertEqual(self.cache.get('answer4'), 42)
- self.assertEqual(self.cache.get('answer4', version=1), 42)
- self.assertEqual(self.cache.get('answer4', version=2), None)
+ caches['v2'].set('answer4', 42, version=1)
+ self.assertEqual(cache.get('answer4'), 42)
+ self.assertEqual(cache.get('answer4', version=1), 42)
+ self.assertEqual(cache.get('answer4', version=2), None)
- self.assertEqual(self.v2_cache.get('answer4'), None)
- self.assertEqual(self.v2_cache.get('answer4', version=1), 42)
- self.assertEqual(self.v2_cache.get('answer4', version=2), None)
+ self.assertEqual(caches['v2'].get('answer4'), None)
+ self.assertEqual(caches['v2'].get('answer4', version=1), 42)
+ self.assertEqual(caches['v2'].get('answer4', version=2), None)
def test_cache_versioning_add(self):
# add, default version = 1, but manually override version = 2
- self.cache.add('answer1', 42, version=2)
- self.assertEqual(self.cache.get('answer1', version=1), None)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
+ cache.add('answer1', 42, version=2)
+ self.assertEqual(cache.get('answer1', version=1), None)
+ self.assertEqual(cache.get('answer1', version=2), 42)
- self.cache.add('answer1', 37, version=2)
- self.assertEqual(self.cache.get('answer1', version=1), None)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
+ cache.add('answer1', 37, version=2)
+ self.assertEqual(cache.get('answer1', version=1), None)
+ self.assertEqual(cache.get('answer1', version=2), 42)
- self.cache.add('answer1', 37, version=1)
- self.assertEqual(self.cache.get('answer1', version=1), 37)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
+ cache.add('answer1', 37, version=1)
+ self.assertEqual(cache.get('answer1', version=1), 37)
+ self.assertEqual(cache.get('answer1', version=2), 42)
# v2 add, using default version = 2
- self.v2_cache.add('answer2', 42)
- self.assertEqual(self.cache.get('answer2', version=1), None)
- self.assertEqual(self.cache.get('answer2', version=2), 42)
+ caches['v2'].add('answer2', 42)
+ self.assertEqual(cache.get('answer2', version=1), None)
+ self.assertEqual(cache.get('answer2', version=2), 42)
- self.v2_cache.add('answer2', 37)
- self.assertEqual(self.cache.get('answer2', version=1), None)
- self.assertEqual(self.cache.get('answer2', version=2), 42)
+ caches['v2'].add('answer2', 37)
+ self.assertEqual(cache.get('answer2', version=1), None)
+ self.assertEqual(cache.get('answer2', version=2), 42)
- self.v2_cache.add('answer2', 37, version=1)
- self.assertEqual(self.cache.get('answer2', version=1), 37)
- self.assertEqual(self.cache.get('answer2', version=2), 42)
+ caches['v2'].add('answer2', 37, version=1)
+ self.assertEqual(cache.get('answer2', version=1), 37)
+ self.assertEqual(cache.get('answer2', version=2), 42)
# v2 add, default version = 2, but manually override version = 1
- self.v2_cache.add('answer3', 42, version=1)
- self.assertEqual(self.cache.get('answer3', version=1), 42)
- self.assertEqual(self.cache.get('answer3', version=2), None)
+ caches['v2'].add('answer3', 42, version=1)
+ self.assertEqual(cache.get('answer3', version=1), 42)
+ self.assertEqual(cache.get('answer3', version=2), None)
- self.v2_cache.add('answer3', 37, version=1)
- self.assertEqual(self.cache.get('answer3', version=1), 42)
- self.assertEqual(self.cache.get('answer3', version=2), None)
+ caches['v2'].add('answer3', 37, version=1)
+ self.assertEqual(cache.get('answer3', version=1), 42)
+ self.assertEqual(cache.get('answer3', version=2), None)
- self.v2_cache.add('answer3', 37)
- self.assertEqual(self.cache.get('answer3', version=1), 42)
- self.assertEqual(self.cache.get('answer3', version=2), 37)
+ caches['v2'].add('answer3', 37)
+ self.assertEqual(cache.get('answer3', version=1), 42)
+ self.assertEqual(cache.get('answer3', version=2), 37)
def test_cache_versioning_has_key(self):
- self.cache.set('answer1', 42)
+ cache.set('answer1', 42)
# has_key
- self.assertTrue(self.cache.has_key('answer1'))
- self.assertTrue(self.cache.has_key('answer1', version=1))
- self.assertFalse(self.cache.has_key('answer1', version=2))
+ self.assertTrue(cache.has_key('answer1'))
+ self.assertTrue(cache.has_key('answer1', version=1))
+ self.assertFalse(cache.has_key('answer1', version=2))
- self.assertFalse(self.v2_cache.has_key('answer1'))
- self.assertTrue(self.v2_cache.has_key('answer1', version=1))
- self.assertFalse(self.v2_cache.has_key('answer1', version=2))
+ self.assertFalse(caches['v2'].has_key('answer1'))
+ self.assertTrue(caches['v2'].has_key('answer1', version=1))
+ self.assertFalse(caches['v2'].has_key('answer1', version=2))
def test_cache_versioning_delete(self):
- self.cache.set('answer1', 37, version=1)
- self.cache.set('answer1', 42, version=2)
- self.cache.delete('answer1')
- self.assertEqual(self.cache.get('answer1', version=1), None)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
-
- self.cache.set('answer2', 37, version=1)
- self.cache.set('answer2', 42, version=2)
- self.cache.delete('answer2', version=2)
- self.assertEqual(self.cache.get('answer2', version=1), 37)
- self.assertEqual(self.cache.get('answer2', version=2), None)
-
- self.cache.set('answer3', 37, version=1)
- self.cache.set('answer3', 42, version=2)
- self.v2_cache.delete('answer3')
- self.assertEqual(self.cache.get('answer3', version=1), 37)
- self.assertEqual(self.cache.get('answer3', version=2), None)
-
- self.cache.set('answer4', 37, version=1)
- self.cache.set('answer4', 42, version=2)
- self.v2_cache.delete('answer4', version=1)
- self.assertEqual(self.cache.get('answer4', version=1), None)
- self.assertEqual(self.cache.get('answer4', version=2), 42)
+ cache.set('answer1', 37, version=1)
+ cache.set('answer1', 42, version=2)
+ cache.delete('answer1')
+ self.assertEqual(cache.get('answer1', version=1), None)
+ self.assertEqual(cache.get('answer1', version=2), 42)
+
+ cache.set('answer2', 37, version=1)
+ cache.set('answer2', 42, version=2)
+ cache.delete('answer2', version=2)
+ self.assertEqual(cache.get('answer2', version=1), 37)
+ self.assertEqual(cache.get('answer2', version=2), None)
+
+ cache.set('answer3', 37, version=1)
+ cache.set('answer3', 42, version=2)
+ caches['v2'].delete('answer3')
+ self.assertEqual(cache.get('answer3', version=1), 37)
+ self.assertEqual(cache.get('answer3', version=2), None)
+
+ cache.set('answer4', 37, version=1)
+ cache.set('answer4', 42, version=2)
+ caches['v2'].delete('answer4', version=1)
+ self.assertEqual(cache.get('answer4', version=1), None)
+ self.assertEqual(cache.get('answer4', version=2), 42)
def test_cache_versioning_incr_decr(self):
- self.cache.set('answer1', 37, version=1)
- self.cache.set('answer1', 42, version=2)
- self.cache.incr('answer1')
- self.assertEqual(self.cache.get('answer1', version=1), 38)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
- self.cache.decr('answer1')
- self.assertEqual(self.cache.get('answer1', version=1), 37)
- self.assertEqual(self.cache.get('answer1', version=2), 42)
-
- self.cache.set('answer2', 37, version=1)
- self.cache.set('answer2', 42, version=2)
- self.cache.incr('answer2', version=2)
- self.assertEqual(self.cache.get('answer2', version=1), 37)
- self.assertEqual(self.cache.get('answer2', version=2), 43)
- self.cache.decr('answer2', version=2)
- self.assertEqual(self.cache.get('answer2', version=1), 37)
- self.assertEqual(self.cache.get('answer2', version=2), 42)
-
- self.cache.set('answer3', 37, version=1)
- self.cache.set('answer3', 42, version=2)
- self.v2_cache.incr('answer3')
- self.assertEqual(self.cache.get('answer3', version=1), 37)
- self.assertEqual(self.cache.get('answer3', version=2), 43)
- self.v2_cache.decr('answer3')
- self.assertEqual(self.cache.get('answer3', version=1), 37)
- self.assertEqual(self.cache.get('answer3', version=2), 42)
-
- self.cache.set('answer4', 37, version=1)
- self.cache.set('answer4', 42, version=2)
- self.v2_cache.incr('answer4', version=1)
- self.assertEqual(self.cache.get('answer4', version=1), 38)
- self.assertEqual(self.cache.get('answer4', version=2), 42)
- self.v2_cache.decr('answer4', version=1)
- self.assertEqual(self.cache.get('answer4', version=1), 37)
- self.assertEqual(self.cache.get('answer4', version=2), 42)
+ cache.set('answer1', 37, version=1)
+ cache.set('answer1', 42, version=2)
+ cache.incr('answer1')
+ self.assertEqual(cache.get('answer1', version=1), 38)
+ self.assertEqual(cache.get('answer1', version=2), 42)
+ cache.decr('answer1')
+ self.assertEqual(cache.get('answer1', version=1), 37)
+ self.assertEqual(cache.get('answer1', version=2), 42)
+
+ cache.set('answer2', 37, version=1)
+ cache.set('answer2', 42, version=2)
+ cache.incr('answer2', version=2)
+ self.assertEqual(cache.get('answer2', version=1), 37)
+ self.assertEqual(cache.get('answer2', version=2), 43)
+ cache.decr('answer2', version=2)
+ self.assertEqual(cache.get('answer2', version=1), 37)
+ self.assertEqual(cache.get('answer2', version=2), 42)
+
+ cache.set('answer3', 37, version=1)
+ cache.set('answer3', 42, version=2)
+ caches['v2'].incr('answer3')
+ self.assertEqual(cache.get('answer3', version=1), 37)
+ self.assertEqual(cache.get('answer3', version=2), 43)
+ caches['v2'].decr('answer3')
+ self.assertEqual(cache.get('answer3', version=1), 37)
+ self.assertEqual(cache.get('answer3', version=2), 42)
+
+ cache.set('answer4', 37, version=1)
+ cache.set('answer4', 42, version=2)
+ caches['v2'].incr('answer4', version=1)
+ self.assertEqual(cache.get('answer4', version=1), 38)
+ self.assertEqual(cache.get('answer4', version=2), 42)
+ caches['v2'].decr('answer4', version=1)
+ self.assertEqual(cache.get('answer4', version=1), 37)
+ self.assertEqual(cache.get('answer4', version=2), 42)
def test_cache_versioning_get_set_many(self):
# set, using default version = 1
- self.cache.set_many({'ford1': 37, 'arthur1': 42})
- self.assertEqual(self.cache.get_many(['ford1', 'arthur1']),
+ cache.set_many({'ford1': 37, 'arthur1': 42})
+ self.assertEqual(cache.get_many(['ford1', 'arthur1']),
{'ford1': 37, 'arthur1': 42})
- self.assertEqual(self.cache.get_many(['ford1', 'arthur1'], version=1),
+ self.assertEqual(cache.get_many(['ford1', 'arthur1'], version=1),
{'ford1': 37, 'arthur1': 42})
- self.assertEqual(self.cache.get_many(['ford1', 'arthur1'], version=2), {})
+ self.assertEqual(cache.get_many(['ford1', 'arthur1'], version=2), {})
- self.assertEqual(self.v2_cache.get_many(['ford1', 'arthur1']), {})
- self.assertEqual(self.v2_cache.get_many(['ford1', 'arthur1'], version=1),
+ self.assertEqual(caches['v2'].get_many(['ford1', 'arthur1']), {})
+ self.assertEqual(caches['v2'].get_many(['ford1', 'arthur1'], version=1),
{'ford1': 37, 'arthur1': 42})
- self.assertEqual(self.v2_cache.get_many(['ford1', 'arthur1'], version=2), {})
+ self.assertEqual(caches['v2'].get_many(['ford1', 'arthur1'], version=2), {})
# set, default version = 1, but manually override version = 2
- self.cache.set_many({'ford2': 37, 'arthur2': 42}, version=2)
- self.assertEqual(self.cache.get_many(['ford2', 'arthur2']), {})
- self.assertEqual(self.cache.get_many(['ford2', 'arthur2'], version=1), {})
- self.assertEqual(self.cache.get_many(['ford2', 'arthur2'], version=2),
+ cache.set_many({'ford2': 37, 'arthur2': 42}, version=2)
+ self.assertEqual(cache.get_many(['ford2', 'arthur2']), {})
+ self.assertEqual(cache.get_many(['ford2', 'arthur2'], version=1), {})
+ self.assertEqual(cache.get_many(['ford2', 'arthur2'], version=2),
{'ford2': 37, 'arthur2': 42})
- self.assertEqual(self.v2_cache.get_many(['ford2', 'arthur2']),
+ self.assertEqual(caches['v2'].get_many(['ford2', 'arthur2']),
{'ford2': 37, 'arthur2': 42})
- self.assertEqual(self.v2_cache.get_many(['ford2', 'arthur2'], version=1), {})
- self.assertEqual(self.v2_cache.get_many(['ford2', 'arthur2'], version=2),
+ self.assertEqual(caches['v2'].get_many(['ford2', 'arthur2'], version=1), {})
+ self.assertEqual(caches['v2'].get_many(['ford2', 'arthur2'], version=2),
{'ford2': 37, 'arthur2': 42})
# v2 set, using default version = 2
- self.v2_cache.set_many({'ford3': 37, 'arthur3': 42})
- self.assertEqual(self.cache.get_many(['ford3', 'arthur3']), {})
- self.assertEqual(self.cache.get_many(['ford3', 'arthur3'], version=1), {})
- self.assertEqual(self.cache.get_many(['ford3', 'arthur3'], version=2),
+ caches['v2'].set_many({'ford3': 37, 'arthur3': 42})
+ self.assertEqual(cache.get_many(['ford3', 'arthur3']), {})
+ self.assertEqual(cache.get_many(['ford3', 'arthur3'], version=1), {})
+ self.assertEqual(cache.get_many(['ford3', 'arthur3'], version=2),
{'ford3': 37, 'arthur3': 42})
- self.assertEqual(self.v2_cache.get_many(['ford3', 'arthur3']),
+ self.assertEqual(caches['v2'].get_many(['ford3', 'arthur3']),
{'ford3': 37, 'arthur3': 42})
- self.assertEqual(self.v2_cache.get_many(['ford3', 'arthur3'], version=1), {})
- self.assertEqual(self.v2_cache.get_many(['ford3', 'arthur3'], version=2),
+ self.assertEqual(caches['v2'].get_many(['ford3', 'arthur3'], version=1), {})
+ self.assertEqual(caches['v2'].get_many(['ford3', 'arthur3'], version=2),
{'ford3': 37, 'arthur3': 42})
# v2 set, default version = 2, but manually override version = 1
- self.v2_cache.set_many({'ford4': 37, 'arthur4': 42}, version=1)
- self.assertEqual(self.cache.get_many(['ford4', 'arthur4']),
+ caches['v2'].set_many({'ford4': 37, 'arthur4': 42}, version=1)
+ self.assertEqual(cache.get_many(['ford4', 'arthur4']),
{'ford4': 37, 'arthur4': 42})
- self.assertEqual(self.cache.get_many(['ford4', 'arthur4'], version=1),
+ self.assertEqual(cache.get_many(['ford4', 'arthur4'], version=1),
{'ford4': 37, 'arthur4': 42})
- self.assertEqual(self.cache.get_many(['ford4', 'arthur4'], version=2), {})
+ self.assertEqual(cache.get_many(['ford4', 'arthur4'], version=2), {})
- self.assertEqual(self.v2_cache.get_many(['ford4', 'arthur4']), {})
- self.assertEqual(self.v2_cache.get_many(['ford4', 'arthur4'], version=1),
+ self.assertEqual(caches['v2'].get_many(['ford4', 'arthur4']), {})
+ self.assertEqual(caches['v2'].get_many(['ford4', 'arthur4'], version=1),
{'ford4': 37, 'arthur4': 42})
- self.assertEqual(self.v2_cache.get_many(['ford4', 'arthur4'], version=2), {})
+ self.assertEqual(caches['v2'].get_many(['ford4', 'arthur4'], version=2), {})
def test_incr_version(self):
- self.cache.set('answer', 42, version=2)
- self.assertEqual(self.cache.get('answer'), None)
- self.assertEqual(self.cache.get('answer', version=1), None)
- self.assertEqual(self.cache.get('answer', version=2), 42)
- self.assertEqual(self.cache.get('answer', version=3), None)
-
- self.assertEqual(self.cache.incr_version('answer', version=2), 3)
- self.assertEqual(self.cache.get('answer'), None)
- self.assertEqual(self.cache.get('answer', version=1), None)
- self.assertEqual(self.cache.get('answer', version=2), None)
- self.assertEqual(self.cache.get('answer', version=3), 42)
-
- self.v2_cache.set('answer2', 42)
- self.assertEqual(self.v2_cache.get('answer2'), 42)
- self.assertEqual(self.v2_cache.get('answer2', version=1), None)
- self.assertEqual(self.v2_cache.get('answer2', version=2), 42)
- self.assertEqual(self.v2_cache.get('answer2', version=3), None)
-
- self.assertEqual(self.v2_cache.incr_version('answer2'), 3)
- self.assertEqual(self.v2_cache.get('answer2'), None)
- self.assertEqual(self.v2_cache.get('answer2', version=1), None)
- self.assertEqual(self.v2_cache.get('answer2', version=2), None)
- self.assertEqual(self.v2_cache.get('answer2', version=3), 42)
-
- self.assertRaises(ValueError, self.cache.incr_version, 'does_not_exist')
+ cache.set('answer', 42, version=2)
+ self.assertEqual(cache.get('answer'), None)
+ self.assertEqual(cache.get('answer', version=1), None)
+ self.assertEqual(cache.get('answer', version=2), 42)
+ self.assertEqual(cache.get('answer', version=3), None)
+
+ self.assertEqual(cache.incr_version('answer', version=2), 3)
+ self.assertEqual(cache.get('answer'), None)
+ self.assertEqual(cache.get('answer', version=1), None)
+ self.assertEqual(cache.get('answer', version=2), None)
+ self.assertEqual(cache.get('answer', version=3), 42)
+
+ caches['v2'].set('answer2', 42)
+ self.assertEqual(caches['v2'].get('answer2'), 42)
+ self.assertEqual(caches['v2'].get('answer2', version=1), None)
+ self.assertEqual(caches['v2'].get('answer2', version=2), 42)
+ self.assertEqual(caches['v2'].get('answer2', version=3), None)
+
+ self.assertEqual(caches['v2'].incr_version('answer2'), 3)
+ self.assertEqual(caches['v2'].get('answer2'), None)
+ self.assertEqual(caches['v2'].get('answer2', version=1), None)
+ self.assertEqual(caches['v2'].get('answer2', version=2), None)
+ self.assertEqual(caches['v2'].get('answer2', version=3), 42)
+
+ self.assertRaises(ValueError, cache.incr_version, 'does_not_exist')
def test_decr_version(self):
- self.cache.set('answer', 42, version=2)
- self.assertEqual(self.cache.get('answer'), None)
- self.assertEqual(self.cache.get('answer', version=1), None)
- self.assertEqual(self.cache.get('answer', version=2), 42)
+ cache.set('answer', 42, version=2)
+ self.assertEqual(cache.get('answer'), None)
+ self.assertEqual(cache.get('answer', version=1), None)
+ self.assertEqual(cache.get('answer', version=2), 42)
- self.assertEqual(self.cache.decr_version('answer', version=2), 1)
- self.assertEqual(self.cache.get('answer'), 42)
- self.assertEqual(self.cache.get('answer', version=1), 42)
- self.assertEqual(self.cache.get('answer', version=2), None)
+ self.assertEqual(cache.decr_version('answer', version=2), 1)
+ self.assertEqual(cache.get('answer'), 42)
+ self.assertEqual(cache.get('answer', version=1), 42)
+ self.assertEqual(cache.get('answer', version=2), None)
- self.v2_cache.set('answer2', 42)
- self.assertEqual(self.v2_cache.get('answer2'), 42)
- self.assertEqual(self.v2_cache.get('answer2', version=1), None)
- self.assertEqual(self.v2_cache.get('answer2', version=2), 42)
+ caches['v2'].set('answer2', 42)
+ self.assertEqual(caches['v2'].get('answer2'), 42)
+ self.assertEqual(caches['v2'].get('answer2', version=1), None)
+ self.assertEqual(caches['v2'].get('answer2', version=2), 42)
- self.assertEqual(self.v2_cache.decr_version('answer2'), 1)
- self.assertEqual(self.v2_cache.get('answer2'), None)
- self.assertEqual(self.v2_cache.get('answer2', version=1), 42)
- self.assertEqual(self.v2_cache.get('answer2', version=2), None)
+ self.assertEqual(caches['v2'].decr_version('answer2'), 1)
+ self.assertEqual(caches['v2'].get('answer2'), None)
+ self.assertEqual(caches['v2'].get('answer2', version=1), 42)
+ self.assertEqual(caches['v2'].get('answer2', version=2), None)
- self.assertRaises(ValueError, self.cache.decr_version, 'does_not_exist', version=2)
+ self.assertRaises(ValueError, cache.decr_version, 'does_not_exist', version=2)
def test_custom_key_func(self):
# Two caches with different key functions aren't visible to each other
- self.cache.set('answer1', 42)
- self.assertEqual(self.cache.get('answer1'), 42)
- self.assertEqual(self.custom_key_cache.get('answer1'), None)
- self.assertEqual(self.custom_key_cache2.get('answer1'), None)
+ cache.set('answer1', 42)
+ self.assertEqual(cache.get('answer1'), 42)
+ self.assertEqual(caches['custom_key'].get('answer1'), None)
+ self.assertEqual(caches['custom_key2'].get('answer1'), None)
- self.custom_key_cache.set('answer2', 42)
- self.assertEqual(self.cache.get('answer2'), None)
- self.assertEqual(self.custom_key_cache.get('answer2'), 42)
- self.assertEqual(self.custom_key_cache2.get('answer2'), 42)
+ caches['custom_key'].set('answer2', 42)
+ self.assertEqual(cache.get('answer2'), None)
+ self.assertEqual(caches['custom_key'].get('answer2'), 42)
+ self.assertEqual(caches['custom_key2'].get('answer2'), 42)
def test_cache_write_unpickable_object(self):
update_middleware = UpdateCacheMiddleware()
- update_middleware.cache = self.cache
+ update_middleware.cache = cache
fetch_middleware = FetchFromCacheMiddleware()
- fetch_middleware.cache = self.cache
+ fetch_middleware.cache = cache
request = self.factory.get('/cache/test')
request._cache_update_cache = True
@@ -817,46 +850,36 @@ def test_cache_write_unpickable_object(self):
self.assertEqual(get_cache_data.cookies, response.cookies)
-def custom_key_func(key, key_prefix, version):
- "A customized cache key function"
- return 'CUSTOM-' + '-'.join([key_prefix, str(version), key])
-
-
-@override_settings(
- CACHES={
- 'default': {
- 'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
- 'LOCATION': 'test cache table',
- },
- },
-)
+@override_settings(CACHES=caches_setting_for_tests(
+ BACKEND='django.core.cache.backends.db.DatabaseCache',
+ # Spaces are used in the table name to ensure quoting/escaping is working
+ LOCATION='test cache table'
+))
class DBCacheTests(BaseCacheTests, TransactionTestCase):
available_apps = ['cache']
- backend_name = 'django.core.cache.backends.db.DatabaseCache'
def setUp(self):
- self.factory = RequestFactory()
- # Spaces are used in the table name to ensure quoting/escaping is working
- self._table_name = 'test cache table'
- management.call_command('createcachetable', verbosity=0, interactive=False)
- self.cache = get_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30})
- self.prefix_cache = get_cache(self.backend_name, LOCATION=self._table_name, KEY_PREFIX='cacheprefix')
- self.v2_cache = get_cache(self.backend_name, LOCATION=self._table_name, VERSION=2)
- self.custom_key_cache = get_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION=custom_key_func)
- self.custom_key_cache2 = get_cache(self.backend_name, LOCATION=self._table_name, KEY_FUNCTION='cache.tests.custom_key_func')
+ # The super calls needs to happen first for the settings override.
+ super(DBCacheTests, self).setUp()
+ self.create_table()
def tearDown(self):
- cursor = connection.cursor()
- cursor.execute('DROP TABLE %s' % connection.ops.quote_name(self._table_name))
- connection.commit()
+ # The super call needs to happen first because it uses the database.
+ super(DBCacheTests, self).tearDown()
+ self.drop_table()
- def test_cull(self):
- self.perform_cull_test(50, 29)
+ def create_table(self):
+ management.call_command('createcachetable', verbosity=0, interactive=False)
+
+ def drop_table(self):
+ cursor = connection.cursor()
+ table_name = connection.ops.quote_name('test cache table')
+ cursor.execute('DROP TABLE %s' % table_name)
+ cursor.close()
def test_zero_cull(self):
- self.cache = get_cache(self.backend_name, LOCATION=self._table_name, OPTIONS={'MAX_ENTRIES': 30, 'CULL_FREQUENCY': 0})
- self.perform_cull_test(50, 18)
+ self._perform_cull_test(caches['zero_cull'], 50, 18)
def test_second_call_doesnt_crash(self):
stdout = six.StringIO()
@@ -865,30 +888,30 @@ def test_second_call_doesnt_crash(self):
stdout=stdout
)
self.assertEqual(stdout.getvalue(),
- "Cache table '%s' already exists.\n" % self._table_name)
+ "Cache table 'test cache table' already exists.\n" * len(settings.CACHES))
def test_createcachetable_with_table_argument(self):
"""
Delete and recreate cache table with legacy behavior (explicitly
specifying the table name).
"""
- self.tearDown()
+ self.drop_table()
stdout = six.StringIO()
management.call_command(
'createcachetable',
- self._table_name,
+ 'test cache table',
verbosity=2,
stdout=stdout
)
self.assertEqual(stdout.getvalue(),
- "Cache table '%s' created.\n" % self._table_name)
+ "Cache table 'test cache table' created.\n")
def test_clear_commits_transaction(self):
# Ensure the database transaction is committed (#19896)
- self.cache.set("key1", "spam")
- self.cache.clear()
+ cache.set("key1", "spam")
+ cache.clear()
transaction.rollback()
- self.assertEqual(self.cache.get("key1"), None)
+ self.assertEqual(cache.get("key1"), None)
@override_settings(USE_TZ=True)
@@ -945,86 +968,59 @@ def test_createcachetable_observes_database_router(self):
router.routers = old_routers
-class LocMemCacheTests(unittest.TestCase, BaseCacheTests):
- backend_name = 'django.core.cache.backends.locmem.LocMemCache'
+@override_settings(CACHES=caches_setting_for_tests(
+ BACKEND='django.core.cache.backends.locmem.LocMemCache',
+))
+class LocMemCacheTests(BaseCacheTests, TestCase):
def setUp(self):
- self.factory = RequestFactory()
- self.cache = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30})
- self.prefix_cache = get_cache(self.backend_name, KEY_PREFIX='cacheprefix')
- self.v2_cache = get_cache(self.backend_name, VERSION=2)
- self.custom_key_cache = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION=custom_key_func)
- self.custom_key_cache2 = get_cache(self.backend_name, OPTIONS={'MAX_ENTRIES': 30}, KEY_FUNCTION='cache.tests.custom_key_func')
+ <