mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-12 10:11:52 +00:00
Make more graceful exceptions
This commit is contained in:
parent
e66194dbf3
commit
06c509cda8
3 changed files with 79 additions and 45 deletions
|
|
@ -1,9 +1,12 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from http import HTTPStatus
|
||||
|
||||
import aiohttp
|
||||
|
||||
from ..exceptions import ValidationError, TelegramAPIError
|
||||
from ..exceptions import ValidationError, TelegramAPIError, BadRequest, Unauthorized, NetworkError, RetryAfter, \
|
||||
MigrateToChat
|
||||
from ..utils import json
|
||||
from ..utils.helper import Helper, HelperMode, Item
|
||||
|
||||
|
|
@ -45,22 +48,34 @@ async def _check_result(method_name, response):
|
|||
:param response: The returned response of the method request
|
||||
:return: The result parsed to a JSON dictionary.
|
||||
"""
|
||||
if response.status != 200:
|
||||
body = await response.text()
|
||||
raise TelegramAPIError("The server returned HTTP {0}. Response body:\n[{1}]".format(
|
||||
response.status, body),
|
||||
method_name, response.status, body)
|
||||
body = await response.text()
|
||||
log.debug(f"Response for {method_name}: {body}")
|
||||
|
||||
result_json = await response.json(loads=json.loads)
|
||||
try:
|
||||
result_json = await response.json(loads=json.loads)
|
||||
except ValueError:
|
||||
result_json = {}
|
||||
|
||||
if not result_json.get('ok'):
|
||||
body = await response.text()
|
||||
code = result_json.get('error_code')
|
||||
description = result_json.get('description')
|
||||
raise TelegramAPIError("Error code: {0} Description {1}".format(code, description),
|
||||
method_name, response.status, body)
|
||||
log.debug("Response for '{0}': {1}".format(method_name, result_json))
|
||||
return result_json.get('result')
|
||||
message = result_json.get('description') or body
|
||||
|
||||
if response.status >= HTTPStatus.INTERNAL_SERVER_ERROR:
|
||||
raise TelegramAPIError(message)
|
||||
|
||||
if 'retry_after' in result_json:
|
||||
raise RetryAfter(result_json['retry_after'])
|
||||
elif 'migrate_to_chat_id' in result_json:
|
||||
raise MigrateToChat(result_json['migrate_to_chat_id'])
|
||||
elif HTTPStatus.OK <= response.status <= HTTPStatus.IM_USED:
|
||||
return result_json.get('result')
|
||||
elif response.status == HTTPStatus.BAD_REQUEST:
|
||||
raise BadRequest(message)
|
||||
elif response.status in [HTTPStatus.UNAUTHORIZED, HTTPStatus.FORBIDDEN]:
|
||||
raise Unauthorized(message)
|
||||
elif response.status == HTTPStatus.REQUEST_ENTITY_TOO_LARGE:
|
||||
raise NetworkError('File too large for uploading. '
|
||||
'Check telegram api limits https://core.telegram.org/bots/api#senddocument')
|
||||
else:
|
||||
raise TelegramAPIError(f"{message} [{response.status}]")
|
||||
|
||||
|
||||
def _guess_filename(obj):
|
||||
|
|
@ -104,7 +119,7 @@ def _compose_data(params=None, files=None):
|
|||
return data
|
||||
|
||||
|
||||
async def request(session, token, method, data=None, files=None, **kwargs) -> bool or dict:
|
||||
async def request(session, token, method, data=None, files=None, continue_retry=False, **kwargs) -> bool or dict:
|
||||
"""
|
||||
Make request to API
|
||||
|
||||
|
|
@ -119,14 +134,23 @@ async def request(session, token, method, data=None, files=None, **kwargs) -> bo
|
|||
:param method: API method
|
||||
:param data: request payload
|
||||
:param files: files
|
||||
:param continue_retry:
|
||||
:return: bool or dict
|
||||
"""
|
||||
log.debug("Make request: '{0}' with data: {1} and files {2}".format(
|
||||
method, data or {}, files or {}))
|
||||
data = _compose_data(data, files)
|
||||
url = Methods.api_url(token=token, method=method)
|
||||
async with session.post(url, data=data, **kwargs) as response:
|
||||
return await _check_result(method, response)
|
||||
try:
|
||||
async with session.post(url, data=data, **kwargs) as response:
|
||||
return await _check_result(method, response)
|
||||
except aiohttp.ClientError as e:
|
||||
raise TelegramAPIError(f"aiohttp client throws an error: {e.__class__.__name__}: {e}")
|
||||
except RetryAfter as e:
|
||||
if continue_retry:
|
||||
await asyncio.sleep(e.timeout)
|
||||
return await request(session, token, method, data, files, **kwargs)
|
||||
raise
|
||||
|
||||
|
||||
class Methods(Helper):
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ class BaseBot:
|
|||
|
||||
def __init__(self, token: String,
|
||||
loop: Optional[Union[asyncio.BaseEventLoop, asyncio.AbstractEventLoop]] = None,
|
||||
connections_limit: Optional[Integer] = 10, proxy=None, proxy_auth=None):
|
||||
connections_limit: Optional[Integer] = 10, proxy=None, proxy_auth=None, continue_retry=False):
|
||||
"""
|
||||
Instructions how to get Bot token is found here: https://core.telegram.org/bots#3-how-do-i-create-a-bot
|
||||
|
||||
|
|
@ -36,6 +36,7 @@ class BaseBot:
|
|||
self.__token = token
|
||||
self.proxy = proxy
|
||||
self.proxy_auth = proxy_auth
|
||||
self.continue_retry = continue_retry
|
||||
|
||||
if loop is None:
|
||||
loop = asyncio.get_event_loop()
|
||||
|
|
@ -98,7 +99,8 @@ class BaseBot:
|
|||
:raise: :class:`aiogram.exceptions.TelegramApiError`
|
||||
"""
|
||||
return await api.request(self.session, self.__token, method, data, files,
|
||||
proxy=self.proxy, proxy_auth=self.proxy_auth)
|
||||
proxy=self.proxy, proxy_auth=self.proxy_auth,
|
||||
continue_retry=self.continue_retry)
|
||||
|
||||
async def download_file(self, file_path: String,
|
||||
destination: Optional[InputFile] = None,
|
||||
|
|
|
|||
|
|
@ -1,30 +1,38 @@
|
|||
from .utils import json
|
||||
|
||||
|
||||
class ValidationError(Exception):
|
||||
pass
|
||||
def _clean_message(text):
|
||||
return text. \
|
||||
lstrip('Error: '). \
|
||||
lstrip('[Error]: '). \
|
||||
lstrip('Bad Request: ')
|
||||
|
||||
|
||||
class TelegramAPIError(Exception):
|
||||
def __init__(self, message, method, status, body):
|
||||
super(TelegramAPIError, self).__init__(
|
||||
"A request to the Telegram API was unsuccessful.\n" + message)
|
||||
self.method = method
|
||||
self.status = status
|
||||
self.body = body
|
||||
def __init__(self, message):
|
||||
super(TelegramAPIError, self).__init__(_clean_message(message))
|
||||
|
||||
def json(self):
|
||||
if not self.body:
|
||||
return None
|
||||
try:
|
||||
data = json.dumps(self.body)
|
||||
except Exception:
|
||||
data = None
|
||||
return data
|
||||
|
||||
@property
|
||||
def parameters(self):
|
||||
from .types import ResponseParameters
|
||||
data = self.json()
|
||||
if data and 'parameters' in data:
|
||||
return ResponseParameters.deserialize(data['parameters'])
|
||||
class ValidationError(TelegramAPIError):
|
||||
pass
|
||||
|
||||
|
||||
class BadRequest(TelegramAPIError):
|
||||
pass
|
||||
|
||||
|
||||
class Unauthorized(TelegramAPIError):
|
||||
pass
|
||||
|
||||
|
||||
class NetworkError(TelegramAPIError):
|
||||
pass
|
||||
|
||||
|
||||
class RetryAfter(TelegramAPIError):
|
||||
def __init__(self, retry_after):
|
||||
super(RetryAfter, self).__init__(f"Flood control exceeded. Retry in {retry_after} seconds")
|
||||
self.timeout = retry_after
|
||||
|
||||
|
||||
class MigrateToChat(TelegramAPIError):
|
||||
def __init__(self, chat_id):
|
||||
super(MigrateToChat, self).__init__(f"The group has been migrated to a supergroup. New id: {chat_id}")
|
||||
self.migrate_to_chat_id = chat_id
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue