Commit 686d6a41 authored by Malcolm Tredinnick's avatar Malcolm Tredinnick
Browse files

[1.2.X] Add warning when using cache keys that might not work with

memcached.

This means testing with local dev caches (not memcache) will warn
developers if they are introducing inadvertent importabilities.  There
is also the ability to silence the warning if a dev is not planning to
use memcache and knows what they are doing with their keys.

Thanks to Carl Meyer for the patch. Fixed #6447.

Backport of r13766 from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@13767 bcc190cf-cafb-0310-a4f2-bffc1f526a37
parent 6bc74f06
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -18,7 +18,7 @@ See docs/cache.txt for information on the public API.
from cgi import parse_qsl
from django.conf import settings
from django.core import signals
from django.core.cache.backends.base import InvalidCacheBackendError
from django.core.cache.backends.base import InvalidCacheBackendError, CacheKeyWarning
from django.utils import importlib

# Name for use in settings file --> name of module in "backends" directory.
+27 −1
Original line number Diff line number Diff line
"Base Cache class."

from django.core.exceptions import ImproperlyConfigured
import warnings

from django.core.exceptions import ImproperlyConfigured, DjangoRuntimeWarning

class InvalidCacheBackendError(ImproperlyConfigured):
    pass

class CacheKeyWarning(DjangoRuntimeWarning):
    pass

# Memcached does not accept keys longer than this.
MEMCACHE_MAX_KEY_LENGTH = 250

class BaseCache(object):
    def __init__(self, params):
        timeout = params.get('timeout', 300)
@@ -116,3 +124,21 @@ class BaseCache(object):
    def clear(self):
        """Remove *all* values from the cache at once."""
        raise NotImplementedError

    def validate_key(self, key):
        """
        Warn about keys that would not be portable to the memcached
        backend. This encourages (but does not force) writing backend-portable
        cache code.

        """
        if len(key) > MEMCACHE_MAX_KEY_LENGTH:
            warnings.warn('Cache key will cause errors if used with memcached: '
                    '%s (longer than %s)' % (key, MEMCACHE_MAX_KEY_LENGTH),
                    CacheKeyWarning)
        for char in key:
            if ord(char) < 33 or ord(char) == 127:
                warnings.warn('Cache key contains characters that will cause '
                        'errors if used with memcached: %r' % key,
                              CacheKeyWarning)
+5 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ class CacheClass(BaseCache):
            self._cull_frequency = 3

    def get(self, key, default=None):
        self.validate_key(key)
        db = router.db_for_read(self.cache_model_class)
        table = connections[db].ops.quote_name(self._table)
        cursor = connections[db].cursor()
@@ -65,9 +66,11 @@ class CacheClass(BaseCache):
        return pickle.loads(base64.decodestring(value))

    def set(self, key, value, timeout=None):
        self.validate_key(key)
        self._base_set('set', key, value, timeout)

    def add(self, key, value, timeout=None):
        self.validate_key(key)
        return self._base_set('add', key, value, timeout)

    def _base_set(self, mode, key, value, timeout=None):
@@ -103,6 +106,7 @@ class CacheClass(BaseCache):
            return True

    def delete(self, key):
        self.validate_key(key)
        db = router.db_for_write(self.cache_model_class)
        table = connections[db].ops.quote_name(self._table)
        cursor = connections[db].cursor()
@@ -111,6 +115,7 @@ class CacheClass(BaseCache):
        transaction.commit_unless_managed(using=db)

    def has_key(self, key):
        self.validate_key(key)
        db = router.db_for_read(self.cache_model_class)
        table = connections[db].ops.quote_name(self._table)
        cursor = connections[db].cursor()
+9 −6
Original line number Diff line number Diff line
@@ -6,22 +6,25 @@ class CacheClass(BaseCache):
    def __init__(self, *args, **kwargs):
        pass

    def add(self, *args, **kwargs):
    def add(self, key, *args, **kwargs):
        self.validate_key(key)
        return True

    def get(self, key, default=None):
        self.validate_key(key)
        return default

    def set(self, *args, **kwargs):
        pass
    def set(self, key, *args, **kwargs):
        self.validate_key(key)

    def delete(self, *args, **kwargs):
        pass
    def delete(self, key, *args, **kwargs):
        self.validate_key(key)

    def get_many(self, *args, **kwargs):
        return {}

    def has_key(self, *args, **kwargs):
    def has_key(self, key, *args, **kwargs):
        self.validate_key(key)
        return False

    def set_many(self, *args, **kwargs):
+5 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ class CacheClass(BaseCache):
            self._createdir()

    def add(self, key, value, timeout=None):
        self.validate_key(key)
        if self.has_key(key):
            return False

@@ -39,6 +40,7 @@ class CacheClass(BaseCache):
        return True

    def get(self, key, default=None):
        self.validate_key(key)
        fname = self._key_to_file(key)
        try:
            f = open(fname, 'rb')
@@ -56,6 +58,7 @@ class CacheClass(BaseCache):
        return default

    def set(self, key, value, timeout=None):
        self.validate_key(key)
        fname = self._key_to_file(key)
        dirname = os.path.dirname(fname)

@@ -79,6 +82,7 @@ class CacheClass(BaseCache):
            pass

    def delete(self, key):
        self.validate_key(key)
        try:
            self._delete(self._key_to_file(key))
        except (IOError, OSError):
@@ -95,6 +99,7 @@ class CacheClass(BaseCache):
            pass

    def has_key(self, key):
        self.validate_key(key)
        fname = self._key_to_file(key)
        try:
            f = open(fname, 'rb')
Loading