@@ -57,15 +57,15 @@ def __init__(self,
57
57
# Dictionary from script to sha ''Script''
58
58
self .shas = dict ()
59
59
60
- #### Connection Functions ### #
60
+ # Connection Functions #
61
61
62
62
def echo (self , msg ):
63
63
return self ._encode (msg )
64
64
65
65
def ping (self ):
66
66
return b'PONG'
67
67
68
- #### Transactions Functions ### #
68
+ # Transactions Functions #
69
69
70
70
def lock (self , key , timeout = 0 , sleep = 0 ):
71
71
"""Emulate lock."""
@@ -101,7 +101,7 @@ def execute(self):
101
101
in this mock, so this is a no-op."""
102
102
pass
103
103
104
- #### Keys Functions ### #
104
+ # Keys Functions #
105
105
106
106
def type (self , key ):
107
107
key = self ._encode (key )
@@ -247,7 +247,7 @@ def _rename(self, old_key, new_key, nx=False):
247
247
return True
248
248
return False
249
249
250
- #### String Functions ### #
250
+ # String Functions #
251
251
252
252
def get (self , key ):
253
253
key = self ._encode (key )
@@ -413,7 +413,46 @@ def incr(self, key, amount=1):
413
413
414
414
incrby = incr
415
415
416
- #### Hash Functions ####
416
+ def setbit (self , key , offset , value ):
417
+ """
418
+ Set the bit at ``offset`` in ``key`` to ``value``.
419
+ """
420
+ key = self ._encode (key )
421
+ index , bits , mask = self ._get_bits_and_offset (key , offset )
422
+
423
+ if index >= len (bits ):
424
+ bits .extend (b"\x00 " * (index + 1 - len (bits )))
425
+
426
+ prev_val = 1 if (bits [index ] & mask ) else 0
427
+
428
+ if value :
429
+ bits [index ] |= mask
430
+ else :
431
+ bits [index ] &= ~ mask
432
+
433
+ self .redis [key ] = bytes (bits )
434
+
435
+ return prev_val
436
+
437
+ def getbit (self , key , offset ):
438
+ """
439
+ Returns the bit value at ``offset`` in ``key``.
440
+ """
441
+ key = self ._encode (key )
442
+ index , bits , mask = self ._get_bits_and_offset (key , offset )
443
+
444
+ if index >= len (bits ):
445
+ return 0
446
+
447
+ return 1 if (bits [index ] & mask ) else 0
448
+
449
+ def _get_bits_and_offset (self , key , offset ):
450
+ bits = bytearray (self .redis .get (key , b"" ))
451
+ index , position = divmod (offset , 8 )
452
+ mask = 128 >> position
453
+ return index , bits , mask
454
+
455
+ # Hash Functions #
417
456
418
457
def hexists (self , hashkey , attribute ):
419
458
"""Emulate hexists."""
@@ -518,7 +557,7 @@ def hvals(self, hashkey):
518
557
redis_hash = self ._get_hash (hashkey , 'HVALS' )
519
558
return redis_hash .values ()
520
559
521
- #### List Functions ### #
560
+ # List Functions #
522
561
523
562
def lrange (self , key , start , stop ):
524
563
"""Emulate lrange."""
@@ -726,7 +765,7 @@ def sort(self, name,
726
765
return []
727
766
728
767
by = self ._encode (by ) if by is not None else by
729
- # always organize the items as tuples of the value from the list itself and the value to sort by
768
+ # always organize the items as tuples of the value from the list and the sort key
730
769
if by and b'*' in by :
731
770
items = [(i , self .get (by .replace (b'*' , self ._encode (i )))) for i in items ]
732
771
elif by in [None , b'nosort' ]:
@@ -782,7 +821,7 @@ def sort(self, name,
782
821
else :
783
822
return results
784
823
785
- #### SCAN COMMANDS ### #
824
+ # SCAN COMMANDS #
786
825
787
826
def _common_scan (self , values_function , cursor = '0' , match = None , count = 10 , key = None ):
788
827
"""
@@ -820,6 +859,14 @@ def value_function():
820
859
return sorted (self .redis .keys ()) # sorted list for consistent order
821
860
return self ._common_scan (value_function , cursor = cursor , match = match , count = count )
822
861
862
+ def scan_iter (self , match = None , count = 10 ):
863
+ """Emulate scan_iter."""
864
+ cursor = '0'
865
+ while cursor != 0 :
866
+ cursor , data = self .scan (cursor = cursor , match = match , count = count )
867
+ for item in data :
868
+ yield item
869
+
823
870
def sscan (self , name , cursor = '0' , match = None , count = 10 ):
824
871
"""Emulate sscan."""
825
872
def value_function ():
@@ -828,13 +875,31 @@ def value_function():
828
875
return members
829
876
return self ._common_scan (value_function , cursor = cursor , match = match , count = count )
830
877
878
+ def sscan_iter (self , name , match = None , count = 10 ):
879
+ """Emulate sscan_iter."""
880
+ cursor = '0'
881
+ while cursor != 0 :
882
+ cursor , data = self .sscan (name , cursor = cursor ,
883
+ match = match , count = count )
884
+ for item in data :
885
+ yield item
886
+
831
887
def zscan (self , name , cursor = '0' , match = None , count = 10 ):
832
888
"""Emulate zscan."""
833
889
def value_function ():
834
890
values = self .zrange (name , 0 , - 1 , withscores = True )
835
891
values .sort (key = lambda x : x [1 ]) # sort for consistent order
836
892
return values
837
- return self ._common_scan (value_function , cursor = cursor , match = match , count = count , key = lambda v : v [0 ])
893
+ return self ._common_scan (value_function , cursor = cursor , match = match , count = count , key = lambda v : v [0 ]) # noqa
894
+
895
+ def zscan_iter (self , name , match = None , count = 10 ):
896
+ """Emulate zscan_iter."""
897
+ cursor = '0'
898
+ while cursor != 0 :
899
+ cursor , data = self .zscan (name , cursor = cursor , match = match ,
900
+ count = count )
901
+ for item in data :
902
+ yield item
838
903
839
904
def hscan (self , name , cursor = '0' , match = None , count = 10 ):
840
905
"""Emulate hscan."""
@@ -843,11 +908,20 @@ def value_function():
843
908
values = list (values .items ()) # list of tuples for sorting and matching
844
909
values .sort (key = lambda x : x [0 ]) # sort for consistent order
845
910
return values
846
- scanned = self ._common_scan (value_function , cursor = cursor , match = match , count = count , key = lambda v : v [0 ])
911
+ scanned = self ._common_scan (value_function , cursor = cursor , match = match , count = count , key = lambda v : v [0 ]) # noqa
847
912
scanned [1 ] = dict (scanned [1 ]) # from list of tuples back to dict
848
913
return scanned
849
914
850
- #### SET COMMANDS ####
915
+ def hscan_iter (self , name , match = None , count = 10 ):
916
+ """Emulate hscan_iter."""
917
+ cursor = '0'
918
+ while cursor != 0 :
919
+ cursor , data = self .hscan (name , cursor = cursor ,
920
+ match = match , count = count )
921
+ for item in data .items ():
922
+ yield item
923
+
924
+ # SET COMMANDS #
851
925
852
926
def sadd (self , key , * values ):
853
927
"""Emulate sadd."""
@@ -960,7 +1034,7 @@ def sunionstore(self, dest, keys, *args):
960
1034
self .redis [self ._encode (dest )] = result
961
1035
return len (result )
962
1036
963
- #### SORTED SET COMMANDS ### #
1037
+ # SORTED SET COMMANDS #
964
1038
965
1039
def zadd (self , name , * args , ** kwargs ):
966
1040
zset = self ._get_zset (name , "ZADD" , create = True )
@@ -981,21 +1055,21 @@ def zadd(self, name, *args, **kwargs):
981
1055
# kwargs
982
1056
pieces .extend (kwargs .items ())
983
1057
984
- insert_count = lambda member , score : 1 if zset .insert (self ._encode (member ), float (score )) else 0
1058
+ insert_count = lambda member , score : 1 if zset .insert (self ._encode (member ), float (score )) else 0 # noqa
985
1059
return sum ((insert_count (member , score ) for member , score in pieces ))
986
1060
987
1061
def zcard (self , name ):
988
1062
zset = self ._get_zset (name , "ZCARD" )
989
1063
990
1064
return len (zset ) if zset is not None else 0
991
1065
992
- def zcount (self , name , min_ , max_ ):
1066
+ def zcount (self , name , min , max ):
993
1067
zset = self ._get_zset (name , "ZCOUNT" )
994
1068
995
1069
if not zset :
996
1070
return 0
997
1071
998
- return len (zset .scorerange (float (min_ ), float (max_ )))
1072
+ return len (zset .scorerange (float (min ), float (max )))
999
1073
1000
1074
def zincrby (self , name , value , amount = 1 ):
1001
1075
zset = self ._get_zset (name , "ZINCRBY" , create = True )
@@ -1041,7 +1115,7 @@ def zrange(self, name, start, end, desc=False, withscores=False,
1041
1115
func = self ._range_func (withscores , score_cast_func )
1042
1116
return [func (item ) for item in zset .range (start , end , desc )]
1043
1117
1044
- def zrangebyscore (self , name , min_ , max_ , start = None , num = None ,
1118
+ def zrangebyscore (self , name , min , max , start = None , num = None ,
1045
1119
withscores = False , score_cast_func = float ):
1046
1120
if (start is None ) ^ (num is None ):
1047
1121
raise RedisError ('`start` and `num` must both be specified' )
@@ -1052,9 +1126,9 @@ def zrangebyscore(self, name, min_, max_, start=None, num=None,
1052
1126
return []
1053
1127
1054
1128
func = self ._range_func (withscores , score_cast_func )
1055
- include_start , min_ = self ._score_inclusive (min_ )
1056
- include_end , max_ = self ._score_inclusive (max_ )
1057
- scorerange = zset .scorerange (min_ , max_ , start_inclusive = include_start , end_inclusive = include_end )
1129
+ include_start , min = self ._score_inclusive (min )
1130
+ include_end , max = self ._score_inclusive (max )
1131
+ scorerange = zset .scorerange (min , max , start_inclusive = include_start , end_inclusive = include_end ) # noqa
1058
1132
if start is not None and num is not None :
1059
1133
start , num = self ._translate_limit (len (scorerange ), int (start ), int (num ))
1060
1134
scorerange = scorerange [start :start + num ]
@@ -1085,23 +1159,23 @@ def zremrangebyrank(self, name, start, end):
1085
1159
1086
1160
start , end = self ._translate_range (len (zset ), start , end )
1087
1161
count_removals = lambda score , member : 1 if zset .remove (member ) else 0
1088
- removal_count = sum ((count_removals (score , member ) for score , member in zset .range (start , end )))
1162
+ removal_count = sum ((count_removals (score , member ) for score , member in zset .range (start , end ))) # noqa
1089
1163
if removal_count > 0 and len (zset ) == 0 :
1090
1164
self .delete (name )
1091
1165
return removal_count
1092
1166
1093
- def zremrangebyscore (self , name , min_ , max_ ):
1167
+ def zremrangebyscore (self , name , min , max ):
1094
1168
zset = self ._get_zset (name , "ZREMRANGEBYSCORE" )
1095
1169
1096
1170
if not zset :
1097
1171
return 0
1098
1172
1099
1173
count_removals = lambda score , member : 1 if zset .remove (member ) else 0
1100
- include_start , min_ = self ._score_inclusive (min_ )
1101
- include_end , max_ = self ._score_inclusive (max_ )
1174
+ include_start , min = self ._score_inclusive (min )
1175
+ include_end , max = self ._score_inclusive (max )
1102
1176
1103
1177
removal_count = sum ((count_removals (score , member )
1104
- for score , member in zset .scorerange (min_ , max_ ,
1178
+ for score , member in zset .scorerange (min , max ,
1105
1179
start_inclusive = include_start ,
1106
1180
end_inclusive = include_end )))
1107
1181
if removal_count > 0 and len (zset ) == 0 :
@@ -1113,7 +1187,7 @@ def zrevrange(self, name, start, end, withscores=False,
1113
1187
return self .zrange (name , start , end ,
1114
1188
desc = True , withscores = withscores , score_cast_func = score_cast_func )
1115
1189
1116
- def zrevrangebyscore (self , name , max_ , min_ , start = None , num = None ,
1190
+ def zrevrangebyscore (self , name , max , min , start = None , num = None ,
1117
1191
withscores = False , score_cast_func = float ):
1118
1192
1119
1193
if (start is None ) ^ (num is None ):
@@ -1124,11 +1198,12 @@ def zrevrangebyscore(self, name, max_, min_, start=None, num=None,
1124
1198
return []
1125
1199
1126
1200
func = self ._range_func (withscores , score_cast_func )
1127
- include_start , min_ = self ._score_inclusive (min_ )
1128
- include_end , max_ = self ._score_inclusive (max_ )
1201
+ include_start , min = self ._score_inclusive (min )
1202
+ include_end , max = self ._score_inclusive (max )
1129
1203
1130
- scorerange = [x for x in reversed (zset .scorerange (float (min_ ), float (max_ ),
1131
- start_inclusive = include_start , end_inclusive = include_end ))]
1204
+ scorerange = [x for x in reversed (zset .scorerange (float (min ), float (max ),
1205
+ start_inclusive = include_start ,
1206
+ end_inclusive = include_end ))]
1132
1207
if start is not None and num is not None :
1133
1208
start , num = self ._translate_limit (len (scorerange ), int (start ), int (num ))
1134
1209
scorerange = scorerange [start :start + num ]
@@ -1170,7 +1245,7 @@ def zunionstore(self, dest, keys, aggregate=None):
1170
1245
self .redis [self ._encode (dest )] = union
1171
1246
return len (union )
1172
1247
1173
- #### Script Commands ### #
1248
+ # Script Commands #
1174
1249
1175
1250
def eval (self , script , numkeys , * keys_and_args ):
1176
1251
"""Emulate eval"""
@@ -1279,12 +1354,12 @@ def _normalize_command_response(self, command, response):
1279
1354
1280
1355
return response
1281
1356
1282
- #### PubSub commands ### #
1357
+ # PubSub commands #
1283
1358
1284
1359
def publish (self , channel , message ):
1285
1360
self .pubsub [channel ].append (message )
1286
1361
1287
- #### Internal ### #
1362
+ # Internal #
1288
1363
1289
1364
def _get_list (self , key , operation , create = False ):
1290
1365
"""
@@ -1308,7 +1383,7 @@ def _get_zset(self, name, operation, create=False):
1308
1383
"""
1309
1384
Get (and maybe create) a sorted set by name.
1310
1385
"""
1311
- return self ._get_by_type (name , operation , create , b'zset' , SortedSet (), return_default = False )
1386
+ return self ._get_by_type (name , operation , create , b'zset' , SortedSet (), return_default = False ) # noqa
1312
1387
1313
1388
def _get_by_type (self , key , operation , create , type_ , default , return_default = True ):
1314
1389
"""
@@ -1348,7 +1423,7 @@ def _range_func(self, withscores, score_cast_func):
1348
1423
Return a suitable function from (score, member)
1349
1424
"""
1350
1425
if withscores :
1351
- return lambda score_member : (score_member [1 ], score_cast_func (self ._encode (score_member [0 ])))
1426
+ return lambda score_member : (score_member [1 ], score_cast_func (self ._encode (score_member [0 ]))) # noqa
1352
1427
else :
1353
1428
return lambda score_member : score_member [1 ]
1354
1429
0 commit comments