def geopos(self, key, member, *members, **kwargs): """Returns longitude and latitude of members of a geospatial index. :rtype: list[GeoPoint or None] """ fut = self.execute(b'GEOPOS', key, member, *members, **kwargs) return wait_convert(fut, make_geopos)
def geodist(self, key, member1, member2, unit='m'): """Returns the distance between two members of a geospatial index. :rtype: list[float or None] """ fut = self.execute(b'GEODIST', key, member1, member2, unit) return wait_convert(fut, make_geodist)
def client_list(self): """Get the list of client connections. Returns list of ClientInfo named tuples. """ fut = self.execute(b'CLIENT', b'LIST', encoding='utf-8') return wait_convert(fut, to_tuples)
def zrevrangebyscore(self, key, max=float('inf'), min=float('-inf'), *, exclude=None, withscores=False, offset=None, count=None): """Return a range of members in a sorted set, by score, with scores ordered from high to low. :raises TypeError: if min or max is not float or int :raises TypeError: if both offset and count are not specified :raises TypeError: if offset is not int :raises TypeError: if count is not int """ if not isinstance(min, (int, float)): raise TypeError("min argument must be int or float") if not isinstance(max, (int, float)): raise TypeError("max argument must be int or float") if (offset is not None and count is None) or \ (count is not None and offset is None): raise TypeError("offset and count must both be specified") if offset is not None and not isinstance(offset, int): raise TypeError("offset argument must be int") if count is not None and not isinstance(count, int): raise TypeError("count argument must be int") min, max = _encode_min_max(exclude, min, max) args = [] if withscores: args = [b'WITHSCORES'] if offset is not None and count is not None: args.extend([b'LIMIT', offset, count]) fut = self._conn.execute(b'ZREVRANGEBYSCORE', key, max, min, *args) if withscores: return wait_convert(fut, pairs_int_or_float) return fut
def sscan(self, key, cursor=0, match=None, count=None): """Incrementally iterate Set elements.""" tokens = [key, cursor] match is not None and tokens.extend([b"MATCH", match]) count is not None and tokens.extend([b"COUNT", count]) fut = self._conn.execute(b"SSCAN", *tokens) return wait_convert(fut, lambda obj: (int(obj[0]), obj[1]))
def hscan(self, key, cursor=0, match=None, count=None): """Incrementally iterate hash fields and associated values.""" args = [key, cursor] match is not None and args.extend([b'MATCH', match]) count is not None and args.extend([b'COUNT', count]) fut = self._conn.execute(b'HSCAN', *args) return wait_convert(fut, lambda obj: (int(obj[0]), obj[1]))
def xrevrange(self, stream, start='+', stop='-', count=None): """Retrieve messages from a stream in reverse order.""" if count is not None: extra = ['COUNT', count] else: extra = [] fut = self.execute(b'XREVRANGE', stream, start, stop, *extra) return wait_convert(fut, parse_messages)
def xclaim(self, stream, group_name, consumer_name, min_idle_time, id, *ids): """Claim a message for a given consumer""" fut = self.execute( b'XCLAIM', stream, group_name, consumer_name, min_idle_time, id, *ids ) return wait_convert(fut, parse_messages)
def role(self): """Return the role of the server instance. Returns named tuples describing role of the instance. For fields information see http://redis.io/commands/role#output-format """ fut = self.execute(b'ROLE', encoding='utf-8') return wait_convert(fut, parse_role)
def zincrby(self, key, increment, member): """Increment the score of a member in a sorted set. :raises TypeError: increment is not float or int """ if not isinstance(increment, (int, float)): raise TypeError("increment argument must be int or float") fut = self._conn.execute(b'ZINCRBY', key, increment, member) return wait_convert(fut, int_or_float)
def xread(self, streams, timeout=0, count=None, latest_ids=None): """Perform a blocking read on the given stream :raises ValueError: if the length of streams and latest_ids do not match """ args = self._xread(streams, timeout, count, latest_ids) fut = self.execute(b'XREAD', *args) return wait_convert(fut, parse_messages_by_stream)
def renamenx(self, key, newkey): """Renames key to newkey only if newkey does not exist. :raises ValueError: if key == newkey """ if key == newkey: raise ValueError("key and newkey are the same") fut = self.execute(b'RENAMENX', key, newkey) return wait_convert(fut, bool)
def scan(self, cursor=0, match=None, count=None): """Incrementally iterate the keys space.""" args = [] if match is not None: args += [b'MATCH', match] if count is not None: args += [b'COUNT', count] fut = self._conn.execute(b'SCAN', cursor, *args) return wait_convert(fut, lambda o: (int(o[0]), o[1]))
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._conn.execute(b'INCRBYFLOAT', key, increment) return wait_convert(fut, float)
def pexpire(self, key, timeout): """Set a milliseconds timeout on key. :raises TypeError: if timeout is not int """ if not isinstance(timeout, int): raise TypeError("timeout argument must be int, not {!r}" .format(timeout)) fut = self.execute(b'PEXPIRE', key, timeout) return wait_convert(fut, bool)
def pexpireat(self, key, timestamp): """Set expire timestamp on key, timestamp in milliseconds. :raises TypeError: if timeout is not int """ if not isinstance(timestamp, int): raise TypeError("timestamp argument must be int, not {!r}" .format(timestamp)) fut = self.execute(b'PEXPIREAT', key, timestamp) return wait_convert(fut, bool)
def xread_group(self, group_name, consumer_name, streams, timeout=0, count=None, latest_ids=None): """Perform a blocking read on the given stream as part of a consumer group :raises ValueError: if the length of streams and latest_ids do not match """ args = self._xread(streams, timeout, count, latest_ids) fut = self.execute( b'XREADGROUP', b'GROUP', group_name, consumer_name, *args ) return wait_convert(fut, parse_messages_by_stream)
def zscan(self, key, cursor=0, match=None, count=None): """Incrementally iterate sorted sets elements and associated scores.""" args = [] if match is not None: args += [b'MATCH', match] if count is not None: args += [b'COUNT', count] fut = self._conn.execute(b'ZSCAN', key, cursor, *args) def _converter(obj): return (int(obj[0]), pairs_int_or_float(obj[1])) return wait_convert(fut, _converter)
def info(self, section='default'): """Get information and statistics about the server. If called without argument will return default set of sections. For available sections, see http://redis.io/commands/INFO :raises ValueError: if section is invalid """ if not section: raise ValueError("invalid section") fut = self.execute(b'INFO', section, encoding='utf-8') return wait_convert(fut, parse_info)
def move(self, key, db): """Move key from currently selected database to specified destination. :raises TypeError: if db is not int :raises ValueError: if db is less than 0 """ if not isinstance(db, int): raise TypeError("db argument must be int, not {!r}".format(db)) if db < 0: raise ValueError("db argument must be not less than 0, {!r}" .format(db)) fut = self.execute(b'MOVE', key, db) return wait_convert(fut, bool)
def expire(self, key, timeout): """Set a timeout on key. if timeout is float it will be multiplyed by 1000 coerced to int and passed to `pexpire` method. Otherwise raises TypeError if timeout argument is not int. """ if isinstance(timeout, float): return self.pexpire(key, int(timeout * 1000)) if not isinstance(timeout, int): raise TypeError("timeout argument must be int, not {!r}" .format(timeout)) fut = self._conn.execute(b'EXPIRE', key, timeout) return wait_convert(fut, bool)
def expireat(self, key, timestamp): """Set expire timestamp on a key. if timeout is float it will be multiplied by 1000 coerced to int and passed to `pexpireat` method. Otherwise raises TypeError if timestamp argument is not int. """ if isinstance(timestamp, float): return self.pexpireat(key, int(timestamp * 1000)) if not isinstance(timestamp, int): raise TypeError("timestamp argument must be int, not {!r}" .format(timestamp)) fut = self.execute(b'EXPIREAT', key, timestamp) return wait_convert(fut, bool)
def zrevrange(self, key, start, stop, withscores=False): """Return a range of members in a sorted set, by index, with scores ordered from high to low. :raises TypeError: if start or stop is not int """ if not isinstance(start, int): raise TypeError("start argument must be int") if not isinstance(stop, int): raise TypeError("stop argument must be int") if withscores: args = [b'WITHSCORES'] else: args = [] fut = self._conn.execute(b'ZREVRANGE', key, start, stop, *args) if withscores: return wait_convert(fut, pairs_int_or_float) return fut
def zrange(self, key, start=0, stop=-1, withscores=False, encoding=_NOTSET): """Return a range of members in a sorted set, by index. :raises TypeError: if start is not int :raises TypeError: if stop is not int """ if not isinstance(start, int): raise TypeError("start argument must be int") if not isinstance(stop, int): raise TypeError("stop argument must be int") if withscores: args = [b'WITHSCORES'] else: args = [] fut = self.execute(b'ZRANGE', key, start, stop, *args, encoding=encoding) if withscores: return wait_convert(fut, pairs_int_or_float) return fut
def scan(self, cursor=0, match=None, count=None): """Incrementally iterate the keys space. Usage example: >>> match = 'something*' >>> cur = b'0' >>> while cur: ... cur, keys = await redis.scan(cur, match=match) ... for key in keys: ... print('Matched:', key) """ args = [] if match is not None: args += [b'MATCH', match] if count is not None: args += [b'COUNT', count] fut = self.execute(b'SCAN', cursor, *args) return wait_convert(fut, lambda o: (int(o[0]), o[1]))
def georadius(self, key, longitude, latitude, radius, unit='m', *, with_dist=False, with_hash=False, with_coord=False, count=None, sort=None, encoding=_NOTSET): """Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point. Return value follows Redis convention: * if none of ``WITH*`` flags are set -- list of strings returned: >>> await redis.georadius('Sicily', 15, 37, 200, 'km') [b"Palermo", b"Catania"] * if any flag (or all) is set -- list of named tuples returned: >>> await redis.georadius('Sicily', 15, 37, 200, 'km', ... with_dist=True) [GeoMember(name=b"Palermo", dist=190.4424, hash=None, coord=None), GeoMember(name=b"Catania", dist=56.4413, hash=None, coord=None)] :raises TypeError: radius is not float or int :raises TypeError: count is not int :raises ValueError: if unit not equal ``m``, ``km``, ``mi`` or ``ft`` :raises ValueError: if sort not equal ``ASC`` or ``DESC`` :rtype: list[str] or list[GeoMember] """ args = validate_georadius_options( radius, unit, with_dist, with_hash, with_coord, count, sort ) fut = self.execute( b'GEORADIUS', key, longitude, latitude, radius, unit, *args, encoding=encoding ) if with_dist or with_hash or with_coord: return wait_convert(fut, make_geomember, with_dist=with_dist, with_hash=with_hash, with_coord=with_coord) return fut
def zscore(self, key, member): """Get the score associated with the given member in a sorted set.""" fut = self.execute(b'ZSCORE', key, member) return wait_convert(fut, optional_int_or_float)
def hincrbyfloat(self, key, field, increment=1.0): """Increment the float value of a hash field by the given number.""" fut = self.execute(b"HINCRBYFLOAT", key, field, increment) return wait_convert(fut, float)
def hexists(self, key, field): """Determine if hash field exists.""" fut = self.execute(b"HEXISTS", key, field) return wait_convert(fut, bool)
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 client_list(self): """Get the list of client connections.""" fut = self._conn.execute(b'CLIENT', b'LIST', encoding='utf-8') return wait_convert(fut, to_tuples)
def config_get(self, parameter): """Get the value of a configuration parameter.""" if not isinstance(parameter, str): raise TypeError("parameter must be str") fut = self._conn.execute(b'CONFIG', b'GET', parameter) return wait_convert(fut, to_dict)
def hexists(self, key, field): """Determine if hash field exists.""" fut = self._conn.execute(b'HEXISTS', key, field) return wait_convert(fut, bool)
def time(self): """Return current server time.""" fut = self._conn.execute(b'TIME') return wait_convert(fut, lambda obj: float(b'.'.join(obj)))
def persist(self, key): """Remove the existing timeout on key.""" fut = self._conn.execute(b'PERSIST', key) return wait_convert(fut, bool)
def cluster_slaves(self, node_id): """List slave nodes of the specified master node.""" fut = self.execute(b'CLUSTER', b'SLAVES', node_id) return wait_convert(fut, parse_cluster_nodes_lines, encoding=self.encoding)
def time(self): """Return current server time.""" fut = self.execute(b'TIME') return wait_convert(fut, to_time)
def cluster_nodes(self): """Get Cluster config for the node.""" fut = self.execute(b'CLUSTER', b'NODES') return wait_convert(fut, parse_cluster_nodes, encoding=self.encoding)
def xinfo_groups(self, stream): """Retrieve the consumer groups for a stream""" fut = self.execute(b'XINFO', b'GROUPS', stream) return wait_convert(fut, parse_lists_to_dicts)
def cluster_slots(self): """Get array of Cluster slot to node mappings.""" fut = self.execute(b'CLUSTER', b'SLOTS') return wait_convert(fut, parse_cluster_slots)
def exists(self, key): """Check if key exists.""" fut = self._conn.execute(b'EXISTS', key) return wait_convert(fut, bool)
def unlink(self, key, *keys): """Delete a key asynchronously in another thread.""" return wait_convert(self.execute(b'UNLINK', key, *keys), int)
def info(self, section): """Get information and statistics about the server.""" # TODO: check section fut = self._conn.execute(b'INFO', section, encoding='utf-8') return wait_convert(fut, parse_info)
def hincrbyfloat(self, key, field, increment=1.0): """Increment the float value of a hash field by the given number.""" fut = self._conn.execute(b'HINCRBYFLOAT', key, field, increment) return wait_convert(fut, float)
def delete(self, key, *keys): """Delete a key.""" fut = self._conn.execute(b'DEL', key, *keys) return wait_convert(fut, int)
def xinfo_help(self): """Retrieve help regarding the ``XINFO`` sub-commands""" fut = self.execute(b"XINFO", b"HELP") return wait_convert(fut, lambda l: b"\n".join(l))
def zscore(self, key, member): """Get the score associated with the given member in a sorted set.""" fut = self._conn.execute(b'ZSCORE', key, member) return wait_convert(fut, optional_int_or_float)
def xinfo_help(self): """Retrieve help regarding the ``XINFO`` sub-commands""" fut = self.execute(b'XINFO', b'HELP') return wait_convert(fut, lambda l: b'\n'.join(l))
def xgroup_delconsumer(self, stream, group_name, consumer_name): """Delete a specific consumer from a group""" fut = self.execute(b'XGROUP', b'DELCONSUMER', stream, group_name, consumer_name) return wait_convert(fut, int)
def cluster_info(self): """Provides info about Redis Cluster node state.""" fut = self.execute(b'CLUSTER', b'INFO') return wait_convert(fut, parse_info, encoding=self.encoding)
def hgetall(self, key): """Get all the fields and values in a hash.""" fut = self._conn.execute(b'HGETALL', key) return wait_convert(fut, to_dict)
def xclaim(self, stream, group_name, consumer_name, min_idle_time, id, *ids): """Claim a message for a given consumer""" fut = self.execute(b'XCLAIM', stream, group_name, consumer_name, min_idle_time, id, *ids) return wait_convert(fut, parse_messages)
def xinfo_consumers(self, stream, group_name): """Retrieve consumers of a consumer group""" fut = self.execute(b'XINFO', b'CONSUMERS', stream, group_name) return wait_convert(fut, parse_lists_to_dicts)
def georadius( self, key, longitude, latitude, radius, unit="m", *, with_dist=False, with_hash=False, with_coord=False, count=None, sort=None, encoding=_NOTSET ): """Query a sorted set representing a geospatial index to fetch members matching a given maximum distance from a point. Return value follows Redis convention: * if none of ``WITH*`` flags are set -- list of strings returned: >>> await redis.georadius('Sicily', 15, 37, 200, 'km') [b"Palermo", b"Catania"] * if any flag (or all) is set -- list of named tuples returned: >>> await redis.georadius('Sicily', 15, 37, 200, 'km', ... with_dist=True) [GeoMember(name=b"Palermo", dist=190.4424, hash=None, coord=None), GeoMember(name=b"Catania", dist=56.4413, hash=None, coord=None)] :raises TypeError: radius is not float or int :raises TypeError: count is not int :raises ValueError: if unit not equal ``m``, ``km``, ``mi`` or ``ft`` :raises ValueError: if sort not equal ``ASC`` or ``DESC`` :rtype: list[str] or list[GeoMember] """ args = validate_georadius_options( radius, unit, with_dist, with_hash, with_coord, count, sort ) fut = self.execute( b"GEORADIUS", key, longitude, latitude, radius, unit, *args, encoding=encoding ) if with_dist or with_hash or with_coord: return wait_convert( fut, make_geomember, with_dist=with_dist, with_hash=with_hash, with_coord=with_coord, ) return fut