def multi(self): if self.explicit_transaction: raise RedisError('Cannot issue nested calls to MULTI') if self.command_stack: raise RedisError( 'Commands without an initial WATCH have already been issued') self.explicit_transaction = True
def __init__(self, ssl_keyfile=None, ssl_certfile=None, ssl_cert_reqs='required', ssl_ca_certs=None, **kwargs): if not ssl_available: raise RedisError("Python wasn't built with SSL support") super(SSLConnection, self).__init__(**kwargs) self.keyfile = ssl_keyfile self.certfile = ssl_certfile if ssl_cert_reqs is None: ssl_cert_reqs = ssl.CERT_NONE elif isinstance(ssl_cert_reqs, basestring): CERT_REQS = { 'none': ssl.CERT_NONE, 'optional': ssl.CERT_OPTIONAL, 'required': ssl.CERT_REQUIRED } if ssl_cert_reqs not in CERT_REQS: raise RedisError( "Invalid SSL Certificate Requirements Flag: %s" % ssl_cert_reqs) ssl_cert_reqs = CERT_REQS[ssl_cert_reqs] self.cert_reqs = ssl_cert_reqs self.ca_certs = ssl_ca_certs
def multi(self): """ Start a transactional block of the pipeline after WATCH commands are issued. End the transactional block with `execute`. """ if self.explicit_transaction: raise RedisError('Cannot issue nested calls to MULTI') if self.command_stack: raise RedisError( 'Commands without an initial WATCH have already been issued') self.explicit_transaction = True
def cluster_setslot(self, target_node, node_id, slot_id, state): """ Bind an hash slot to a specific node :target_node: 'ClusterNode' The node to execute the command on """ if state.upper() in ("IMPORTING", "NODE", "MIGRATING"): return self.execute_command( "CLUSTER SETSLOT", slot_id, state, node_id, target_nodes=target_node ) elif state.upper() == "STABLE": raise RedisError('For "stable" state please use ' "cluster_setslot_stable") else: raise RedisError(f"Invalid slot state: {state}")
def zrevrangebyscore(self, name, max, min, start=None, num=None, withscores=False): """ Return a range of values from the sorted set ``name`` with scores between ``min`` and ``max`` in descending order. If ``start`` and ``num`` are specified, then return a slice of the range. ``withscores`` indicates to return the scores along with the values. The return type is a list of (value, score) pairs """ if (start is not None and num is None) or \ (num is not None and start is None): raise RedisError("``start`` and ``num`` must both be specified") pieces = ['ZREVRANGEBYSCORE', name, max, min] if start is not None and num is not None: pieces.extend(['LIMIT', start, num]) if withscores: pieces.append('withscores') return self.execute_command(*pieces, **{'withscores': withscores})
async def get_keys(self, *args: Any) -> Optional[Tuple[str, ...]]: if len(args) < 2: # The command has no keys in it return None try: command = self.commands[args[0]] except KeyError: # try to split the command name and to take only the main command # e.g. 'memory' for 'memory usage' args = args[0].split() + list(args[1:]) cmd_name = args[0] if cmd_name not in self.commands: # We'll try to reinitialize the commands cache, if the engine # version has changed, the commands may not be current await self.initialize() if cmd_name not in self.commands: raise RedisError( f"{cmd_name.upper()} command doesn't exist in Redis commands" ) command = self.commands[cmd_name] if command == 1: return (args[1],) if command == 0: return None if command == -1: return await self._get_moveable_keys(*args) last_key_pos = command["last_key_pos"] if last_key_pos < 0: last_key_pos = len(args) + last_key_pos return args[command["first_key_pos"] : last_key_pos + 1 : command["step_count"]]
def zadd(self, name, *args, **kwargs): """ NOTE: The order of arguments differs from that of the official ZADD command. For backwards compatability, this method accepts arguments in the form of name1, score1, name2, score2, while the official Redis documents expects score1, name1, score2, name2. If you're looking to use the standard syntax, consider using the StrictRedis class. See the API Reference section of the docs for more information. Set any number of element-name, score pairs to the key ``name``. Pairs can be specified in two ways: As *args, in the form of: name1, score1, name2, score2, ... or as **kwargs, in the form of: name1=score1, name2=score2, ... The following example would add four values to the 'my-key' key: redis.zadd('my-key', 'name1', 1.1, 'name2', 2.2, name3=3.3, name4=4.4) """ pieces = [] if args: if len(args) % 2 != 0: raise RedisError( "ZADD requires an equal number of values and scores") pieces.extend(reversed(args)) for pair in iteritems(kwargs): pieces.append(pair[1]) pieces.append(pair[0]) return self.execute_command('ZADD', name, *pieces)
def coerce_zadd_args(*args, **kwargs): """ Take arguments attended by a zadd call, named or not, and return a flat list that can be used. A callback can be called with all "values" (as *args) if defined as the `values_callback` named argument. Real values will then be the result of this callback. """ values_callback = kwargs.pop('values_callback', None) pieces = [] if args: if len(args) % 2 != 0: raise RedisError("ZADD requires an equal number of " "values and scores") pieces.extend(args) for pair in iteritems(kwargs): pieces.append(pair[1]) pieces.append(pair[0]) values = pieces[1::2] if values_callback: values = values_callback(*values) scores = pieces[0::2] pieces = [] for z in zip(scores, values): pieces.extend(z) return pieces
def sort(self, name, start=None, num=None, by=None, get=None, desc=False, alpha=False, store=None): """ Sort and return the list, set or sorted set at ``name``. ``start`` and ``num`` allow for paging through the sorted data ``by`` allows using an external key to weight and sort the items. Use an "*" to indicate where in the key the item value is located ``get`` allows for returning items from external keys rather than the sorted data itself. Use an "*" to indicate where int he key the item value is located ``desc`` allows for reversing the sort ``alpha`` allows for sorting lexicographically rather than numerically ``store`` allows for storing the result of the sort into the key ``store`` """ if (start is not None and num is None) or \ (num is not None and start is None): raise RedisError("``start`` and ``num`` must both be specified") pieces = [name] if by is not None: pieces.append('BY') pieces.append(by) if start is not None and num is not None: pieces.append('LIMIT') pieces.append(start) pieces.append(num) if get is not None: # If get is a string assume we want to get a single value. # Otherwise assume it's an interable and we want to get multiple # values. We can't just iterate blindly because strings are # iterable. if isinstance(get, basestring): pieces.append('GET') pieces.append(get) else: for g in get: pieces.append('GET') pieces.append(g) if desc: pieces.append('DESC') if alpha: pieces.append('ALPHA') if store is not None: pieces.append('STORE') pieces.append(store) return self.execute_command('SORT', *pieces)
def load_redis_engine(): redis_url = urlparse.urlparse(settings.REDISTOGO_URL) if redis_url.scheme == "redis": engine = RedisEngine(host=redis_url.hostname, port=redis_url.port, password=redis_url.password) try: info = engine.client.info() if "db0" in info: nb_keys = info["db0"]["keys"] else: nb_keys = 0 print "Conn. Redis server, %s keys stored." % nb_keys return engine except ConnectionError: if settings.DEBUG: raise ConnectionError("Redis Server is not reachable.") else: return None else: if settings.DEBUG: raise RedisError("Redis Server '%s' URL is not valid." % settings.REDISTOGO_URL) else: return None
def zadd(self, *args, **kwargs): """ Parse args and kwargs to check values to pass them through the from_python method. We pass the parsed args/kwargs as args in the super call, to avoid doing the same calculation on kwargs one more time. """ pieces = [] if args: if len(args) % 2 != 0: raise RedisError("ZADD requires an equal number of " "values and scores") pieces.extend(args) for pair in kwargs.iteritems(): pieces.append(pair[1]) pieces.append(pair[0]) values = self.from_python(pieces[1::2]) scores = pieces[0::2] pieces = [] for z in zip(scores, values): pieces.extend(z) return super(M2MSortedSetField, self).zadd(*pieces)
def __init__(self, socket_read_size): if not HIREDIS_AVAILABLE: raise RedisError("Hiredis is not installed") self.socket_read_size = socket_read_size if HIREDIS_USE_BYTE_BUFFER: self._buffer = bytearray(socket_read_size)
def shutdown(self): "Shutdown the server" try: self.execute_command('SHUTDOWN') except ConnectionError: # a ConnectionError here is expected return raise RedisError("SHUTDOWN seems to have failed.")
def mset(self, *args, **kwargs): if args: if len(args) != 1 or not isinstance(args[0], dict): raise RedisError('MSET requires **kwargs or a single dict arg') kwargs.update(args[0]) mapping = {self.appendKeys(key): value for key, value in iteritems(kwargs)} return self.redis.mset(mapping)
def test_on_redis_errors_raises_RedisError(self, Queue): """On Redis connection errors, exceptions subclasses of `RedisError` will be raised.""" Queue.all.side_effect = RedisError('Connection error') with self.assertRaises(RedisError): get_jobs_by_queue() Queue.all.assert_called_once_with()
def test_on_redis_errors_raises_RedisError(self, Queue): """On Redis connection errors, exceptions subclasses of `RedisError` will be raised.""" type(Queue.return_value).count = PropertyMock( side_effect=RedisError('Connection error')) with self.assertRaises(RedisError): get_queue_jobs('queue_name') Queue.assert_called_once_with('queue_name')
def cluster_setslot( self, target_node: "TargetNodesT", node_id: str, slot_id: int, state: str ) -> ResponseT: """ Bind an hash slot to a specific node :target_node: 'ClusterNode' The node to execute the command on For more information see https://redis.io/commands/cluster-setslot """ if state.upper() in ("IMPORTING", "NODE", "MIGRATING"): return self.execute_command( "CLUSTER SETSLOT", slot_id, state, node_id, target_nodes=target_node ) elif state.upper() == "STABLE": raise RedisError('For "stable" state please use ' "cluster_setslot_stable") else: raise RedisError(f"Invalid slot state: {state}")
def DefaultSelector(sock): "Return the best selector for the platform" global _DEFAULT_SELECTOR if _DEFAULT_SELECTOR is None: if has_selector('poll'): _DEFAULT_SELECTOR = PollSelector elif hasattr(select, 'select'): _DEFAULT_SELECTOR = SelectSelector else: raise RedisError('Platform does not support any selectors') return _DEFAULT_SELECTOR(sock)
def cluster_setslot(self, node_id, slot_id, state, bind_to_node_id=None): """Bind an hash slot to a specific node""" if state.upper() in ('IMPORTING', 'MIGRATING', 'NODE') and node_id is not None: return self.execute_command('CLUSTER SETSLOT', slot_id, Token(state), node_id) elif state.upper() == 'STABLE': return self.execute_command('CLUSTER SETSLOT', slot_id, Token('STABLE')) else: raise RedisError('Invalid slot state: {0}'.format(state))
def acquire_lock(lock, degrade_gracefully, **kwargs): acquired = False try: acquired = lock.acquire(**kwargs) except RedisError: if degrade_gracefully: lock = None else: raise if lock and not acquired and not degrade_gracefully: raise RedisError("Unable to acquire lock") return lock
async def bitpos(cls, key, bit, start=None, end=None): """ Return the position of the first bit set to 1 or 0 in a string. ``start`` and ``end`` difines search range. The range is interpreted as a range of bytes and not a range of bits, so start=0 and end=2 means to look at the first three bytes. """ key = cls.__coll__ + key if bit not in (0, 1): raise RedisError('bit must be 0 or 1') params = [key, bit] start is not None and params.append(start) if start is not None and end is not None: params.append(end) elif start is None and end is not None: raise RedisError("start argument is not set, " "when end is specified") return await cls.Execute('BITPOS', *params)
def get_keys(self, redis_conn, *args): """ Get the keys from the passed command. NOTE: Due to a bug in redis<7.0, this function does not work properly for EVAL or EVALSHA when the `numkeys` arg is 0. - issue: https://github.com/redis/redis/issues/9493 - fix: https://github.com/redis/redis/pull/9733 So, don't use this function with EVAL or EVALSHA. """ if len(args) < 2: # The command has no keys in it return None cmd_name = args[0].lower() if cmd_name not in self.commands: # try to split the command name and to take only the main command, # e.g. 'memory' for 'memory usage' cmd_name_split = cmd_name.split() cmd_name = cmd_name_split[0] if cmd_name in self.commands: # save the splitted command to args args = cmd_name_split + list(args[1:]) else: # We'll try to reinitialize the commands cache, if the engine # version has changed, the commands may not be current self.initialize(redis_conn) if cmd_name not in self.commands: raise RedisError( f"{cmd_name.upper()} command doesn't exist in Redis commands" ) command = self.commands.get(cmd_name) if "movablekeys" in command["flags"]: keys = self._get_moveable_keys(redis_conn, *args) elif "pubsub" in command["flags"]: keys = self._get_pubsub_keys(*args) else: if (command["step_count"] == 0 and command["first_key_pos"] == 0 and command["last_key_pos"] == 0): # The command doesn't have keys in it return None last_key_pos = command["last_key_pos"] if last_key_pos < 0: last_key_pos = len(args) - abs(last_key_pos) keys_pos = list( range(command["first_key_pos"], last_key_pos + 1, command["step_count"])) keys = [args[pos] for pos in keys_pos] return keys
def bitcount(self, key, start=None, end=None): """ Returns the count of set bits in the value of ``key``. Optional ``start`` and ``end`` paramaters indicate which bytes to consider """ params = [key] if start is not None and end is not None: params.append(start) params.append(end) elif (start is not None and end is None) or \ (end is not None and start is None): raise RedisError("Both start and end must be specified") return self.Execute('BITCOUNT', *params)
def mset(self, *args, **kwargs): """ Sets key/values based on a mapping. Mapping can be supplied as a single dictionary argument or as kwargs. Cluster impl: Itterate over all items and do SET on each (k,v) pair """ if args: if len(args) != 1 or not isinstance(args[0], dict): raise RedisError('MSET requires **kwargs or a single dict arg') kwargs.update(args[0]) for pair in iteritems(kwargs): self.set(pair[0], pair[1]) return True
def validate(self, attr): uuid = attr.get("image_code_id") image_code_test = attr.get("text") cur = get_redis_connection("code") image_code = cur.get("image_code_%s" % uuid) try: cur.delete("image_code_%s" % uuid) except RedisError as e: logger.error(e) if not image_code: raise RedisError("验证码已过期!") if image_code.decode().lower() != image_code_test.lower(): return Response("验证码错误!", status=400) return attr
def cluster_failover(self, node_id, option=None): """ Forces a slave to perform a manual failover of its master Sends to specefied node """ if option: if option.upper() not in ['FORCE', 'TAKEOVER']: raise RedisError( 'Invalid option for CLUSTER FAILOVER command: {0}'.format( option)) else: return self.execute_command('CLUSTER FAILOVER', option, node_id=node_id) else: return self.execute_command('CLUSTER FAILOVER', node_id=node_id)
def sort(self, name, start=None, num=None, by=None, get=None, desc=False, alpha=False, store=None): """ Sort and return the list, set or sorted set at ``name``. ``start`` and ``num`` allow for paging through the sorted data ``by`` allows using an external key to weight and sort the items. Use an "*" to indicate where in the key the item value is located ``get`` allows for returning items from external keys rather than the sorted data itself. Use an "*" to indicate where int he key the item value is located ``desc`` allows for reversing the sort ``alpha`` allows for sorting lexicographically rather than numerically ``store`` allows for storing the result of the sort into the key ``store`` """ if (start is not None and num is None) or \ (num is not None and start is None): raise RedisError("``start`` and ``num`` must both be specified") pieces = [name] if by is not None: pieces.append('BY %s' % by) if start is not None and num is not None: pieces.append('LIMIT %s %s' % (start, num)) if get is not None: pieces.append('GET %s' % get) if desc: pieces.append('DESC') if alpha: pieces.append('ALPHA') if store is not None: pieces.append('STORE %s' % store) return self.format_inline('SORT', *pieces)
def get_keys(self, redis_conn, *args): """ Get the keys from the passed command """ if len(args) < 2: # The command has no keys in it return None cmd_name = args[0].lower() if cmd_name not in self.commands: # try to split the command name and to take only the main command, # e.g. 'memory' for 'memory usage' cmd_name_split = cmd_name.split() cmd_name = cmd_name_split[0] if cmd_name in self.commands: # save the splitted command to args args = cmd_name_split + list(args[1:]) else: # We'll try to reinitialize the commands cache, if the engine # version has changed, the commands may not be current self.initialize(redis_conn) if cmd_name not in self.commands: raise RedisError( f"{cmd_name.upper()} command doesn't exist in Redis commands" ) command = self.commands.get(cmd_name) if "movablekeys" in command["flags"]: keys = self._get_moveable_keys(redis_conn, *args) elif "pubsub" in command["flags"]: keys = self._get_pubsub_keys(*args) else: if (command["step_count"] == 0 and command["first_key_pos"] == 0 and command["last_key_pos"] == 0): # The command doesn't have keys in it return None last_key_pos = command["last_key_pos"] if last_key_pos < 0: last_key_pos = len(args) - abs(last_key_pos) keys_pos = list( range(command["first_key_pos"], last_key_pos + 1, command["step_count"])) keys = [args[pos] for pos in keys_pos] return keys
def execute_command(self, *args, **options): """ 重写该命令,主要是为了检测Redis命令的长度 最长不能超过128字节,防止代码Bug导致Key特别长 """ # 有些key直接传递的整形等,可以直接忽略 if len(args) > 2 and isinstance(args[1], str): # 第一个参数为Redis的命令,第二个参数为key名字 redis_command_key = args[1] try: command_key_length = len(redis_command_key) if command_key_length > 128: raise RedisError( "redis key is too long, please fix: %s-%s" % (redis_command_key, command_key_length)) except RedisError: pass return super(CustomRedis, self).execute_command(*args, **options)
def cluster_failover(self, target_node, option=None): """ Forces a slave to perform a manual failover of its master Sends to specified node :target_node: 'ClusterNode' The node to execute the command on """ if option: if option.upper() not in ["FORCE", "TAKEOVER"]: raise RedisError( f"Invalid option for CLUSTER FAILOVER command: {option}" ) else: return self.execute_command( "CLUSTER FAILOVER", option, target_nodes=target_node ) else: return self.execute_command("CLUSTER FAILOVER", target_nodes=target_node)