diff --git a/pyredis/__init__.py b/pyredis/__init__.py index a7c2619..8f69d4b 100644 --- a/pyredis/__init__.py +++ b/pyredis/__init__.py @@ -83,6 +83,9 @@ def get_by_url( Args: url: The URL containing connection information and options. async_client: If True, returns the asynchronous pool or client variant. + + Returns: + A connection pool or client instance matching the scheme and configuration. """ scheme, rest = url.split("://", 1) conns = list() diff --git a/pyredis/client/async_client.py b/pyredis/client/async_client.py index 2a06790..fd2a296 100644 --- a/pyredis/client/async_client.py +++ b/pyredis/client/async_client.py @@ -24,16 +24,33 @@ class AsyncClient( """ def __init__(self, **kwargs): + """ + Initialize the AsyncClient connection. + + Args: + **kwargs: Connection options forwarded to AsyncConnection. + """ super().__init__() self._conn = AsyncConnection(**kwargs) async def execute(self, *args): + """ + Asynchronously execute a Redis command. + + Args: + *args: Command name and positional arguments. + + Returns: + Parsed Redis reply. + """ await self._conn.write(*args) return await self._conn.read() async def close(self): + """Asynchronously close the underlying connection.""" await self._conn.close() @property def closed(self): + """Flag indicating if connection is closed.""" return self._conn.closed diff --git a/pyredis/client/async_cluster.py b/pyredis/client/async_cluster.py index 70c548f..8118cb0 100644 --- a/pyredis/client/async_cluster.py +++ b/pyredis/client/async_cluster.py @@ -38,6 +38,20 @@ def __init__( cluster_map=None, username=None, ): + """ + Initialize the AsyncClusterClient. + + Args: + seeds: List of (host, port) tuples representing cluster seeds. + database: Redis database index (default: 0). + password: Optional password for Redis authentication. + encoding: Optional string encoding for decoding responses. + slave_ok: If True, allows routing read commands to replicas. + conn_timeout: Connection timeout in seconds. + read_timeout: Read timeout in seconds. + cluster_map: Optional pre-configured AsyncClusterMap instance. + username: Optional username for Redis ACL authentication. + """ super().__init__() if not bool(seeds) != bool(cluster_map): raise PyRedisError("Ether seeds or cluster_map has to be provided") @@ -101,6 +115,11 @@ async def _get_slot_info(self, shard_key): @property def closed(self): + """ + Flag indicating if all cluster connections are closed. + + Always returns False for AsyncClusterClient. + """ return False async def execute( @@ -111,6 +130,19 @@ async def execute( asking=False, retries=3 ): + """ + Execute a Redis command on the appropriate cluster node asynchronously. + + Args: + *args: Command name and arguments. + shard_key: Key used to determine the slot and node for routing. + sock: Optional explicit socket identifier (host_port) to route to. + asking: Flag indicating if this is an ASKING command redirection. + retries: Number of retries on slot redirection before failing. + + Returns: + The Redis command response. + """ if not bool(shard_key) != bool(sock): raise PyRedisError("Ether shard_key or sock has to be provided") if not sock: diff --git a/pyredis/client/async_hash.py b/pyredis/client/async_hash.py index e0cd7f1..d1df175 100644 --- a/pyredis/client/async_hash.py +++ b/pyredis/client/async_hash.py @@ -36,6 +36,18 @@ def __init__( read_timeout=2, username=None, ): + """ + Initialize the AsyncHashClient. + + Args: + buckets: List of (host, port) tuples representing the server buckets. + database: Optional Redis database index. + password: Optional password for Redis authentication. + encoding: Optional string encoding for decoding responses. + conn_timeout: Connection timeout in seconds. + read_timeout: Read timeout in seconds. + username: Optional username for Redis ACL authentication. + """ super().__init__() self._conns = dict() self._conn_names = list() @@ -116,9 +128,17 @@ def _init_map(self): @property def bulk(self): + """Flag indicating if bulk mode is active.""" return self._bulk def bulk_start(self, bulk_size=5000, keep_results=True): + """ + Start bulk command pipelining mode. + + Args: + bulk_size: Maximum commands to queue before reading responses. + keep_results: Flag indicating if responses should be returned. + """ if self.bulk: raise PyRedisError("Already in bulk mode") self._bulk = True @@ -129,6 +149,12 @@ def bulk_start(self, bulk_size=5000, keep_results=True): self._bulk_keep = True async def bulk_stop(self): + """ + Stop bulk mode and retrieve results asynchronously. + + Returns: + List of execution results if keep_results was set. + """ if not self.bulk: raise PyRedisError("Not in bulk mode") await self._bulk_fetch() @@ -141,15 +167,28 @@ async def bulk_stop(self): return results async def close(self): + """Close all connections to the server buckets asynchronously.""" for conn in self._conns.values(): await conn.close() self._closed = True @property def closed(self): + """Flag indicating if the client connections are closed.""" return self._closed async def execute(self, *args, shard_key=None, sock=None): + """ + Execute a command on the appropriate bucket asynchronously. + + Args: + *args: Command name and arguments. + shard_key: Key used to calculate the slot and route the command. + sock: Optional explicit socket name/bucket to route to. + + Returns: + The Redis command response, or None if in bulk mode. + """ if not bool(shard_key) != bool(sock): raise PyRedisError("Ether shard_key or sock has to be provided") if not sock: diff --git a/pyredis/client/async_pubsub.py b/pyredis/client/async_pubsub.py index 5465c7e..665b2be 100644 --- a/pyredis/client/async_pubsub.py +++ b/pyredis/client/async_pubsub.py @@ -11,17 +11,37 @@ class AsyncPubSubClient(commands.Subscribe): """ def __init__(self, **kwargs): + """ + Initialize the AsyncPubSubClient connection. + + Args: + **kwargs: Connection options forwarded to AsyncConnection. + """ self._conn = pyredis.client.AsyncConnection(**kwargs) async def close(self): + """Close the underlying connection asynchronously.""" await self._conn.close() @property def closed(self): + """Flag indicating if the connection is closed.""" return self._conn.closed async def write(self, *args): + """ + Write a command to the underlying connection asynchronously. + + Args: + *args: Command name and arguments. + """ return await self._conn.write(*args) async def get(self): + """ + Read the next message/response from the connection asynchronously. + + Returns: + The message or response read from Redis. + """ return await self._conn.read(close_on_timeout=False) diff --git a/pyredis/client/async_sentinel.py b/pyredis/client/async_sentinel.py index 2a718aa..14ae086 100644 --- a/pyredis/client/async_sentinel.py +++ b/pyredis/client/async_sentinel.py @@ -11,6 +11,14 @@ class AsyncSentinelClient(object): """ def __init__(self, sentinels, password=None, username=None): + """ + Initialize the AsyncSentinelClient. + + Args: + sentinels: List of (host, port) tuples representing the Sentinel nodes. + password: Optional password for Sentinel authentication. + username: Optional username for Sentinel ACL authentication. + """ self._conn = None self._sentinels = deque(sentinels) self._password = password @@ -42,27 +50,53 @@ async def _sentinel_get(self): raise PyRedisConnError("Could not connect to any sentinel") async def close(self): + """Close the active Sentinel connection asynchronously.""" if self._conn: await self._conn.close() self._conn = None @property def sentinels(self): + """Deque of configured Sentinel (host, port) node addresses.""" return self._sentinels async def execute(self, *args): + """ + Execute a Sentinel command asynchronously, automatically selecting an active Sentinel node. + + Args: + *args: Command name and arguments. + + Returns: + The Sentinel command response. + """ if not self._conn: await self._sentinel_get() await self._conn.write(*args) return await self._conn.read() async def get_master(self, name): + """ + Get the master node configuration for the specified service name asynchronously. + + Args: + name: The service name of the Redis master. + + Returns: + Dict containing the master's configuration. + """ result = await self.execute( *["SENTINEL", "master", name] ) return pyredis.client.dict_from_list(result) async def get_masters(self): + """ + Get configurations for all monitored Redis master nodes asynchronously. + + Returns: + List of dicts containing configurations for all monitored masters. + """ masters = await self.execute( *["SENTINEL", "masters"] ) @@ -74,6 +108,15 @@ async def get_masters(self): return result async def get_slaves(self, name): + """ + Get replication replica configurations for the specified master service name asynchronously. + + Args: + name: The service name of the Redis master. + + Returns: + List of dicts containing replica configurations. + """ slaves = await self.execute( *["SENTINEL", "slaves", name] ) @@ -85,5 +128,6 @@ async def get_slaves(self, name): return result async def next_sentinel(self): + """Close the active connection and rotate the Sentinel node list asynchronously.""" await self.close() self._sentinels.rotate(-1) diff --git a/pyredis/client/client.py b/pyredis/client/client.py index c63da2f..ed71179 100644 --- a/pyredis/client/client.py +++ b/pyredis/client/client.py @@ -25,6 +25,12 @@ class Client( """ def __init__(self, **kwargs): + """ + Initialize the Client connection. + + Args: + **kwargs: Connection options forwarded to Connection. + """ super().__init__() self._conn = pyredis.client.Connection(**kwargs) self._bulk = False @@ -52,9 +58,17 @@ def _execute_bulk(self, *args): @property def bulk(self): + """Flag indicating if bulk mode is active.""" return self._bulk def bulk_start(self, bulk_size=5000, keep_results=True): + """ + Start bulk command pipelining mode. + + Args: + bulk_size: Maximum commands to queue before reading responses. + keep_results: Flag indicating if responses should be returned. + """ if self.bulk: raise PyRedisError("Already in bulk mode") self._bulk = True @@ -65,6 +79,12 @@ def bulk_start(self, bulk_size=5000, keep_results=True): self._bulk_keep = True def bulk_stop(self): + """ + Stop bulk mode and retrieve results. + + Returns: + List of execution results if keep_results was set. + """ if not self.bulk: raise PyRedisError("Not in bulk mode") self._bulk_fetch() @@ -77,13 +97,24 @@ def bulk_stop(self): return results def close(self): + """Close the underlying connection.""" self._conn.close() @property def closed(self): + """Flag indicating if connection is closed.""" return self._conn.closed def execute(self, *args): + """ + Execute a Redis command. + + Args: + *args: Command name and positional arguments. + + Returns: + Parsed Redis reply. + """ if not self._bulk: return self._execute_basic(*args) else: diff --git a/pyredis/client/cluster.py b/pyredis/client/cluster.py index 6366dc9..7f8cd8f 100644 --- a/pyredis/client/cluster.py +++ b/pyredis/client/cluster.py @@ -38,6 +38,20 @@ def __init__( cluster_map=None, username=None, ): + """ + Initialize the ClusterClient. + + Args: + seeds: List of (host, port) tuples representing cluster seeds. + database: Redis database index (default: 0). + password: Optional password for Redis authentication. + encoding: Optional string encoding for decoding responses. + slave_ok: If True, allows routing read commands to replicas. + conn_timeout: Connection timeout in seconds. + read_timeout: Read timeout in seconds. + cluster_map: Optional pre-configured ClusterMap instance. + username: Optional username for Redis ACL authentication. + """ super().__init__() if not bool(seeds) != bool(cluster_map): raise PyRedisError("Ether seeds or cluster_map has to be provided") @@ -101,6 +115,11 @@ def _get_slot_info(self, shard_key): @property def closed(self): + """ + Flag indicating if all cluster connections are closed. + + Always returns False for ClusterClient. + """ return False def execute( @@ -111,6 +130,19 @@ def execute( asking=False, retries=3 ): + """ + Execute a Redis command on the appropriate cluster node. + + Args: + *args: Command name and arguments. + shard_key: Key used to determine the slot and node for routing. + sock: Optional explicit socket identifier (host_port) to route to. + asking: Flag indicating if this is an ASKING command redirection. + retries: Number of retries on slot redirection before failing. + + Returns: + The Redis command response. + """ if not bool(shard_key) != bool(sock): raise PyRedisError("Ether shard_key or sock has to be provided") if not sock: diff --git a/pyredis/client/hash.py b/pyredis/client/hash.py index 7c4bdac..028ccdd 100644 --- a/pyredis/client/hash.py +++ b/pyredis/client/hash.py @@ -36,6 +36,18 @@ def __init__( read_timeout=2, username=None, ): + """ + Initialize the HashClient. + + Args: + buckets: List of (host, port) tuples representing the server buckets. + database: Optional Redis database index. + password: Optional password for Redis authentication. + encoding: Optional string encoding for decoding responses. + conn_timeout: Connection timeout in seconds. + read_timeout: Read timeout in seconds. + username: Optional username for Redis ACL authentication. + """ super().__init__() self._conns = dict() self._conn_names = list() @@ -116,9 +128,17 @@ def _init_map(self): @property def bulk(self): + """Flag indicating if bulk mode is active.""" return self._bulk def bulk_start(self, bulk_size=5000, keep_results=True): + """ + Start bulk command pipelining mode. + + Args: + bulk_size: Maximum commands to queue before reading responses. + keep_results: Flag indicating if responses should be returned. + """ if self.bulk: raise PyRedisError("Already in bulk mode") self._bulk = True @@ -129,6 +149,12 @@ def bulk_start(self, bulk_size=5000, keep_results=True): self._bulk_keep = True def bulk_stop(self): + """ + Stop bulk mode and retrieve results. + + Returns: + List of execution results if keep_results was set. + """ if not self.bulk: raise PyRedisError("Not in bulk mode") self._bulk_fetch() @@ -141,15 +167,28 @@ def bulk_stop(self): return results def close(self): + """Close all connections to the server buckets.""" for conn in self._conns.values(): conn.close() self._closed = True @property def closed(self): + """Flag indicating if the client connections are closed.""" return self._closed def execute(self, *args, shard_key=None, sock=None): + """ + Execute a command on the appropriate bucket. + + Args: + *args: Command name and arguments. + shard_key: Key used to calculate the slot and route the command. + sock: Optional explicit socket name/bucket to route to. + + Returns: + The Redis command response, or None if in bulk mode. + """ if not bool(shard_key) != bool(sock): raise PyRedisError("Ether shard_key or sock has to be provided") if not sock: diff --git a/pyredis/client/pubsub.py b/pyredis/client/pubsub.py index 7bc6e53..ace0bdf 100644 --- a/pyredis/client/pubsub.py +++ b/pyredis/client/pubsub.py @@ -11,17 +11,37 @@ class PubSubClient(commands.Subscribe): """ def __init__(self, **kwargs): + """ + Initialize the PubSubClient connection. + + Args: + **kwargs: Connection options forwarded to Connection. + """ self._conn = pyredis.client.Connection(**kwargs) def close(self): + """Close the underlying connection.""" self._conn.close() @property def closed(self): + """Flag indicating if the connection is closed.""" return self._conn.closed def write(self, *args): + """ + Write a command to the underlying connection. + + Args: + *args: Command name and arguments. + """ return self._conn.write(*args) def get(self): + """ + Read the next message/response from the connection. + + Returns: + The message or response read from Redis. + """ return self._conn.read(close_on_timeout=False) diff --git a/pyredis/client/sentinel.py b/pyredis/client/sentinel.py index 0832bad..706d1b0 100644 --- a/pyredis/client/sentinel.py +++ b/pyredis/client/sentinel.py @@ -11,6 +11,14 @@ class SentinelClient(object): """ def __init__(self, sentinels, password=None, username=None): + """ + Initialize the SentinelClient. + + Args: + sentinels: List of (host, port) tuples representing the Sentinel nodes. + password: Optional password for Sentinel authentication. + username: Optional username for Sentinel ACL authentication. + """ self._conn = None self._sentinels = deque(sentinels) self._password = password @@ -42,21 +50,41 @@ def _sentinel_get(self): raise PyRedisConnError("Could not connect to any sentinel") def close(self): + """Close the active Sentinel connection.""" if self._conn: self._conn.close() self._conn = None @property def sentinels(self): + """Deque of configured Sentinel (host, port) node addresses.""" return self._sentinels def execute(self, *args): + """ + Execute a Sentinel command, automatically selecting an active Sentinel node. + + Args: + *args: Command name and arguments. + + Returns: + The Sentinel command response. + """ if not self._conn: self._sentinel_get() self._conn.write(*args) return self._conn.read() def get_master(self, name): + """ + Get the master node configuration for the specified service name. + + Args: + name: The service name of the Redis master. + + Returns: + Dict containing the master's configuration. + """ return pyredis.client.dict_from_list( self.execute( *["SENTINEL", "master", name] @@ -64,6 +92,12 @@ def get_master(self, name): ) def get_masters(self): + """ + Get configurations for all monitored Redis master nodes. + + Returns: + List of dicts containing configurations for all monitored masters. + """ masters = self.execute( *["SENTINEL", "masters"] ) @@ -75,6 +109,15 @@ def get_masters(self): return result def get_slaves(self, name): + """ + Get replication replica configurations for the specified master service name. + + Args: + name: The service name of the Redis master. + + Returns: + List of dicts containing replica configurations. + """ slaves = self.execute( *["SENTINEL", "slaves", name] ) @@ -86,5 +129,6 @@ def get_slaves(self, name): return result def next_sentinel(self): + """Close the active connection and rotate the Sentinel node list.""" self.close() self._sentinels.rotate(-1) diff --git a/pyredis/connection/async_connection.py b/pyredis/connection/async_connection.py index 27dc907..17b2e5e 100644 --- a/pyredis/connection/async_connection.py +++ b/pyredis/connection/async_connection.py @@ -8,6 +8,13 @@ class AsyncConnection(object): + """ + Low level asynchronous client for talking to a Redis Server. + + Manages connection lifecycle, non-blocking network streams via asyncio, + protocol serialization, authentication, and async reads/writes. + """ + def __init__( self, host=None, @@ -22,6 +29,23 @@ def __init__( sentinel=False, username=None, ): + """ + Initialize asynchronous connection parameters. + + Args: + host: Redis server hostname or IP. + port: Redis server port number. + unix_sock: Path to Unix domain socket. + database: Database index to select. + password: Password for authentication. + encoding: Optional string encoding for automatic decoding. + conn_timeout: Async connection timeout in seconds. + read_only: Flag indicating if the connection is read-only. + read_timeout: Async socket read timeout in seconds. + sentinel: Flag indicating if this is a Sentinel connection. + username: Username for ACL authentication. + """ + if not bool(host) != bool(unix_sock): raise PyRedisError("Ether host or unix_sock has to be provided") self._closed = False @@ -128,6 +152,9 @@ async def _set_read_only(self): raise err async def close(self): + """ + Asynchronously close the socket writer and clean up connection resources. + """ if self._writer: self._writer.close() try: @@ -141,9 +168,27 @@ async def close(self): @property def closed(self): + """ + Check if the connection has been closed. + + Returns: + True if closed, False otherwise. + """ return self._closed + async def read(self, close_on_timeout=True, raise_on_result_err=True): + """ + Asynchronously read and parse a reply from the Redis server. + + Args: + close_on_timeout: If True, closes the connection on read timeout. + raise_on_result_err: If True, raises exceptions returned as replies. + + Returns: + Parsed Redis reply (e.g. string, integer, list, dict, or None). + """ + if not self._writer: await self._connect() while True: @@ -173,6 +218,13 @@ async def read(self, close_on_timeout=True, raise_on_result_err=True): self._reader_parser.feed(data) async def write(self, *args): + """ + Asynchronously serialize and send a command to the Redis server. + + Args: + *args: Command name and positional arguments. + """ + if not self._writer: await self._connect() data = self._writer_func(*args) diff --git a/pyredis/connection/connection.py b/pyredis/connection/connection.py index 97592f2..25a5e9e 100644 --- a/pyredis/connection/connection.py +++ b/pyredis/connection/connection.py @@ -7,7 +7,12 @@ class Connection(object): - """Low level client for talking to a Redis Server.""" + """ + Low level client for talking to a Redis Server. + + Manages socket lifecycle, protocol serialization, authentication, + and reads/writes for a single synchronous connection. + """ def __init__( self, @@ -23,6 +28,22 @@ def __init__( sentinel=False, username=None, ): + """ + Initialize connection parameters. + + Args: + host: Redis server hostname or IP. + port: Redis server port number. + unix_sock: Path to Unix domain socket. + database: Database index to select. + password: Password for authentication. + encoding: Optional string encoding for automatic decoding. + conn_timeout: Socket connection timeout in seconds. + read_only: Flag indicating if the connection is read-only. + read_timeout: Socket read timeout in seconds. + sentinel: Flag indicating if this is a Sentinel connection. + username: Username for ACL authentication. + """ if not bool(host) != bool(unix_sock): raise PyRedisError("Ether host or unix_sock has to be provided") self._closed = False @@ -144,6 +165,9 @@ def _set_read_only(self): raise err def close(self): + """ + Close the socket and clean up connection resources. + """ if self._sock: self._sock.close() self._sock = None @@ -152,9 +176,25 @@ def close(self): @property def closed(self): + """ + Check if the connection has been closed. + + Returns: + True if the connection is closed, False otherwise. + """ return self._closed def read(self, close_on_timeout=True, raise_on_result_err=True): + """ + Read and parse a reply from the Redis server. + + Args: + close_on_timeout: If True, closes the connection on read timeout. + raise_on_result_err: If True, raises exceptions returned as replies. + + Returns: + Parsed Redis reply (e.g. string, integer, list, dict, or None). + """ if not self._sock: self._connect() while True: @@ -181,6 +221,12 @@ def read(self, close_on_timeout=True, raise_on_result_err=True): self._reader.feed(data) def write(self, *args): + """ + Serialize and send a command to the Redis server. + + Args: + *args: Command name and positional arguments. + """ if not self._sock: self._connect() data = self._writer(*args) diff --git a/pyredis/pool/async_base.py b/pyredis/pool/async_base.py index fd67d36..17dc700 100644 --- a/pyredis/pool/async_base.py +++ b/pyredis/pool/async_base.py @@ -21,6 +21,20 @@ def __init__( lock=None, username=None, ): + """ + Initialize asynchronous connection pool parameters. + + Args: + database: Database index to select. + password: Password for authentication. + encoding: Optional string encoding for automatic decoding. + conn_timeout: Async connection timeout in seconds. + read_timeout: Async read timeout in seconds. + pool_size: Maximum number of connections allowed in the pool. + lock: Asyncio lock for synchronization. + username: Username for ACL authentication. + """ + self._conn_timeout = conn_timeout self._read_timeout = read_timeout if lock is None: @@ -39,26 +53,32 @@ def __init__( @property def conn_timeout(self): + """Async connection timeout in seconds.""" return self._conn_timeout @property def read_timeout(self): + """Async read timeout in seconds.""" return self._read_timeout @property def database(self): + """Database index selected on connections.""" return self._database @property def password(self): + """Authentication password.""" return self._password @property def encoding(self): + """Optional string decoding encoding.""" return self._encoding @property def pool_size(self): + """Maximum number of connections allowed in the pool.""" return self._pool_size @pool_size.setter @@ -77,16 +97,30 @@ def pool_size(self, size): @property def close_on_err(self): + """Whether to close all idle connections when a connection closes on error.""" return self._close_on_err @property def username(self): + """ACL authentication username.""" return self._username def _connect(self): raise NotImplementedError async def acquire(self): + """ + Asynchronously acquire a connection from the pool. + + Reuses an idle connection or establishes a new one if the pool size limit + has not been reached. + + Returns: + An AsyncConnection instance. + + Raises: + PyRedisError: If the maximum pool size is exceeded. + """ async with self._lock: try: client = self._pool_free.pop() @@ -103,10 +137,17 @@ async def acquire(self): ) return client + async def release( self, conn ): + """ + Asynchronously release a connection back to the pool. + + Args: + conn: The AsyncConnection instance to return. + """ async with self._lock: try: current_size = len(self._pool_free) + len(self._pool_used) @@ -124,11 +165,22 @@ async def release( except KeyError: await conn.close() + async def execute( self, *args, **kwargs ): + """ + Asynchronously acquire a connection, execute a command, and release it. + + Args: + *args: Command name and positional arguments. + **kwargs: Execution options (e.g. shard_key, sock). + + Returns: + Parsed Redis reply. + """ conn = await self.acquire() try: return await conn.execute( @@ -139,3 +191,4 @@ async def execute( await self.release( conn=conn ) + diff --git a/pyredis/pool/async_cluster.py b/pyredis/pool/async_cluster.py index cf9a04f..7e50d97 100644 --- a/pyredis/pool/async_cluster.py +++ b/pyredis/pool/async_cluster.py @@ -31,6 +31,16 @@ def __init__( username=None, **kwargs ): + """ + Initialize the AsyncClusterPool connection manager. + + Args: + seeds: List of seed node addresses (e.g. ['host:port']). + slave_ok: Flag indicating if reading from replica nodes is allowed. + password: Password for authentication. + username: Username for ACL authentication. + **kwargs: Additional options forwarded to AsyncBasePool. + """ super().__init__( password=password, **kwargs @@ -45,6 +55,7 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok def _connect(self): diff --git a/pyredis/pool/async_hash.py b/pyredis/pool/async_hash.py index c1dce32..83c2a09 100644 --- a/pyredis/pool/async_hash.py +++ b/pyredis/pool/async_hash.py @@ -25,12 +25,20 @@ class AsyncHashPool( """ def __init__(self, buckets, **kwargs): + """ + Initialize the AsyncHashPool connection manager. + + Args: + buckets: Dict mapping server keyspace slots/buckets to connection options. + **kwargs: Additional options forwarded to AsyncBasePool. + """ super().__init__(**kwargs) self._buckets = buckets self._cluster = True @property def buckets(self): + """Dict of connection options for node buckets.""" return self._buckets def _connect(self): diff --git a/pyredis/pool/async_pool.py b/pyredis/pool/async_pool.py index 930f3b6..a225478 100644 --- a/pyredis/pool/async_pool.py +++ b/pyredis/pool/async_pool.py @@ -32,6 +32,15 @@ def __init__( unix_sock=None, **kwargs ): + """ + Initialize the AsyncPool connection manager. + + Args: + host: Redis server hostname or IP. + port: Redis server port number. + unix_sock: Path to Unix domain socket. + **kwargs: Additional options forwarded to AsyncBasePool. + """ if not bool(host) != bool(unix_sock): raise PyRedisError("Ether host or unix_sock has to be provided") super().__init__(**kwargs) @@ -41,14 +50,17 @@ def __init__( @property def host(self): + """Hostname or IP of the Redis server.""" return self._host @property def port(self): + """Port number of the Redis server.""" return self._port @property def unix_sock(self): + """Path to the Unix domain socket.""" return self._unix_sock def _connect(self): diff --git a/pyredis/pool/async_sentinel.py b/pyredis/pool/async_sentinel.py index dc0cf2a..d368071 100644 --- a/pyredis/pool/async_sentinel.py +++ b/pyredis/pool/async_sentinel.py @@ -35,6 +35,18 @@ def __init__( sentinel_username=None, **kwargs ): + """ + Initialize the AsyncSentinelPool connection manager. + + Args: + sentinels: List of Sentinel node addresses (e.g. ['host:port']). + name: Name of the master group to monitor. + slave_ok: Flag indicating if reading from replica nodes is allowed. + retries: Number of connection retries. + sentinel_password: Password for Sentinel authentication. + sentinel_username: Username for Sentinel ACL authentication. + **kwargs: Additional options forwarded to AsyncBasePool. + """ super().__init__(**kwargs) self._sentinel = pyredis.pool.AsyncSentinelClient( sentinels=sentinels, @@ -48,14 +60,17 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok @property def name(self): + """Name of the monitored master group.""" return self._name @property def retries(self): + """Number of connection retries.""" return self._retries @property diff --git a/pyredis/pool/async_sentinel_hash.py b/pyredis/pool/async_sentinel_hash.py index 62d2d1c..76ad8a5 100644 --- a/pyredis/pool/async_sentinel_hash.py +++ b/pyredis/pool/async_sentinel_hash.py @@ -35,6 +35,18 @@ def __init__( sentinel_username=None, **kwargs ): + """ + Initialize the AsyncSentinelHashPool connection manager. + + Args: + sentinels: List of Sentinel node addresses (e.g. ['host:port']). + buckets: Dict mapping server keyspace slots/buckets to master group names. + slave_ok: Flag indicating if reading from replica nodes is allowed. + retries: Number of connection retries. + sentinel_password: Password for Sentinel authentication. + sentinel_username: Username for Sentinel ACL authentication. + **kwargs: Additional options forwarded to AsyncBasePool. + """ super().__init__(**kwargs) self._sentinel = pyredis.pool.AsyncSentinelClient( sentinels=sentinels, @@ -49,14 +61,17 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok @property def buckets(self): + """Dict mapping server keyspace slots/buckets to master group names.""" return self._buckets @property def retries(self): + """Number of connection retries.""" return self._retries @property diff --git a/pyredis/pool/base.py b/pyredis/pool/base.py index e368aa4..5be9cea 100644 --- a/pyredis/pool/base.py +++ b/pyredis/pool/base.py @@ -21,6 +21,20 @@ def __init__( lock=None, username=None, ): + """ + Initialize connection pool parameters. + + Args: + database: Database index to select. + password: Password for authentication. + encoding: Optional string encoding for automatic decoding. + conn_timeout: Socket connection timeout in seconds. + read_timeout: Socket read timeout in seconds. + pool_size: Maximum number of connections allowed in the pool. + lock: Threading lock for synchronization. + username: Username for ACL authentication. + """ + self._conn_timeout = conn_timeout self._read_timeout = read_timeout if lock is None: @@ -39,26 +53,32 @@ def __init__( @property def conn_timeout(self): + """Socket connection timeout in seconds.""" return self._conn_timeout @property def read_timeout(self): + """Socket read timeout in seconds.""" return self._read_timeout @property def database(self): + """Database index selected on connections.""" return self._database @property def password(self): + """Authentication password.""" return self._password @property def encoding(self): + """Optional string decoding encoding.""" return self._encoding @property def pool_size(self): + """Maximum number of connections allowed in the pool.""" return self._pool_size @pool_size.setter @@ -79,16 +99,30 @@ def pool_size(self, size): @property def close_on_err(self): + """Whether to close all idle connections when a connection closes on error.""" return self._close_on_err @property def username(self): + """ACL authentication username.""" return self._username def _connect(self): raise NotImplementedError def acquire(self): + """ + Acquire a connection from the pool. + + Reuses an idle connection or establishes a new one if the pool size limit + has not been reached. + + Returns: + A Connection instance. + + Raises: + PyRedisError: If the maximum pool size is exceeded. + """ try: self._lock.acquire() client = self._pool_free.pop() @@ -105,7 +139,14 @@ def acquire(self): self._lock.release() return client + def release(self, conn): + """ + Release a connection back to the pool. + + Args: + conn: The Connection instance to return. + """ try: self._lock.acquire() current_size = len(self._pool_free) + len(self._pool_used) @@ -125,7 +166,18 @@ def release(self, conn): finally: self._lock.release() + def execute(self, *args, **kwargs): + """ + Acquire a connection, execute a command, and release it back to the pool. + + Args: + *args: Command name and positional arguments. + **kwargs: Execution options (e.g. shard_key, sock). + + Returns: + Parsed Redis reply. + """ conn = self.acquire() try: return conn.execute( @@ -134,3 +186,4 @@ def execute(self, *args, **kwargs): ) finally: self.release(conn) + diff --git a/pyredis/pool/cluster.py b/pyredis/pool/cluster.py index 3faf2b9..43ee979 100644 --- a/pyredis/pool/cluster.py +++ b/pyredis/pool/cluster.py @@ -31,6 +31,16 @@ def __init__( username=None, **kwargs ): + """ + Initialize the ClusterPool connection manager. + + Args: + seeds: List of seed node addresses (e.g. ['host:port']). + slave_ok: Flag indicating if reading from replica nodes is allowed. + password: Password for authentication. + username: Username for ACL authentication. + **kwargs: Additional options forwarded to BasePool. + """ super().__init__( password=password, **kwargs @@ -45,6 +55,7 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok def _connect(self): diff --git a/pyredis/pool/hash.py b/pyredis/pool/hash.py index 2a98fed..481b681 100644 --- a/pyredis/pool/hash.py +++ b/pyredis/pool/hash.py @@ -25,12 +25,20 @@ class HashPool( """ def __init__(self, buckets, **kwargs): + """ + Initialize the HashPool connection manager. + + Args: + buckets: Dict mapping server keyspace slots/buckets to connection options. + **kwargs: Additional options forwarded to BasePool. + """ super().__init__(**kwargs) self._buckets = buckets self._cluster = True @property def buckets(self): + """Dict of connection options for node buckets.""" return self._buckets def _connect(self): diff --git a/pyredis/pool/pool.py b/pyredis/pool/pool.py index 7d2a956..3b6672a 100644 --- a/pyredis/pool/pool.py +++ b/pyredis/pool/pool.py @@ -26,6 +26,15 @@ class Pool( """ def __init__(self, host=None, port=6379, unix_sock=None, **kwargs): + """ + Initialize the Pool connection manager. + + Args: + host: Redis server hostname or IP. + port: Redis server port number. + unix_sock: Path to Unix domain socket. + **kwargs: Additional options forwarded to BasePool. + """ if not bool(host) != bool(unix_sock): raise PyRedisError("Ether host or unix_sock has to be provided") super().__init__(**kwargs) @@ -35,14 +44,17 @@ def __init__(self, host=None, port=6379, unix_sock=None, **kwargs): @property def host(self): + """Hostname or IP of the Redis server.""" return self._host @property def port(self): + """Port number of the Redis server.""" return self._port @property def unix_sock(self): + """Path to the Unix domain socket.""" return self._unix_sock def _connect(self): diff --git a/pyredis/pool/sentinel.py b/pyredis/pool/sentinel.py index ef13bbc..d430a67 100644 --- a/pyredis/pool/sentinel.py +++ b/pyredis/pool/sentinel.py @@ -35,6 +35,18 @@ def __init__( sentinel_username=None, **kwargs ): + """ + Initialize the SentinelPool connection manager. + + Args: + sentinels: List of Sentinel node addresses (e.g. ['host:port']). + name: Name of the master group to monitor. + slave_ok: Flag indicating if reading from replica nodes is allowed. + retries: Number of connection retries. + sentinel_password: Password for Sentinel authentication. + sentinel_username: Username for Sentinel ACL authentication. + **kwargs: Additional options forwarded to BasePool. + """ super().__init__(**kwargs) self._sentinel = pyredis.pool.SentinelClient( sentinels=sentinels, @@ -48,14 +60,17 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok @property def name(self): + """Name of the monitored master group.""" return self._name @property def retries(self): + """Number of connection retries.""" return self._retries @property diff --git a/pyredis/pool/sentinel_hash.py b/pyredis/pool/sentinel_hash.py index 3daaabd..30c0864 100644 --- a/pyredis/pool/sentinel_hash.py +++ b/pyredis/pool/sentinel_hash.py @@ -35,6 +35,18 @@ def __init__( sentinel_username=None, **kwargs ): + """ + Initialize the SentinelHashPool connection manager. + + Args: + sentinels: List of Sentinel node addresses (e.g. ['host:port']). + buckets: Dict mapping server keyspace slots/buckets to master group names. + slave_ok: Flag indicating if reading from replica nodes is allowed. + retries: Number of connection retries. + sentinel_password: Password for Sentinel authentication. + sentinel_username: Username for Sentinel ACL authentication. + **kwargs: Additional options forwarded to BasePool. + """ super().__init__(**kwargs) self._sentinel = pyredis.pool.SentinelClient( sentinels=sentinels, @@ -49,14 +61,17 @@ def __init__( @property def slave_ok(self): + """Flag indicating if reading from replica nodes is allowed.""" return self._slave_ok @property def buckets(self): + """Dict mapping server keyspace slots/buckets to master group names.""" return self._buckets @property def retries(self): + """Number of connection retries.""" return self._retries @property