diff options
| author | Jon Parise <jon@pinterest.com> | 2019-08-05 12:52:12 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-08-05 12:52:12 -0700 |
| commit | 7ad74da1c242a735bd805c836f3ddf5830b19a83 (patch) | |
| tree | b1a91714b32bc3340a3932d99526b5a801ba450f | |
| parent | de558b56cab9fa36576158a2ffa7783f0246ba16 (diff) | |
| download | pymemcache-7ad74da1c242a735bd805c836f3ddf5830b19a83.tar.gz | |
Fix flags when setting multiple values at once (#248)v2.2.1
We introduced the ability to override the serializer-returned flags
values in 26f7c1b1. Unfortunately, there was a flaw in that logic which
resulted in the first item's flags being used for all later items. This
bug primarily affected set_many()'s behavior when the data dictionary
contained multiple different value types which were assigned different
per-value flags values by the serializer.
For example:
set_many({'a': 'string', 'b': 10})
If a serializer returned different flags for strings (e.g. 1) and
integer values (e.g. 2), the previous logic would have set ``flags``
to 1 the first time through the loop and repeated that value for the
second item, instead of using 2.
This was the intended behavior when ``flags`` was explicitly passed to
set_many(), but not for the default case where we still want to respect
the flags values returned by the serializer.
| -rw-r--r-- | ChangeLog.rst | 4 | ||||
| -rw-r--r-- | pymemcache/__init__.py | 2 | ||||
| -rw-r--r-- | pymemcache/client/base.py | 17 | ||||
| -rw-r--r-- | pymemcache/test/test_client.py | 34 |
4 files changed, 47 insertions, 10 deletions
diff --git a/ChangeLog.rst b/ChangeLog.rst index ccb30ee..c8d6376 100644 --- a/ChangeLog.rst +++ b/ChangeLog.rst @@ -1,6 +1,10 @@ Change Log ========== +New in version 2.2.1 +-------------------- +* Fix ``flags`` when setting multiple differently-typed values at once. + New in version 2.2.0 -------------------- * Drop official support for Python 3.4. diff --git a/pymemcache/__init__.py b/pymemcache/__init__.py index 984d042..ae051ba 100644 --- a/pymemcache/__init__.py +++ b/pymemcache/__init__.py @@ -1,4 +1,4 @@ -__version__ = '2.2.0' +__version__ = '2.2.1' from pymemcache.client.base import Client # noqa from pymemcache.client.base import PooledClient # noqa diff --git a/pymemcache/client/base.py b/pymemcache/client/base.py index 8dd1191..02c70d9 100644 --- a/pymemcache/client/base.py +++ b/pymemcache/client/base.py @@ -854,15 +854,14 @@ class Client(object): key = self.check_key(key) if self.serializer: - data, serializer_flags = self.serializer(key, data) - # Use the serializer's flags if the caller hasn't specified an - # explicit, overridding value. - if flags is None: - flags = serializer_flags + data, data_flags = self.serializer(key, data) + else: + data_flags = 0 - # Set flags to 0 if none were provided by the caller or serializer. - if flags is None: - flags = 0 + # If 'flags' was explicitly provided, it overrides the value + # returned by the serializer. + if flags is not None: + data_flags = flags if not isinstance(data, six.binary_type): try: @@ -872,7 +871,7 @@ class Client(object): "Data values must be binary-safe: %s" % e) cmds.append(name + b' ' + key + b' ' + - six.text_type(flags).encode(self.encoding) + + six.text_type(data_flags).encode(self.encoding) + b' ' + expire + b' ' + six.text_type(len(data)).encode(self.encoding) + extra + b'\r\n' + data + b'\r\n') diff --git a/pymemcache/test/test_client.py b/pymemcache/test/test_client.py index 773bac9..0cebf32 100644 --- a/pymemcache/test/test_client.py +++ b/pymemcache/test/test_client.py @@ -674,6 +674,40 @@ class TestClient(ClientTestMixin, unittest.TestCase): b'set key 0 0 10 noreply\r\n{"c": "d"}\r\n' ] + def test_serialization_flags(self): + def _ser(key, value): + return value, 1 if isinstance(value, int) else 0 + + client = self.make_client( + [b'STORED\r\n', b'STORED\r\n'], serializer=_ser) + client.set_many( + collections.OrderedDict([(b'a', b's'), (b'b', 0)]), noreply=False) + assert client.sock.send_bufs == [ + b'set a 0 0 1\r\ns\r\nset b 1 0 1\r\n0\r\n' + ] + + def test_serialization_overridden_flags(self): + def _ser(key, value): + return value, 1 if isinstance(value, int) else 0 + + client = self.make_client( + [b'STORED\r\n', b'STORED\r\n'], serializer=_ser) + client.set_many( + collections.OrderedDict([(b'a', b's'), (b'b', 0)]), + noreply=False, flags=5) + assert client.sock.send_bufs == [ + b'set a 5 0 1\r\ns\r\nset b 5 0 1\r\n0\r\n' + ] + + def test_explicit_flags(self): + client = self.make_client([b'STORED\r\n', b'STORED\r\n']) + client.set_many( + collections.OrderedDict([(b'a', b's'), (b'b', 0)]), + noreply=False, flags=5) + assert client.sock.send_bufs == [ + b'set a 5 0 1\r\ns\r\nset b 5 0 1\r\n0\r\n' + ] + def test_set_socket_handling(self): client = self.make_client([b'STORED\r\n']) result = client.set(b'key', b'value', noreply=False) |
