aboutsummaryrefslogtreecommitdiff
path: root/discord
diff options
context:
space:
mode:
Diffstat (limited to 'discord')
-rw-r--r--discord/errors.py90
1 files changed, 67 insertions, 23 deletions
diff --git a/discord/errors.py b/discord/errors.py
index ca953848..398cdc55 100644
--- a/discord/errors.py
+++ b/discord/errors.py
@@ -22,6 +22,21 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
+from __future__ import annotations
+from typing import Dict, List, Optional, TYPE_CHECKING, Any, Tuple, Union
+
+if TYPE_CHECKING:
+ from aiohttp import ClientResponse, ClientWebSocketResponse
+
+ try:
+ from requests import Response
+
+ ResponseType = Union[ClientResponse, Response]
+ except ModuleNotFoundError:
+ ResponseType = ClientResponse
+
+ from .interactions import Interaction
+
__all__ = (
'DiscordException',
'ClientException',
@@ -39,41 +54,49 @@ __all__ = (
'InteractionResponded',
)
+
class DiscordException(Exception):
"""Base exception class for discord.py
Ideally speaking, this could be caught to handle any exceptions raised from this library.
"""
+
pass
+
class ClientException(DiscordException):
"""Exception that's raised when an operation in the :class:`Client` fails.
These are usually for exceptions that happened due to user input.
"""
+
pass
+
class NoMoreItems(DiscordException):
- """Exception that is raised when an async iteration operation has no more
- items."""
+ """Exception that is raised when an async iteration operation has no more items."""
+
pass
+
class GatewayNotFound(DiscordException):
"""An exception that is raised when the gateway for Discord could not be found"""
+
def __init__(self):
message = 'The gateway to connect to discord was not found.'
super().__init__(message)
-def flatten_error_dict(d, key=''):
- items = []
+
+def _flatten_error_dict(d: Dict[str, Any], key: str = '') -> Dict[str, str]:
+ items: List[Tuple[str, str]] = []
for k, v in d.items():
new_key = key + '.' + k if key else k
if isinstance(v, dict):
try:
- _errors = v['_errors']
+ _errors: List[Dict[str, Any]] = v['_errors']
except KeyError:
- items.extend(flatten_error_dict(v, new_key).items())
+ items.extend(_flatten_error_dict(v, new_key).items())
else:
items.append((new_key, ' '.join(x.get('message', '') for x in _errors)))
else:
@@ -81,6 +104,7 @@ def flatten_error_dict(d, key=''):
return dict(items)
+
class HTTPException(DiscordException):
"""Exception that's raised when an HTTP request operation fails.
@@ -99,21 +123,23 @@ class HTTPException(DiscordException):
The Discord specific error code for the failure.
"""
- def __init__(self, response, message):
- self.response = response
- self.status = response.status
+ def __init__(self, response: ResponseType, message: Optional[Union[str, Dict[str, Any]]]):
+ self.response: ResponseType = response
+ self.status: int = response.status # type: ignore
+ self.code: int
+ self.text: str
if isinstance(message, dict):
self.code = message.get('code', 0)
base = message.get('message', '')
errors = message.get('errors')
if errors:
- errors = flatten_error_dict(errors)
+ errors = _flatten_error_dict(errors)
helpful = '\n'.join('In %s: %s' % t for t in errors.items())
self.text = base + '\n' + helpful
else:
self.text = base
else:
- self.text = message
+ self.text = message or ''
self.code = 0
fmt = '{0.status} {0.reason} (error code: {1})'
@@ -122,20 +148,25 @@ class HTTPException(DiscordException):
super().__init__(fmt.format(self.response, self.code, self.text))
+
class Forbidden(HTTPException):
"""Exception that's raised for when status code 403 occurs.
Subclass of :exc:`HTTPException`
"""
+
pass
+
class NotFound(HTTPException):
"""Exception that's raised for when status code 404 occurs.
Subclass of :exc:`HTTPException`
"""
+
pass
+
class DiscordServerError(HTTPException):
"""Exception that's raised for when a 500 range status code occurs.
@@ -143,14 +174,18 @@ class DiscordServerError(HTTPException):
.. versionadded:: 1.5
"""
+
pass
+
class InvalidData(ClientException):
"""Exception that's raised when the library encounters unknown
or invalid data from Discord.
"""
+
pass
+
class InvalidArgument(ClientException):
"""Exception that's raised when an argument to a function
is invalid some way (e.g. wrong value or wrong type).
@@ -159,15 +194,19 @@ class InvalidArgument(ClientException):
``TypeError`` except inherited from :exc:`ClientException` and thus
:exc:`DiscordException`.
"""
+
pass
+
class LoginFailure(ClientException):
"""Exception that's raised when the :meth:`Client.login` function
fails to log you in from improper credentials or some other misc.
failure.
"""
+
pass
+
class ConnectionClosed(ClientException):
"""Exception that's raised when the gateway connection is
closed for reasons that could not be handled internally.
@@ -181,15 +220,17 @@ class ConnectionClosed(ClientException):
shard_id: Optional[:class:`int`]
The shard ID that got closed if applicable.
"""
- def __init__(self, socket, *, shard_id, code=None):
+
+ def __init__(self, socket: ClientWebSocketResponse, *, shard_id: Optional[int], code: Optional[int] = None):
# This exception is just the same exception except
# reconfigured to subclass ClientException for users
- self.code = code or socket.close_code
+ self.code: int = code or socket.close_code or -1
# aiohttp doesn't seem to consistently provide close reason
- self.reason = ''
- self.shard_id = shard_id
+ self.reason: str = ''
+ self.shard_id: Optional[int] = shard_id
super().__init__(f'Shard ID {self.shard_id} WebSocket closed with {self.code}')
+
class PrivilegedIntentsRequired(ClientException):
"""Exception that's raised when the gateway is requesting privileged intents
but they're not ticked in the developer page yet.
@@ -206,14 +247,17 @@ class PrivilegedIntentsRequired(ClientException):
The shard ID that got closed if applicable.
"""
- def __init__(self, shard_id):
- self.shard_id = shard_id
- msg = 'Shard ID %s is requesting privileged intents that have not been explicitly enabled in the ' \
- 'developer portal. It is recommended to go to https://discord.com/developers/applications/ ' \
- 'and explicitly enable the privileged intents within your application\'s page. If this is not ' \
- 'possible, then consider disabling the privileged intents instead.'
+ def __init__(self, shard_id: Optional[int]):
+ self.shard_id: Optional[int] = shard_id
+ msg = (
+ 'Shard ID %s is requesting privileged intents that have not been explicitly enabled in the '
+ 'developer portal. It is recommended to go to https://discord.com/developers/applications/ '
+ 'and explicitly enable the privileged intents within your application\'s page. If this is not '
+ 'possible, then consider disabling the privileged intents instead.'
+ )
super().__init__(msg % shard_id)
+
class InteractionResponded(ClientException):
"""Exception that's raised when sending another interaction response using
:class:`InteractionResponse` when one has already been done before.
@@ -228,6 +272,6 @@ class InteractionResponded(ClientException):
The interaction that's already been responded to.
"""
- def __init__(self, interaction):
- self.interaction = interaction
+ def __init__(self, interaction: Interaction):
+ self.interaction: Interaction = interaction
super().__init__('This interaction has already been responded to before')