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