summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Reifschneider <jafo00@gmail.com>2023-04-15 19:43:20 -0600
committerGitHub <noreply@github.com>2023-04-15 19:43:20 -0600
commit9cae205236f6585d388731711bffebe4330177c6 (patch)
tree86c493b6ce40058673a79b3cb8094a115e603d16
parentd39de3caddcd5a64cf40c82140627b2406cf6573 (diff)
parentcea9fd0abdbf84ef6c9d7693c2e65268672579b5 (diff)
downloadpython-memcached-9cae205236f6585d388731711bffebe4330177c6.tar.gz
Merge branch 'master' into fix-crc-0-hash
-rw-r--r--.travis.yml8
-rw-r--r--memcache.py51
-rw-r--r--setup.py12
-rw-r--r--tests/test_memcache.py19
-rw-r--r--tox.ini2
5 files changed, 58 insertions, 34 deletions
diff --git a/.travis.yml b/.travis.yml
index 47cb22e..aa98469 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,9 +1,11 @@
language: python
python:
- - 2.7
- - 3.4
- - 3.5
- 3.6
+ - 3.7
+ - 3.8
+ - 3.9
+ - 3.10
+ - 3.11
- pypy
services:
- memcached
diff --git a/memcache.py b/memcache.py
index 2658446..ea1080e 100644
--- a/memcache.py
+++ b/memcache.py
@@ -67,6 +67,8 @@ else:
def cmemcache_hash(key):
return ((binascii.crc32(key) & 0xffffffff) >> 16) & 0x7fff
+
+
serverHashFunction = cmemcache_hash
@@ -127,7 +129,7 @@ class Client(threading.local):
@group Integers: incr, decr
@group Removal: delete, delete_multi
@sort: __init__, set_servers, forget_dead_hosts, disconnect_all,
- debuglog,\ set, set_multi, add, replace, get, get_multi,
+ debuglog, set, set_multi, add, replace, get, get_multi,
incr, decr, delete, delete_multi
"""
_FLAG_PICKLE = 1 << 0
@@ -323,11 +325,13 @@ class Client(threading.local):
serverData = {}
data.append((name, serverData))
readline = s.readline
- while 1:
+ while True:
line = readline()
- if not line or line.decode('ascii').strip() == 'END':
+ if line:
+ line = line.decode('ascii')
+ if not line or line.strip() == 'END':
break
- stats = line.decode('ascii').split(' ', 2)
+ stats = line.split(' ', 2)
serverData[stats[1]] = stats[2]
return data
@@ -347,8 +351,10 @@ class Client(threading.local):
data.append((name, serverData))
s.send_cmd('stats slabs')
readline = s.readline
- while 1:
+ while True:
line = readline()
+ if line:
+ line = line.decode('ascii')
if not line or line.strip() == 'END':
break
item = line.split(' ', 2)
@@ -378,7 +384,7 @@ class Client(threading.local):
data.append((name, serverData))
s.send_cmd('stats items')
readline = s.readline
- while 1:
+ while True:
line = readline()
if not line or line.strip() == 'END':
break
@@ -800,8 +806,6 @@ class Client(threading.local):
# server. Returns the mangled key.
server, key = self._get_server(
(serverhash, key_prefix + key))
-
- orig_key = orig_key[1]
else:
key = self._encode_key(orig_key)
if not isinstance(key, six.binary_type):
@@ -1003,8 +1007,7 @@ class Client(threading.local):
val = comp_val
# silently do not store if value length exceeds maximum
- if (self.server_max_value_length != 0 and
- len(val) > self.server_max_value_length):
+ if (self.server_max_value_length != 0 and len(val) > self.server_max_value_length):
return 0
return (flags, len(val), val)
@@ -1059,7 +1062,7 @@ class Client(threading.local):
server.mark_dead(msg)
return 0
- def _get(self, cmd, key):
+ def _get(self, cmd, key, default=None):
key = self._encode_key(key)
if self.do_check_key:
self.check_key(key)
@@ -1088,7 +1091,7 @@ class Client(threading.local):
)
if not rkey:
- return None
+ return default
try:
value = self._recv_value(server, flags, rlen)
finally:
@@ -1113,12 +1116,12 @@ class Client(threading.local):
server.mark_dead(msg)
return None
- def get(self, key):
+ def get(self, key, default=None):
'''Retrieves a key from the memcache.
@return: The value or None.
'''
- return self._get('get', key)
+ return self._get('get', key, default)
def gets(self, key):
'''Retrieves a key from the memcache. Used in conjunction with 'cas'.
@@ -1300,8 +1303,8 @@ class Client(threading.local):
key = key[1]
if key is None:
raise Client.MemcachedKeyNoneError("Key is None")
- if key is '':
- if key_extra_len is 0:
+ if key == '':
+ if key_extra_len == 0:
raise Client.MemcachedKeyNoneError("Key is empty")
# key is empty but there is some other component to key
@@ -1310,8 +1313,7 @@ class Client(threading.local):
if not isinstance(key, six.binary_type):
raise Client.MemcachedKeyTypeError("Key must be a binary string")
- if (self.server_max_key_length != 0 and
- len(key) + key_extra_len > self.server_max_key_length):
+ if (self.server_max_key_length != 0 and len(key) + key_extra_len > self.server_max_key_length):
raise Client.MemcachedKeyLengthError(
"Key length is > %s" % self.server_max_key_length
)
@@ -1436,11 +1438,15 @@ class _Host(object):
If "raise_exception" is set, raise _ConnectionDeadError if the
read fails, otherwise return an empty string.
"""
+ def empty_bytes(_: int) -> bytes:
+ "Fake receiver that returns empty bytes when the socket isn't connected"
+ return b''
+
buf = self.buffer
if self.socket:
recv = self.socket.recv
else:
- recv = lambda bufsize: b''
+ recv = empty_bytes
while True:
index = buf.find(b'\r\n')
@@ -1462,11 +1468,8 @@ class _Host(object):
def expect(self, text, raise_exception=False):
line = self.readline(raise_exception)
if self.debug and line != text:
- if six.PY3:
- text = text.decode('utf8')
- log_line = line.decode('utf8', 'replace')
- else:
- log_line = line
+ text = text.decode('utf8')
+ log_line = line.decode('utf8', 'replace')
self.debuglog("while expecting %r, got unexpected response %r"
% (text, log_line))
return line
diff --git a/setup.py b/setup.py
index 93cbe4d..12da42a 100644
--- a/setup.py
+++ b/setup.py
@@ -10,12 +10,13 @@ setup(
version=version,
description="Pure python memcached client",
long_description=open("README.md").read(),
+ long_description_content_type="text/markdown",
author="Evan Martin",
author_email="martine@danga.com",
maintainer="Sean Reifschneider",
maintainer_email="jafo@tummy.com",
url="https://github.com/linsomniac/python-memcached",
- download_url="https://github.com/linsomniac/python-memcached/releases/download/{0}/python-memcached-{0}.tar.gz".format(version),
+ download_url="https://github.com/linsomniac/python-memcached/releases/download/{0}/python-memcached-{0}.tar.gz".format(version), # noqa
py_modules=["memcache"],
install_requires=open('requirements.txt').read().split(),
classifiers=[
@@ -27,11 +28,12 @@ setup(
"Topic :: Internet",
"Topic :: Software Development :: Libraries :: Python Modules",
"Programming Language :: Python",
- "Programming Language :: Python :: 2",
- "Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.4",
- "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
],
)
diff --git a/tests/test_memcache.py b/tests/test_memcache.py
index 40b6524..d0f4857 100644
--- a/tests/test_memcache.py
+++ b/tests/test_memcache.py
@@ -4,7 +4,10 @@ from __future__ import print_function
import unittest
import zlib
-import mock
+try:
+ import unittest.mock as mock
+except ImportError:
+ import mock
from memcache import Client, _Host, SERVER_MAX_KEY_LENGTH, SERVER_MAX_VALUE_LENGTH # noqa: H301
from .utils import captured_stderr
@@ -51,6 +54,20 @@ class TestMemcache(unittest.TestCase):
self.assertEqual(result, True)
self.assertEqual(self.mc.get("long"), None)
+ def test_default(self):
+ key = "default"
+ default = object()
+ result = self.mc.get(key, default=default)
+ self.assertEqual(result, default)
+
+ self.mc.set("default", None)
+ result = self.mc.get(key, default=default)
+ self.assertIsNone(result)
+
+ self.mc.set("default", 123)
+ result = self.mc.get(key, default=default)
+ self.assertEqual(result, 123)
+
@mock.patch.object(_Host, 'send_cmd')
@mock.patch.object(_Host, 'readline')
def test_touch(self, mock_readline, mock_send_cmd):
diff --git a/tox.ini b/tox.ini
index 7d4fc52..1e2a8f0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
[tox]
minversion = 1.6
-envlist = py27,py34,py35,p36,pypy,pep8
+envlist = py{36,37,38,39,310,311},pypy,pep8
skipsdist = True
[testenv]