Skip to content

Commit dfb85a2

Browse files
committed
Fix issues 130 and 131: Support Lua in Python 3 and improve mock signatures
1 parent ba41d90 commit dfb85a2

File tree

4 files changed

+58
-10
lines changed

4 files changed

+58
-10
lines changed

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ Use pip:
1414
## Usage
1515

1616
Both `mockredis.mock_redis_client` and `mockredis.mock_strict_redis_client` can be
17-
used to patch instances of the *redis client*.
17+
used to patch instances of the *redis client*, and `get_mock_redis_client_creator`
18+
can be used to create a generator for more flexible mocks.
1819

1920
For example, using the [mock][mock] library:
2021

@@ -24,6 +25,11 @@ Or:
2425

2526
@patch('redis.StrictRedis', mock_strict_redis_client)
2627

28+
Or, for more control:
29+
30+
@patch('redis.Redis', get_mock_redis_client_creator(load_lua_dependencies=False))
31+
@patch('redis.StrictRedis', get_mock_redis_client_creator(strict=True, clock=my_frozen_clock))
32+
2733
## Testing
2834

2935
Many unit tests exist to verify correctness of mock functionality. In addition, most

mockredis/client.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1561,7 +1561,7 @@ def get_total_milliseconds(td):
15611561
return int((td.days * 24 * 60 * 60 + td.seconds) * 1000 + td.microseconds / 1000.0)
15621562

15631563

1564-
def mock_redis_client(**kwargs):
1564+
def mock_redis_client(*_, **__):
15651565
"""
15661566
Mock common.util.redis_client so we
15671567
can return a MockRedis object
@@ -1572,7 +1572,7 @@ def mock_redis_client(**kwargs):
15721572
mock_redis_client.from_url = mock_redis_client
15731573

15741574

1575-
def mock_strict_redis_client(**kwargs):
1575+
def mock_strict_redis_client(*_, **__):
15761576
"""
15771577
Mock common.util.redis_client so we
15781578
can return a MockRedis object
@@ -1581,3 +1581,22 @@ def mock_strict_redis_client(**kwargs):
15811581
return MockRedis(strict=True)
15821582

15831583
mock_strict_redis_client.from_url = mock_strict_redis_client
1584+
1585+
1586+
def get_mock_redis_client_creator(**kwargs):
1587+
"""
1588+
Generate a getter for a MockRedis
1589+
object that passes the given kwargs
1590+
to each MockRedis object instantiated
1591+
by the getter returned. Sample usage:
1592+
1593+
@mock.patch('redis.Redis', get_mock_redis_client_creator(load_lua_dependencies=False))
1594+
@mock.patch('redis.StrictRedis', get_mock_redis_client_creator(strict=True, clock=frozen_clock))
1595+
"""
1596+
1597+
def _getter(*_, **__):
1598+
return MockRedis(**kwargs)
1599+
1600+
_getter.from_url = _getter
1601+
1602+
return _getter

mockredis/script.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,26 @@
22
import threading
33
from mockredis.exceptions import ResponseError
44

5+
56
LuaLock = threading.Lock()
67

8+
if sys.version_info[0] == 3:
9+
_string_types = (str, )
10+
_integer_types = (int, )
11+
_number_types = (int, float)
12+
_string_or_binary_types = (str, bytes)
13+
_binary_type = bytes
14+
_long_type = int
15+
_iteritems = lambda d, **kw: iter(d.items(**kw))
16+
else:
17+
_string_types = (basestring, )
18+
_integer_types = (int, long)
19+
_number_types = (int, long, float)
20+
_string_or_binary_types = (basestring, )
21+
_binary_type = str
22+
_long_type = long
23+
_iteritems = lambda d, **kw: d.iteritems(**kw)
24+
725

826
class Script(object):
927
"""
@@ -47,7 +65,10 @@ def _call(*call_args):
4765
response = client.call(*call_args)
4866
return self._python_to_lua(response)
4967

50-
lua_globals.redis = {"call": _call}
68+
def _error_reply(err):
69+
return self._python_to_lua({'err': err})
70+
71+
lua_globals.redis = {'call': _call, 'error_reply', _error_reply}
5172
return self._lua_to_python(lua.execute(self.script), return_status=True)
5273

5374
@staticmethod
@@ -115,11 +136,13 @@ def _lua_to_python(lval, return_status=False):
115136
return lval[i]
116137
if i == 'err':
117138
raise ResponseError(lval[i])
139+
if lval[i] == 'err':
140+
raise ResponseError(lval[i + 1])
118141
pval.append(Script._lua_to_python(lval[i]))
119142
return pval
120-
elif isinstance(lval, long):
143+
elif isinstance(lval, _integer_types):
121144
# Lua number --> Python long
122-
return long(lval)
145+
return _long_type(lval)
123146
elif isinstance(lval, float):
124147
# Lua number --> Python float
125148
return float(lval)
@@ -161,17 +184,17 @@ def _python_to_lua(pval):
161184
# in Lua returns: {k1, v1, k2, v2, k3, v3}
162185
lua_dict = lua.eval("{}")
163186
lua_table = lua.eval("table")
164-
for k, v in pval.iteritems():
187+
for k, v in _iteritems(pval):
165188
lua_table.insert(lua_dict, Script._python_to_lua(k))
166189
lua_table.insert(lua_dict, Script._python_to_lua(v))
167190
return lua_dict
168-
elif isinstance(pval, str):
191+
elif isinstance(pval, _string_or_binary_types):
169192
# Python string --> Lua userdata
170193
return pval
171194
elif isinstance(pval, bool):
172195
# Python bool--> Lua boolean
173196
return lua.eval(str(pval).lower())
174-
elif isinstance(pval, (int, long, float)):
197+
elif isinstance(pval, _number_types):
175198
# Python int --> Lua number
176199
lua_globals = lua.globals()
177200
return lua_globals.tonumber(str(pval))

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
'nose'
1919
],
2020
extras_require={
21-
'lua': ['lunatic-python-bugfix==1.1.1'],
21+
'lua': ['lunatic-python-universal~=2.0'],
2222
},
2323
tests_require=[
2424
'redis>=2.9.0'

0 commit comments

Comments
 (0)