diff options
author | Sean Reifschneider <jafo00@gmail.com> | 2023-04-15 19:43:20 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-15 19:43:20 -0600 |
commit | 9cae205236f6585d388731711bffebe4330177c6 (patch) | |
tree | 86c493b6ce40058673a79b3cb8094a115e603d16 | |
parent | d39de3caddcd5a64cf40c82140627b2406cf6573 (diff) | |
parent | cea9fd0abdbf84ef6c9d7693c2e65268672579b5 (diff) | |
download | python-memcached-9cae205236f6585d388731711bffebe4330177c6.tar.gz |
Merge branch 'master' into fix-crc-0-hash
-rw-r--r-- | .travis.yml | 8 | ||||
-rw-r--r-- | memcache.py | 51 | ||||
-rw-r--r-- | setup.py | 12 | ||||
-rw-r--r-- | tests/test_memcache.py | 19 | ||||
-rw-r--r-- | tox.ini | 2 |
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 @@ -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): @@ -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] |