diff options
-rwxr-xr-x | redis/client.py | 31 | ||||
-rw-r--r-- | tests/test_commands.py | 1 | ||||
-rw-r--r-- | tests/test_pipeline.py | 14 |
3 files changed, 37 insertions, 9 deletions
diff --git a/redis/client.py b/redis/client.py index a597d3a..e1f1103 100755 --- a/redis/client.py +++ b/redis/client.py @@ -26,6 +26,7 @@ from redis.exceptions import ( ) SYM_EMPTY = b('') +EMPTY_ERROR = 'EMPTY_ERROR' def list_or_args(keys, args): @@ -757,7 +758,12 @@ class StrictRedis(object): def parse_response(self, connection, command_name, **options): "Parses a response from the Redis server" - response = connection.read_response() + try: + response = connection.read_response() + except ResponseError: + if EMPTY_ERROR in options: + return options[EMPTY_ERROR] + raise if command_name in self.response_callbacks: return self.response_callbacks[command_name](response, **options) return response @@ -1120,7 +1126,10 @@ class StrictRedis(object): Returns a list of values ordered identically to ``keys`` """ args = list_or_args(keys, args) - return self.execute_command('MGET', *args) + options = {} + if not args: + options[EMPTY_ERROR] = [] + return self.execute_command('MGET', *args, **options) def mset(self, *args, **kwargs): """ @@ -3214,7 +3223,8 @@ class BasePipeline(object): def _execute_transaction(self, connection, commands, raise_on_error): cmds = chain([(('MULTI', ), {})], commands, [(('EXEC', ), {})]) - all_cmds = connection.pack_commands([args for args, _ in cmds]) + all_cmds = connection.pack_commands([args for args, options in cmds + if EMPTY_ERROR not in options]) connection.send_packed_command(all_cmds) errors = [] @@ -3229,12 +3239,15 @@ class BasePipeline(object): # and all the other commands for i, command in enumerate(commands): - try: - self.parse_response(connection, '_') - except ResponseError: - ex = sys.exc_info()[1] - self.annotate_exception(ex, i + 1, command[0]) - errors.append((i, ex)) + if EMPTY_ERROR in command[1]: + errors.append((i, command[1][EMPTY_ERROR])) + else: + try: + self.parse_response(connection, '_') + except ResponseError: + ex = sys.exc_info()[1] + self.annotate_exception(ex, i + 1, command[0]) + errors.append((i, ex)) # parse the EXEC. try: diff --git a/tests/test_commands.py b/tests/test_commands.py index 6394a7a..b6636b0 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -427,6 +427,7 @@ class TestRedisCommands(object): assert set(r.keys(pattern='test*')) == keys def test_mget(self, r): + assert r.mget([]) == [] assert r.mget(['a', 'b']) == [None, None] r['a'] = '1' r['b'] = '2' diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 46fc994..8de08d2 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -114,6 +114,20 @@ class TestPipeline(object): assert pipe.set('z', 'zzz').execute() == [True] assert r['z'] == b('zzz') + def test_command_with_on_error_option_returns_default_value(self, r): + """ + Commands with custom ON_ERROR functionality return their default + values in the pipeline no matter the raise_on_error preference + """ + for error_switch in (True, False): + with r.pipeline() as pipe: + pipe.set('a', 1).mget([]).set('c', 3) + result = pipe.execute(raise_on_error=error_switch) + + assert result[0] + assert result[1] == [] + assert result[2] + def test_parse_error_raised(self, r): with r.pipeline() as pipe: # the zrem is invalid because we don't pass any keys to it |