mirror of https://github.com/django/django.git
Fixed #32193 -- Deprecated MemcachedCache.
This commit is contained in:
parent
2c5d6dc447
commit
5ce31d6a71
|
@ -50,9 +50,8 @@ cache = ConnectionProxy(caches, DEFAULT_CACHE_ALIAS)
|
|||
|
||||
|
||||
def close_caches(**kwargs):
|
||||
# Some caches -- python-memcached in particular -- need to do a cleanup at the
|
||||
# end of a request cycle. If not implemented in a particular backend
|
||||
# cache.close is a no-op
|
||||
# Some caches need to do a cleanup at the end of a request cycle. If not
|
||||
# implemented in a particular backend cache.close() is a no-op.
|
||||
for cache in caches.all():
|
||||
cache.close()
|
||||
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
import pickle
|
||||
import re
|
||||
import time
|
||||
import warnings
|
||||
|
||||
from django.core.cache.backends.base import (
|
||||
DEFAULT_TIMEOUT, BaseCache, InvalidCacheKey, memcache_key_warnings,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango41Warning
|
||||
from django.utils.functional import cached_property
|
||||
|
||||
|
||||
|
@ -164,6 +166,11 @@ class BaseMemcachedCache(BaseCache):
|
|||
class MemcachedCache(BaseMemcachedCache):
|
||||
"An implementation of a cache binding using python-memcached"
|
||||
def __init__(self, server, params):
|
||||
warnings.warn(
|
||||
'MemcachedCache is deprecated in favor of PyMemcacheCache and '
|
||||
'PyLibMCCache.',
|
||||
RemovedInDjango41Warning, stacklevel=2,
|
||||
)
|
||||
# python-memcached ≥ 1.45 returns None for a nonexistent key in
|
||||
# incr/decr(), python-memcached < 1.45 raises ValueError.
|
||||
import memcache
|
||||
|
|
|
@ -29,6 +29,8 @@ details on these changes.
|
|||
* ``TransactionTestCase.assertQuerysetEqual()` will no longer automatically
|
||||
call ``repr()`` on a queryset when compared to string values.
|
||||
|
||||
* ``django.core.cache.backends.memcached.MemcachedCache`` will be removed.
|
||||
|
||||
.. _deprecation-removed-in-4.0:
|
||||
|
||||
4.0
|
||||
|
|
|
@ -156,9 +156,8 @@ The cache backend to use. The built-in cache backends are:
|
|||
* ``'django.core.cache.backends.dummy.DummyCache'``
|
||||
* ``'django.core.cache.backends.filebased.FileBasedCache'``
|
||||
* ``'django.core.cache.backends.locmem.LocMemCache'``
|
||||
* ``'django.core.cache.backends.memcached.MemcachedCache'``
|
||||
* ``'django.core.cache.backends.memcached.PyLibMCCache'``
|
||||
* ``'django.core.cache.backends.memcached.PyMemcacheCache'``
|
||||
* ``'django.core.cache.backends.memcached.PyLibMCCache'``
|
||||
|
||||
You can use a cache backend that doesn't ship with Django by setting
|
||||
:setting:`BACKEND <CACHES-BACKEND>` to a fully-qualified path of a cache
|
||||
|
|
|
@ -660,3 +660,8 @@ Miscellaneous
|
|||
``TransactionTestCase.assertQuerysetEqual()``, when compared to string
|
||||
values, is deprecated. If you need the previous behavior, explicitly set
|
||||
``transform`` to ``repr``.
|
||||
|
||||
* The ``django.core.cache.backends.memcached.MemcachedCache`` backend is
|
||||
deprecated as ``python-memcached`` has some problems and seems to be
|
||||
unmaintained. Use ``django.core.cache.backends.memcached.PyMemcacheCache``
|
||||
or ``django.core.cache.backends.memcached.PyLibMCCache`` instead.
|
||||
|
|
|
@ -77,18 +77,16 @@ database or filesystem usage.
|
|||
|
||||
After installing Memcached itself, you'll need to install a Memcached
|
||||
binding. There are several Python Memcached bindings available; the
|
||||
three most common are `python-memcached`_, `pylibmc`_, and `pymemcache`_.
|
||||
two supported by Django are `pylibmc`_ and `pymemcache`_.
|
||||
|
||||
.. _`python-memcached`: https://pypi.org/project/python-memcached/
|
||||
.. _`pylibmc`: https://pypi.org/project/pylibmc/
|
||||
.. _`pymemcache`: https://pypi.org/project/pymemcache/
|
||||
|
||||
To use Memcached with Django:
|
||||
|
||||
* Set :setting:`BACKEND <CACHES-BACKEND>` to
|
||||
``django.core.cache.backends.memcached.MemcachedCache``,
|
||||
``django.core.cache.backends.memcached.PyLibMCCache``, or
|
||||
``django.core.cache.backends.memcached.PyMemcacheCache`` (depending on your
|
||||
``django.core.cache.backends.memcached.PyMemcacheCache`` or
|
||||
``django.core.cache.backends.memcached.PyLibMCCache`` (depending on your
|
||||
chosen memcached binding)
|
||||
|
||||
* Set :setting:`LOCATION <CACHES-LOCATION>` to ``ip:port`` values,
|
||||
|
@ -97,21 +95,21 @@ To use Memcached with Django:
|
|||
``path`` is the path to a Memcached Unix socket file.
|
||||
|
||||
In this example, Memcached is running on localhost (127.0.0.1) port 11211, using
|
||||
the ``python-memcached`` binding::
|
||||
the ``pymemcache`` binding::
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
In this example, Memcached is available through a local Unix socket file
|
||||
:file:`/tmp/memcached.sock` using the ``python-memcached`` binding::
|
||||
:file:`/tmp/memcached.sock` using the ``pymemcache`` binding::
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'LOCATION': 'unix:/tmp/memcached.sock',
|
||||
}
|
||||
}
|
||||
|
@ -129,7 +127,7 @@ address 172.19.26.240 and 172.19.26.242, both on port 11211::
|
|||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'LOCATION': [
|
||||
'172.19.26.240:11211',
|
||||
'172.19.26.242:11211',
|
||||
|
@ -143,7 +141,7 @@ on the IP addresses 172.19.26.240 (port 11211), 172.19.26.242 (port 11212), and
|
|||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
||||
'LOCATION': [
|
||||
'172.19.26.240:11211',
|
||||
'172.19.26.242:11212',
|
||||
|
@ -165,6 +163,12 @@ particularly temporary.
|
|||
|
||||
The ``PyMemcacheCache`` backend was added.
|
||||
|
||||
.. deprecated:: 3.2
|
||||
|
||||
The ``MemcachedCache`` backend is deprecated as ``python-memcached`` has
|
||||
some problems and seems to be unmaintained. Use ``PyMemcacheCache`` or
|
||||
``PyLibMCCache`` instead.
|
||||
|
||||
.. _database-caching:
|
||||
|
||||
Database caching
|
||||
|
@ -452,19 +456,6 @@ of 60 seconds, and a maximum capacity of 1000 items::
|
|||
}
|
||||
}
|
||||
|
||||
Here's an example configuration for a ``python-memcached`` based backend with
|
||||
an object size limit of 2MB::
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
'OPTIONS': {
|
||||
'server_max_value_length': 1024 * 1024 * 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Here's an example configuration for a ``pylibmc`` based backend that enables
|
||||
the binary protocol, SASL authentication, and the ``ketama`` behavior mode::
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import tempfile
|
|||
import threading
|
||||
import time
|
||||
import unittest
|
||||
import warnings
|
||||
from pathlib import Path
|
||||
from unittest import mock, skipIf
|
||||
|
||||
|
@ -35,13 +36,14 @@ from django.template.context_processors import csrf
|
|||
from django.template.response import TemplateResponse
|
||||
from django.test import (
|
||||
RequestFactory, SimpleTestCase, TestCase, TransactionTestCase,
|
||||
override_settings,
|
||||
ignore_warnings, override_settings,
|
||||
)
|
||||
from django.test.signals import setting_changed
|
||||
from django.utils import timezone, translation
|
||||
from django.utils.cache import (
|
||||
get_cache_key, learn_cache_key, patch_cache_control, patch_vary_headers,
|
||||
)
|
||||
from django.utils.deprecation import RemovedInDjango41Warning
|
||||
from django.views.decorators.cache import cache_control, cache_page
|
||||
|
||||
from .models import Poll, expensive_calculation
|
||||
|
@ -1276,7 +1278,6 @@ configured_caches = {}
|
|||
for _cache_params in settings.CACHES.values():
|
||||
configured_caches[_cache_params['BACKEND']] = _cache_params
|
||||
|
||||
MemcachedCache_params = configured_caches.get('django.core.cache.backends.memcached.MemcachedCache')
|
||||
PyLibMCCache_params = configured_caches.get('django.core.cache.backends.memcached.PyLibMCCache')
|
||||
PyMemcacheCache_params = configured_caches.get('django.core.cache.backends.memcached.PyMemcacheCache')
|
||||
|
||||
|
@ -1349,10 +1350,7 @@ class BaseMemcachedTests(BaseCacheTests):
|
|||
# By default memcached allows objects up to 1MB. For the cache_db session
|
||||
# backend to always use the current session, memcached needs to delete
|
||||
# the old key if it fails to set.
|
||||
# pylibmc doesn't seem to have SERVER_MAX_VALUE_LENGTH as far as I can
|
||||
# tell from a quick check of its source code. This is falling back to
|
||||
# the default value exposed by python-memcached on my system.
|
||||
max_value_length = getattr(cache._lib, 'SERVER_MAX_VALUE_LENGTH', 1048576)
|
||||
max_value_length = 2 ** 20
|
||||
|
||||
cache.set('small_value', 'a')
|
||||
self.assertEqual(cache.get('small_value'), 'a')
|
||||
|
@ -1361,11 +1359,10 @@ class BaseMemcachedTests(BaseCacheTests):
|
|||
try:
|
||||
cache.set('small_value', large_value)
|
||||
except Exception:
|
||||
# Some clients (e.g. pylibmc) raise when the value is too large,
|
||||
# while others (e.g. python-memcached) intentionally return True
|
||||
# indicating success. This test is primarily checking that the key
|
||||
# was deleted, so the return/exception behavior for the set()
|
||||
# itself is not important.
|
||||
# Most clients (e.g. pymemcache or pylibmc) raise when the value is
|
||||
# too large. This test is primarily checking that the key was
|
||||
# deleted, so the return/exception behavior for the set() itself is
|
||||
# not important.
|
||||
pass
|
||||
# small_value should be deleted, or set if configured to accept larger values
|
||||
value = cache.get('small_value')
|
||||
|
@ -1390,6 +1387,11 @@ class BaseMemcachedTests(BaseCacheTests):
|
|||
self.assertEqual(failing_keys, ['key'])
|
||||
|
||||
|
||||
# RemovedInDjango41Warning.
|
||||
MemcachedCache_params = configured_caches.get('django.core.cache.backends.memcached.MemcachedCache')
|
||||
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango41Warning)
|
||||
@unittest.skipUnless(MemcachedCache_params, "MemcachedCache backend not configured")
|
||||
@override_settings(CACHES=caches_setting_for_tests(
|
||||
base=MemcachedCache_params,
|
||||
|
@ -1421,6 +1423,32 @@ class MemcachedCacheTests(BaseMemcachedTests, TestCase):
|
|||
self.assertEqual(cache.get('key_default_none', default='default'), 'default')
|
||||
|
||||
|
||||
class MemcachedCacheDeprecationTests(SimpleTestCase):
|
||||
def test_warning(self):
|
||||
from django.core.cache.backends.memcached import MemcachedCache
|
||||
|
||||
# Remove warnings filter on MemcachedCache deprecation warning, added
|
||||
# in runtests.py.
|
||||
warnings.filterwarnings(
|
||||
'error',
|
||||
'MemcachedCache is deprecated',
|
||||
category=RemovedInDjango41Warning,
|
||||
)
|
||||
try:
|
||||
msg = (
|
||||
'MemcachedCache is deprecated in favor of PyMemcacheCache and '
|
||||
'PyLibMCCache.'
|
||||
)
|
||||
with self.assertRaisesMessage(RemovedInDjango41Warning, msg):
|
||||
MemcachedCache('127.0.0.1:11211', {})
|
||||
finally:
|
||||
warnings.filterwarnings(
|
||||
'ignore',
|
||||
'MemcachedCache is deprecated',
|
||||
category=RemovedInDjango41Warning,
|
||||
)
|
||||
|
||||
|
||||
@unittest.skipUnless(PyLibMCCache_params, "PyLibMCCache backend not configured")
|
||||
@override_settings(CACHES=caches_setting_for_tests(
|
||||
base=PyLibMCCache_params,
|
||||
|
|
|
@ -9,6 +9,7 @@ Pillow >= 6.2.0
|
|||
# pylibmc/libmemcached can't be built on Windows.
|
||||
pylibmc; sys.platform != 'win32'
|
||||
pymemcache >= 3.4.0
|
||||
# RemovedInDjango41Warning.
|
||||
python-memcached >= 1.59
|
||||
pytz
|
||||
pywatchman; sys.platform != 'win32'
|
||||
|
|
|
@ -47,6 +47,12 @@ warnings.simplefilter("error", ResourceWarning)
|
|||
warnings.simplefilter("error", RuntimeWarning)
|
||||
# Ignore known warnings in test dependencies.
|
||||
warnings.filterwarnings("ignore", "'U' mode is deprecated", DeprecationWarning, module='docutils.io')
|
||||
# RemovedInDjango41Warning: Ignore MemcachedCache deprecation warning.
|
||||
warnings.filterwarnings(
|
||||
'ignore',
|
||||
'MemcachedCache is deprecated',
|
||||
category=RemovedInDjango41Warning,
|
||||
)
|
||||
|
||||
RUNTESTS_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
|
Loading…
Reference in New Issue