1from typing import Optional, Sequence   # noqa
2
3__all__ = [
4    'RedisError',
5    'ProtocolError',
6    'ReplyError',
7    'MaxClientsError',
8    'AuthError',
9    'PipelineError',
10    'MultiExecError',
11    'WatchVariableError',
12    'ChannelClosedError',
13    'ConnectionClosedError',
14    'ConnectionForcedCloseError',
15    'PoolClosedError',
16    'MasterNotFoundError',
17    'SlaveNotFoundError',
18    'ReadOnlyError',
19    ]
20
21
22class RedisError(Exception):
23    """Base exception class for aioredis exceptions."""
24
25
26class ProtocolError(RedisError):
27    """Raised when protocol error occurs."""
28
29
30class ReplyError(RedisError):
31    """Raised for redis error replies (-ERR)."""
32
33    MATCH_REPLY = None  # type: Optional[Sequence[str]]
34
35    def __new__(cls, msg, *args):
36        for klass in cls.__subclasses__():
37            if msg and klass.MATCH_REPLY and msg.startswith(klass.MATCH_REPLY):
38                return klass(msg, *args)
39        return super().__new__(cls, msg, *args)
40
41
42class MaxClientsError(ReplyError):
43    """Raised for redis server when the maximum number of client has been
44    reached."""
45
46    MATCH_REPLY = "ERR max number of clients reached"
47
48
49class AuthError(ReplyError):
50    """Raised when authentication errors occurs."""
51
52    MATCH_REPLY = (
53        "NOAUTH ",
54        "ERR invalid password",
55        "ERR Client sent AUTH, but no password is set",
56    )
57
58
59class BusyGroupError(ReplyError):
60    """Raised if Consumer Group name already exists."""
61
62    MATCH_REPLY = "BUSYGROUP Consumer Group name already exists"
63
64
65class PipelineError(RedisError):
66    """Raised if command within pipeline raised error."""
67
68    def __init__(self, errors):
69        super().__init__('{} errors:'.format(self.__class__.__name__), errors)
70
71
72class MultiExecError(PipelineError):
73    """Raised if command within MULTI/EXEC block caused error."""
74
75
76class WatchVariableError(MultiExecError):
77    """Raised if watched variable changed (EXEC returns None)."""
78
79
80class ChannelClosedError(RedisError):
81    """Raised when Pub/Sub channel is unsubscribed and messages queue is empty.
82    """
83
84
85class ReadOnlyError(RedisError):
86    """Raised from slave when read-only mode is enabled"""
87
88
89class MasterNotFoundError(RedisError):
90    """Raised for sentinel master not found error."""
91
92
93class SlaveNotFoundError(RedisError):
94    """Raised for sentinel slave not found error."""
95
96
97class MasterReplyError(RedisError):
98    """Raised by sentinel client for master error replies."""
99
100
101class SlaveReplyError(RedisError):
102    """Raised by sentinel client for slave error replies."""
103
104
105class ConnectionClosedError(RedisError):
106    """Raised if connection to server was closed."""
107
108
109class ConnectionForcedCloseError(ConnectionClosedError):
110    """Raised if connection was closed with .close() method."""
111
112
113class PoolClosedError(RedisError):
114    """Raised if pool is closed."""
115