This repository has been archived by the owner on Feb 21, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 335
/
Copy pathstring.py
248 lines (199 loc) · 8.97 KB
/
string.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
from itertools import chain
from aioredis.util import wait_convert, wait_ok, _NOTSET
class StringCommandsMixin:
"""String commands mixin.
For commands details see: http://redis.io/commands/#string
"""
SET_IF_NOT_EXIST = 'SET_IF_NOT_EXIST' # NX
SET_IF_EXIST = 'SET_IF_EXIST' # XX
def append(self, key, value):
"""Append a value to key."""
return self.execute(b'APPEND', key, value)
def bitcount(self, key, start=None, end=None):
"""Count set bits in a string.
:raises TypeError: if only start or end specified.
"""
if start is None and end is not None:
raise TypeError("both start and stop must be specified")
elif start is not None and end is None:
raise TypeError("both start and stop must be specified")
elif start is not None and end is not None:
args = (start, end)
else:
args = ()
return self.execute(b'BITCOUNT', key, *args)
def bitfield(self):
raise NotImplementedError()
def bitop_and(self, dest, key, *keys):
"""Perform bitwise AND operations between strings."""
return self.execute(b'BITOP', b'AND', dest, key, *keys)
def bitop_or(self, dest, key, *keys):
"""Perform bitwise OR operations between strings."""
return self.execute(b'BITOP', b'OR', dest, key, *keys)
def bitop_xor(self, dest, key, *keys):
"""Perform bitwise XOR operations between strings."""
return self.execute(b'BITOP', b'XOR', dest, key, *keys)
def bitop_not(self, dest, key):
"""Perform bitwise NOT operations between strings."""
return self.execute(b'BITOP', b'NOT', dest, key)
def bitpos(self, key, bit, start=None, end=None):
"""Find first bit set or clear in a string.
:raises ValueError: if bit is not 0 or 1
"""
if bit not in (1, 0):
raise ValueError("bit argument must be either 1 or 0")
bytes_range = []
if start is not None:
bytes_range.append(start)
if end is not None:
if start is None:
bytes_range = [0, end]
else:
bytes_range.append(end)
return self.execute(b'BITPOS', key, bit, *bytes_range)
def decr(self, key):
"""Decrement the integer value of a key by one."""
return self.execute(b'DECR', key)
def decrby(self, key, decrement):
"""Decrement the integer value of a key by the given number.
:raises TypeError: if decrement is not int
"""
if not isinstance(decrement, int):
raise TypeError("decrement must be of type int")
return self.execute(b'DECRBY', key, decrement)
def get(self, key, *, encoding=_NOTSET):
"""Get the value of a key."""
return self.execute(b'GET', key, encoding=encoding)
def getbit(self, key, offset):
"""Returns the bit value at offset in the string value stored at key.
:raises TypeError: if offset is not int
:raises ValueError: if offset is less than 0
"""
if not isinstance(offset, int):
raise TypeError("offset argument must be int")
if offset < 0:
raise ValueError("offset must be greater equal 0")
return self.execute(b'GETBIT', key, offset)
def getrange(self, key, start, end, *, encoding=_NOTSET):
"""Get a substring of the string stored at a key.
:raises TypeError: if start or end is not int
"""
if not isinstance(start, int):
raise TypeError("start argument must be int")
if not isinstance(end, int):
raise TypeError("end argument must be int")
return self.execute(b'GETRANGE', key, start, end, encoding=encoding)
def getset(self, key, value, *, encoding=_NOTSET):
"""Set the string value of a key and return its old value."""
return self.execute(b'GETSET', key, value, encoding=encoding)
def incr(self, key):
"""Increment the integer value of a key by one."""
return self.execute(b'INCR', key)
def incrby(self, key, increment):
"""Increment the integer value of a key by the given amount.
:raises TypeError: if increment is not int
"""
if not isinstance(increment, int):
raise TypeError("increment must be of type int")
return self.execute(b'INCRBY', key, increment)
def incrbyfloat(self, key, increment):
"""Increment the float value of a key by the given amount.
:raises TypeError: if increment is not int
"""
if not isinstance(increment, float):
raise TypeError("increment must be of type int")
fut = self.execute(b'INCRBYFLOAT', key, increment)
return wait_convert(fut, float)
def mget(self, key, *keys, encoding=_NOTSET):
"""Get the values of all the given keys."""
return self.execute(b'MGET', key, *keys, encoding=encoding)
def mset(self, *args):
"""Set multiple keys to multiple values or unpack dict to keys & values.
:raises TypeError: if len of args is not event number
:raises TypeError: if len of args equals 1 and it is not a dict
"""
data = args
if len(args) == 1:
if not isinstance(args[0], dict):
raise TypeError("if one arg it should be a dict")
data = chain.from_iterable(args[0].items())
elif len(args) % 2 != 0:
raise TypeError("length of pairs must be even number")
fut = self.execute(b'MSET', *data)
return wait_ok(fut)
def msetnx(self, key, value, *pairs):
"""Set multiple keys to multiple values,
only if none of the keys exist.
:raises TypeError: if len of pairs is not event number
"""
if len(pairs) % 2 != 0:
raise TypeError("length of pairs must be even number")
return self.execute(b'MSETNX', key, value, *pairs)
def psetex(self, key, milliseconds, value):
"""Set the value and expiration in milliseconds of a key.
:raises TypeError: if milliseconds is not int
"""
if not isinstance(milliseconds, int):
raise TypeError("milliseconds argument must be int")
fut = self.execute(b'PSETEX', key, milliseconds, value)
return wait_ok(fut)
def set(self, key, value, *, expire=0, pexpire=0, exist=None):
"""Set the string value of a key.
:raises TypeError: if expire or pexpire is not int
"""
if expire and not isinstance(expire, int):
raise TypeError("expire argument must be int")
if pexpire and not isinstance(pexpire, int):
raise TypeError("pexpire argument must be int")
args = []
if expire:
args[:] = [b'EX', expire]
if pexpire:
args[:] = [b'PX', pexpire]
if exist is self.SET_IF_EXIST:
args.append(b'XX')
elif exist is self.SET_IF_NOT_EXIST:
args.append(b'NX')
fut = self.execute(b'SET', key, value, *args)
return wait_ok(fut)
def setbit(self, key, offset, value):
"""Sets or clears the bit at offset in the string value stored at key.
:raises TypeError: if offset is not int
:raises ValueError: if offset is less than 0 or value is not 0 or 1
"""
if not isinstance(offset, int):
raise TypeError("offset argument must be int")
if offset < 0:
raise ValueError("offset must be greater equal 0")
if value not in (0, 1):
raise ValueError("value argument must be either 1 or 0")
return self.execute(b'SETBIT', key, offset, value)
def setex(self, key, seconds, value):
"""Set the value and expiration of a key.
If seconds is float it will be multiplied by 1000
coerced to int and passed to `psetex` method.
:raises TypeError: if seconds is neither int nor float
"""
if isinstance(seconds, float):
return self.psetex(key, int(seconds * 1000), value)
if not isinstance(seconds, int):
raise TypeError("milliseconds argument must be int")
fut = self.execute(b'SETEX', key, seconds, value)
return wait_ok(fut)
def setnx(self, key, value):
"""Set the value of a key, only if the key does not exist."""
fut = self.execute(b'SETNX', key, value)
return wait_convert(fut, bool)
def setrange(self, key, offset, value):
"""Overwrite part of a string at key starting at the specified offset.
:raises TypeError: if offset is not int
:raises ValueError: if offset less than 0
"""
if not isinstance(offset, int):
raise TypeError("offset argument must be int")
if offset < 0:
raise ValueError("offset must be greater equal 0")
return self.execute(b'SETRANGE', key, offset, value)
def strlen(self, key):
"""Get the length of the value stored in a key."""
return self.execute(b'STRLEN', key)