|
13 | 13 |
|
14 | 14 | from mockredis.clock import SystemClock
|
15 | 15 | from mockredis.lock import MockRedisLock
|
16 |
| -from mockredis.exceptions import RedisError, ResponseError |
| 16 | +from mockredis.exceptions import RedisError, ResponseError, WatchError |
17 | 17 | from mockredis.pipeline import MockRedisPipeline
|
18 | 18 | from mockredis.script import Script
|
19 | 19 | from mockredis.sortedset import SortedSet
|
@@ -77,6 +77,30 @@ def pipeline(self, transaction=True, shard_hint=None):
|
77 | 77 | """Emulate a redis-python pipeline."""
|
78 | 78 | return MockRedisPipeline(self, transaction, shard_hint)
|
79 | 79 |
|
| 80 | + def transaction(self, func, *watches, **kwargs): |
| 81 | + """ |
| 82 | + Convenience method for executing the callable `func` as a transaction |
| 83 | + while watching all keys specified in `watches`. The 'func' callable |
| 84 | + should expect a single argument which is a Pipeline object. |
| 85 | +
|
| 86 | + Copied directly from redis-py. |
| 87 | + """ |
| 88 | + shard_hint = kwargs.pop('shard_hint', None) |
| 89 | + value_from_callable = kwargs.pop('value_from_callable', False) |
| 90 | + watch_delay = kwargs.pop('watch_delay', None) |
| 91 | + with self.pipeline(True, shard_hint) as pipe: |
| 92 | + while 1: |
| 93 | + try: |
| 94 | + if watches: |
| 95 | + pipe.watch(*watches) |
| 96 | + func_value = func(pipe) |
| 97 | + exec_value = pipe.execute() |
| 98 | + return func_value if value_from_callable else exec_value |
| 99 | + except WatchError: |
| 100 | + if watch_delay is not None and watch_delay > 0: |
| 101 | + time.sleep(watch_delay) |
| 102 | + continue |
| 103 | + |
80 | 104 | def watch(self, *argv, **kwargs):
|
81 | 105 | """
|
82 | 106 | Mock does not support command buffering so watch
|
|
0 commit comments