From c2071a965eaee21541b7158e2350b2779c60a9de Mon Sep 17 00:00:00 2001 From: Pankrat Date: Thu, 7 Oct 2021 10:09:51 +0200 Subject: [PATCH] Return default from hash client when using positional argument When using `HashClient` with `ignore_exc`, `get` would always return `None` if no server is available and the default is passed as a positional argument. The other clients return the default value in this case. An earlier fix only had the desired effect when passing `default` as a keyword argument. Return the default value so `HashClient` behaves like the other clients even when using Fixes another variation of issue #350 --- ChangeLog.rst | 5 +++++ pymemcache/client/hash.py | 5 ++--- pymemcache/test/test_client_hash.py | 17 +++++++++++++++-- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ChangeLog.rst b/ChangeLog.rst index a73b2194..cc448d91 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,6 +1,11 @@ Changelog ========= +Unreleased +---------- +* ``Client.get`` returns the default when using ``ignore_exc`` and if memcached + is unavailable + New in version 3.5.0 -------------------- * Sockets are now closed on ``MemcacheUnexpectedCloseError``. diff --git a/pymemcache/client/hash.py b/pymemcache/client/hash.py index db00d515..e5d89fe6 100644 --- a/pymemcache/client/hash.py +++ b/pymemcache/client/hash.py @@ -356,9 +356,8 @@ def close(self): def set(self, key, *args, **kwargs): return self._run_cmd('set', key, False, *args, **kwargs) - def get(self, key, *args, **kwargs): - default = kwargs.get('default', None) - return self._run_cmd('get', key, default, *args, **kwargs) + def get(self, key, default=None, **kwargs): + return self._run_cmd('get', key, default, default=default, **kwargs) def incr(self, key, *args, **kwargs): return self._run_cmd('incr', key, False, *args, **kwargs) diff --git a/pymemcache/test/test_client_hash.py b/pymemcache/test/test_client_hash.py index 9ce48aae..f747845f 100644 --- a/pymemcache/test/test_client_hash.py +++ b/pymemcache/test/test_client_hash.py @@ -262,6 +262,19 @@ def test_no_servers_left_with_commands_return_default_value(self): result = client.set('foo', 'bar') assert result is False + def test_no_servers_left_return_positional_default(self): + from pymemcache.client.hash import HashClient + client = HashClient( + [], use_pooling=True, + ignore_exc=True, + timeout=1, connect_timeout=1 + ) + + # Ensure compatibility with clients that pass the default as a + # positional argument + result = client.get('foo', 'default') + assert result == 'default' + def test_no_servers_left_with_set_many(self): from pymemcache.client.hash import HashClient client = HashClient( @@ -381,7 +394,7 @@ def test_dead_server_comes_back(self, client_patch): # Client gets removed because of socket timeout assert ("127.0.0.1", 11211) in client._dead_clients - test_client.get.side_effect = lambda *_: "Some value" + test_client.get.side_effect = lambda *_, **_kw: "Some value" # Client should be retried and brought back assert client.get(b"key") == "Some value" assert ("127.0.0.1", 11211) not in client._dead_clients @@ -400,7 +413,7 @@ def test_failed_is_retried(self, client_patch): with pytest.raises(socket.timeout): client.get(b"key", noreply=False) - test_client.get.side_effect = lambda *_: "Some value" + test_client.get.side_effect = lambda *_, **_kw: "Some value" assert client.get(b"key") == "Some value" assert client_patch.call_count == 1