Skip to content

Commit e526a11

Browse files
niconoetimgraham
authored andcommitted
Fix #79, #80 -- Fix storing non-ASCII values on Python 2 and binary values on Python 3
1 parent cc94e72 commit e526a11

File tree

3 files changed

+44
-9
lines changed

3 files changed

+44
-9
lines changed

ChangeLog

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
* Add flake8 testing and cleanups (PR from Tim Graham, cleanups from Sean
1414
Reifschneider) #112
1515

16+
* Fixed storing non-ASCII values on Python 2 and binary values on Python 3
17+
(PR from Nicolas Noé) #135
18+
1619
Fri, 27 May 2016 13:44:55 -0600 Sean Reifschneider <jafo@tummy.com>
1720

1821
* 1.58 release.

memcache.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ class Client(threading.local):
134134
_FLAG_INTEGER = 1 << 1
135135
_FLAG_LONG = 1 << 2
136136
_FLAG_COMPRESSED = 1 << 3
137+
_FLAG_TEXT = 1 << 4
137138

138139
_SERVER_RETRIES = 10 # how many times to try finding a free server.
139140

@@ -955,11 +956,16 @@ def _val_to_store_info(self, val, min_compress_len):
955956
the new value itself.
956957
"""
957958
flags = 0
958-
if isinstance(val, six.binary_type):
959+
# Check against the exact type, rather than using isinstance(), so that
960+
# subclasses of native types (such as markup-safe strings) are pickled
961+
# and restored as instances of the correct class.
962+
val_type = type(val)
963+
if val_type == six.binary_type:
959964
pass
960-
elif isinstance(val, six.text_type):
965+
elif val_type == six.text_type:
966+
flags |= Client._FLAG_TEXT
961967
val = val.encode('utf-8')
962-
elif isinstance(val, int):
968+
elif val_type == int:
963969
flags |= Client._FLAG_INTEGER
964970
val = '%d' % val
965971
if six.PY3:
@@ -1250,13 +1256,11 @@ def _recv_value(self, server, flags, rlen):
12501256
if flags & Client._FLAG_COMPRESSED:
12511257
buf = self.decompressor(buf)
12521258
flags &= ~Client._FLAG_COMPRESSED
1253-
12541259
if flags == 0:
1255-
# Bare string
1256-
if six.PY3:
1257-
val = buf.decode('utf8')
1258-
else:
1259-
val = buf
1260+
# Bare bytes
1261+
val = buf
1262+
elif flags & Client._FLAG_TEXT:
1263+
val = buf.decode('utf-8')
12601264
elif flags & Client._FLAG_INTEGER:
12611265
val = int(buf)
12621266
elif flags & Client._FLAG_LONG:

tests/test_memcache.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
# -*- coding: utf-8 -*-
12
from __future__ import print_function
23

34
import unittest
5+
import zlib
46

57
import mock
68
import six
@@ -128,6 +130,32 @@ def test_unicode_key(self):
128130
value = self.mc.get(key)
129131
self.assertEqual(value, 5)
130132

133+
def test_unicode_value(self):
134+
key = 'key'
135+
value = six.u('Iñtërnâtiônàlizætiøn2')
136+
self.mc.set(key, value)
137+
cached_value = self.mc.get(key)
138+
self.assertEqual(value, cached_value)
139+
140+
def test_binary_string(self):
141+
value = 'value_to_be_compressed'
142+
compressed_value = zlib.compress(value.encode())
143+
144+
self.mc.set('binary1', compressed_value)
145+
compressed_result = self.mc.get('binary1')
146+
self.assertEqual(compressed_value, compressed_result)
147+
self.assertEqual(value, zlib.decompress(compressed_result).decode())
148+
149+
self.mc.add('binary1-add', compressed_value)
150+
compressed_result = self.mc.get('binary1-add')
151+
self.assertEqual(compressed_value, compressed_result)
152+
self.assertEqual(value, zlib.decompress(compressed_result).decode())
153+
154+
self.mc.set_multi({'binary1-set_many': compressed_value})
155+
compressed_result = self.mc.get('binary1-set_many')
156+
self.assertEqual(compressed_value, compressed_result)
157+
self.assertEqual(value, zlib.decompress(compressed_result).decode())
158+
131159
def test_ignore_too_large_value(self):
132160
# NOTE: "MemCached: while expecting[...]" is normal...
133161
key = 'keyhere'

0 commit comments

Comments
 (0)