summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2020-12-09 21:27:32 +0100
committerGitHub <noreply@github.com>2020-12-09 21:27:32 +0100
commit5ce31d6a7142ca8c76d6b52fa42b3406b9a8ff48 (patch)
treee1e99006ce06ced4175767998ba684e9dd0ee4b7
parent2c5d6dc44779448de1497f32c925c96975fae461 (diff)
Fixed #32193 -- Deprecated MemcachedCache.
-rw-r--r--django/core/cache/__init__.py5
-rw-r--r--django/core/cache/backends/memcached.py7
-rw-r--r--docs/internals/deprecation.txt2
-rw-r--r--docs/ref/settings.txt3
-rw-r--r--docs/releases/3.2.txt5
-rw-r--r--docs/topics/cache.txt39
-rw-r--r--tests/cache/tests.py50
-rw-r--r--tests/requirements/py3.txt1
-rwxr-xr-xtests/runtests.py6
9 files changed, 78 insertions, 40 deletions
diff --git a/django/core/cache/__init__.py b/django/core/cache/__init__.py
index 1da58153f4..05ef3897d0 100644
--- a/django/core/cache/__init__.py
+++ b/django/core/cache/__init__.py
@@ -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()
diff --git a/django/core/cache/backends/memcached.py b/django/core/cache/backends/memcached.py
index cc5648bb1c..9a717359b8 100644
--- a/django/core/cache/backends/memcached.py
+++ b/django/core/cache/backends/memcached.py
@@ -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
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index 06ea0fbbc0..b53552bb0a 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -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
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 606ef98744..bfa62f1508 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -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
diff --git a/docs/releases/3.2.txt b/docs/releases/3.2.txt
index 2ab8546026..d5047dfe60 100644
--- a/docs/releases/3.2.txt
+++ b/docs/releases/3.2.txt
@@ -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.
diff --git a/docs/topics/cache.txt b/docs/topics/cache.txt
index ce9a982a23..66551fc8fe 100644
--- a/docs/topics/cache.txt
+++ b/docs/topics/cache.txt
@@ -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::
diff --git a/tests/cache/tests.py b/tests/cache/tests.py
index df0483d26e..2853ada233 100644
--- a/tests/cache/tests.py
+++ b/tests/cache/tests.py
@@ -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,
diff --git a/tests/requirements/py3.txt b/tests/requirements/py3.txt
index a51bda55ad..98f9ae94fd 100644
--- a/tests/requirements/py3.txt
+++ b/tests/requirements/py3.txt
@@ -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'
diff --git a/tests/runtests.py b/tests/runtests.py
index fa933306cd..ad282ce782 100755
--- a/tests/runtests.py
+++ b/tests/runtests.py
@@ -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__))