@@ -162,7 +162,8 @@ def __init__(self, servers, debug=0, pickleProtocol=0,
162
162
pload = None , pid = None ,
163
163
server_max_key_length = None , server_max_value_length = None ,
164
164
dead_retry = _DEAD_RETRY , socket_timeout = _SOCKET_TIMEOUT ,
165
- cache_cas = False , flush_on_reconnect = 0 , check_keys = True ):
165
+ cache_cas = False , flush_on_reconnect = 0 , check_keys = True ,
166
+ key_encoder = None ):
166
167
"""Create a new Client object with the given list of servers.
167
168
168
169
@param servers: C{servers} is passed to L{set_servers}.
@@ -205,6 +206,10 @@ def __init__(self, servers, debug=0, pickleProtocol=0,
205
206
@param check_keys: (default True) If True, the key is checked
206
207
to ensure it is the correct length and composed of the right
207
208
characters.
209
+ @param key_encoder: (default None) If provided a functor that will
210
+ be called to encode keys before they are checked and used. It will
211
+ be expected to take one parameter (the key) and return a new encoded
212
+ key as a result.
208
213
"""
209
214
super (Client , self ).__init__ ()
210
215
self .debug = debug
@@ -226,6 +231,10 @@ def __init__(self, servers, debug=0, pickleProtocol=0,
226
231
self .persistent_load = pload
227
232
self .persistent_id = pid
228
233
self .server_max_key_length = server_max_key_length
234
+ if key_encoder is None :
235
+ def key_encoder (key ):
236
+ return key
237
+ self .key_encoder = key_encoder
229
238
if self .server_max_key_length is None :
230
239
self .server_max_key_length = SERVER_MAX_KEY_LENGTH
231
240
self .server_max_value_length = server_max_value_length
@@ -494,7 +503,7 @@ def delete_multi(self, keys, time=None, key_prefix='', noreply=False):
494
503
else :
495
504
headers = None
496
505
for key in server_keys [server ]: # These are mangled keys
497
- cmd = self ._encode_cmd ('delete' , key , headers , noreply , b'\r \n ' )
506
+ cmd = self ._encode_cmd ('delete' , self . key_encoder ( key ) , headers , noreply , b'\r \n ' )
498
507
write (cmd )
499
508
try :
500
509
server .send_cmds (b'' .join (bigcmd ))
@@ -532,7 +541,7 @@ def delete(self, key, noreply=False):
532
541
reply.
533
542
@rtype: int
534
543
'''
535
- key = self ._encode_key (key )
544
+ key = self ._encode_key (self . key_encoder ( key ) )
536
545
if self .do_check_key :
537
546
self .check_key (key )
538
547
server , key = self ._get_server (key )
@@ -568,7 +577,7 @@ def touch(self, key, time=0, noreply=False):
568
577
reply.
569
578
@rtype: int
570
579
'''
571
- key = self ._encode_key (key )
580
+ key = self ._encode_key (self . key_encoder ( key ) )
572
581
if self .do_check_key :
573
582
self .check_key (key )
574
583
server , key = self ._get_server (key )
@@ -622,7 +631,7 @@ def incr(self, key, delta=1, noreply=False):
622
631
@return: New value after incrementing, no None for noreply or error.
623
632
@rtype: int
624
633
"""
625
- return self ._incrdecr ("incr" , key , delta , noreply )
634
+ return self ._incrdecr ("incr" , self . key_encoder ( key ) , delta , noreply )
626
635
627
636
def decr (self , key , delta = 1 , noreply = False ):
628
637
"""Decrement value for C{key} by C{delta}
@@ -640,7 +649,7 @@ def decr(self, key, delta=1, noreply=False):
640
649
@return: New value after decrementing, or None for noreply or error.
641
650
@rtype: int
642
651
"""
643
- return self ._incrdecr ("decr" , key , delta , noreply )
652
+ return self ._incrdecr ("decr" , self . key_encoder ( key ) , delta , noreply )
644
653
645
654
def _incrdecr (self , cmd , key , delta , noreply = False ):
646
655
key = self ._encode_key (key )
@@ -674,7 +683,7 @@ def add(self, key, val, time=0, min_compress_len=0, noreply=False):
674
683
@return: Nonzero on success.
675
684
@rtype: int
676
685
'''
677
- return self ._set ("add" , key , val , time , min_compress_len , noreply )
686
+ return self ._set ("add" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
678
687
679
688
def append (self , key , val , time = 0 , min_compress_len = 0 , noreply = False ):
680
689
'''Append the value to the end of the existing key's value.
@@ -685,7 +694,7 @@ def append(self, key, val, time=0, min_compress_len=0, noreply=False):
685
694
@return: Nonzero on success.
686
695
@rtype: int
687
696
'''
688
- return self ._set ("append" , key , val , time , min_compress_len , noreply )
697
+ return self ._set ("append" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
689
698
690
699
def prepend (self , key , val , time = 0 , min_compress_len = 0 , noreply = False ):
691
700
'''Prepend the value to the beginning of the existing key's value.
@@ -696,7 +705,7 @@ def prepend(self, key, val, time=0, min_compress_len=0, noreply=False):
696
705
@return: Nonzero on success.
697
706
@rtype: int
698
707
'''
699
- return self ._set ("prepend" , key , val , time , min_compress_len , noreply )
708
+ return self ._set ("prepend" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
700
709
701
710
def replace (self , key , val , time = 0 , min_compress_len = 0 , noreply = False ):
702
711
'''Replace existing key with value.
@@ -707,7 +716,7 @@ def replace(self, key, val, time=0, min_compress_len=0, noreply=False):
707
716
@return: Nonzero on success.
708
717
@rtype: int
709
718
'''
710
- return self ._set ("replace" , key , val , time , min_compress_len , noreply )
719
+ return self ._set ("replace" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
711
720
712
721
def set (self , key , val , time = 0 , min_compress_len = 0 , noreply = False ):
713
722
'''Unconditionally sets a key to a given value in the memcache.
@@ -743,7 +752,7 @@ def set(self, key, val, time=0, min_compress_len=0, noreply=False):
743
752
'''
744
753
if isinstance (time , timedelta ):
745
754
time = int (time .total_seconds ())
746
- return self ._set ("set" , key , val , time , min_compress_len , noreply )
755
+ return self ._set ("set" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
747
756
748
757
def cas (self , key , val , time = 0 , min_compress_len = 0 , noreply = False ):
749
758
'''Check and set (CAS)
@@ -780,7 +789,7 @@ def cas(self, key, val, time=0, min_compress_len=0, noreply=False):
780
789
@param noreply: optional parameter instructs the server to not
781
790
send the reply.
782
791
'''
783
- return self ._set ("cas" , key , val , time , min_compress_len , noreply )
792
+ return self ._set ("cas" , self . key_encoder ( key ) , val , time , min_compress_len , noreply )
784
793
785
794
def _map_and_prefix_keys (self , key_iterable , key_prefix ):
786
795
"""Map keys to the servers they will reside on.
@@ -807,7 +816,7 @@ def _map_and_prefix_keys(self, key_iterable, key_prefix):
807
816
# Ensure call to _get_server gets a Tuple as well.
808
817
serverhash , key = orig_key
809
818
810
- key = self ._encode_key (key )
819
+ key = self ._encode_key (self . key_encoder ( key ) )
811
820
if not isinstance (key , six .binary_type ):
812
821
# set_multi supports int / long keys.
813
822
key = str (key ).encode ('utf8' )
@@ -818,7 +827,7 @@ def _map_and_prefix_keys(self, key_iterable, key_prefix):
818
827
server , key = self ._get_server (
819
828
(serverhash , key_prefix + key ))
820
829
else :
821
- key = self ._encode_key (orig_key )
830
+ key = self ._encode_key (self . key_encoder ( orig_key ) )
822
831
if not isinstance (key , six .binary_type ):
823
832
# set_multi supports int / long keys.
824
833
key = str (key ).encode ('utf8' )
@@ -923,7 +932,7 @@ def set_multi(self, mapping, time=0, key_prefix='', min_compress_len=0,
923
932
if store_info :
924
933
flags , len_val , val = store_info
925
934
headers = "%d %d %d" % (flags , time , len_val )
926
- fullcmd = self ._encode_cmd ('set' , key , headers ,
935
+ fullcmd = self ._encode_cmd ('set' , self . key_encoder ( key ) , headers ,
927
936
noreply ,
928
937
b'\r \n ' , val , b'\r \n ' )
929
938
write (fullcmd )
@@ -1121,14 +1130,14 @@ def get(self, key, default=None):
1121
1130
1122
1131
@return: The value or None.
1123
1132
'''
1124
- return self ._get ('get' , key , default )
1133
+ return self ._get ('get' , self . key_encoder ( key ) , default )
1125
1134
1126
1135
def gets (self , key ):
1127
1136
'''Retrieves a key from the memcache. Used in conjunction with 'cas'.
1128
1137
1129
1138
@return: The value or None.
1130
1139
'''
1131
- return self ._get ('gets' , key )
1140
+ return self ._get ('gets' , self . key_encoder ( key ) )
1132
1141
1133
1142
def get_multi (self , keys , key_prefix = '' ):
1134
1143
'''Retrieves multiple keys from the memcache doing just one query.
@@ -1188,7 +1197,7 @@ def get_multi(self, keys, key_prefix=''):
1188
1197
self ._statlog ('get_multi' )
1189
1198
1190
1199
server_keys , prefixed_to_orig_key = self ._map_and_prefix_keys (
1191
- keys , key_prefix )
1200
+ [ self . key_encoder ( k ) for k in keys ] , key_prefix )
1192
1201
1193
1202
# send out all requests on each server before reading anything
1194
1203
dead_servers = []
0 commit comments