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 logging
|
||||||
import os
|
import os
|
||||||
|
from http import HTTPStatus
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from ..exceptions import ValidationError, TelegramAPIError
|
from ..exceptions import ValidationError, TelegramAPIError, BadRequest, Unauthorized, NetworkError, RetryAfter, \
|
||||||
|
MigrateToChat
|
||||||
from ..utils import json
|
from ..utils import json
|
||||||
from ..utils.helper import Helper, HelperMode, Item
|
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
|
:param response: The returned response of the method request
|
||||||
:return: The result parsed to a JSON dictionary.
|
:return: The result parsed to a JSON dictionary.
|
||||||
"""
|
"""
|
||||||
if response.status != 200:
|
body = await response.text()
|
||||||
body = await response.text()
|
log.debug(f"Response for {method_name}: {body}")
|
||||||
raise TelegramAPIError("The server returned HTTP {0}. Response body:\n[{1}]".format(
|
|
||||||
response.status, body),
|
|
||||||
method_name, response.status, 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'):
|
message = result_json.get('description') or body
|
||||||
body = await response.text()
|
|
||||||
code = result_json.get('error_code')
|
if response.status >= HTTPStatus.INTERNAL_SERVER_ERROR:
|
||||||
description = result_json.get('description')
|
raise TelegramAPIError(message)
|
||||||
raise TelegramAPIError("Error code: {0} Description {1}".format(code, description),
|
|
||||||
method_name, response.status, body)
|
if 'retry_after' in result_json:
|
||||||
log.debug("Response for '{0}': {1}".format(method_name, result_json))
|
raise RetryAfter(result_json['retry_after'])
|
||||||
return result_json.get('result')
|
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):
|
def _guess_filename(obj):
|
||||||
|
|
@ -104,7 +119,7 @@ def _compose_data(params=None, files=None):
|
||||||
return data
|
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
|
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 method: API method
|
||||||
:param data: request payload
|
:param data: request payload
|
||||||
:param files: files
|
:param files: files
|
||||||
|
:param continue_retry:
|
||||||
:return: bool or dict
|
:return: bool or dict
|
||||||
"""
|
"""
|
||||||
log.debug("Make request: '{0}' with data: {1} and files {2}".format(
|
log.debug("Make request: '{0}' with data: {1} and files {2}".format(
|
||||||
method, data or {}, files or {}))
|
method, data or {}, files or {}))
|
||||||
data = _compose_data(data, files)
|
data = _compose_data(data, files)
|
||||||
url = Methods.api_url(token=token, method=method)
|
url = Methods.api_url(token=token, method=method)
|
||||||
async with session.post(url, data=data, **kwargs) as response:
|
try:
|
||||||
return await _check_result(method, response)
|
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):
|
class Methods(Helper):
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ class BaseBot:
|
||||||
|
|
||||||
def __init__(self, token: String,
|
def __init__(self, token: String,
|
||||||
loop: Optional[Union[asyncio.BaseEventLoop, asyncio.AbstractEventLoop]] = None,
|
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
|
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.__token = token
|
||||||
self.proxy = proxy
|
self.proxy = proxy
|
||||||
self.proxy_auth = proxy_auth
|
self.proxy_auth = proxy_auth
|
||||||
|
self.continue_retry = continue_retry
|
||||||
|
|
||||||
if loop is None:
|
if loop is None:
|
||||||
loop = asyncio.get_event_loop()
|
loop = asyncio.get_event_loop()
|
||||||
|
|
@ -98,7 +99,8 @@ class BaseBot:
|
||||||
:raise: :class:`aiogram.exceptions.TelegramApiError`
|
:raise: :class:`aiogram.exceptions.TelegramApiError`
|
||||||
"""
|
"""
|
||||||
return await api.request(self.session, self.__token, method, data, files,
|
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,
|
async def download_file(self, file_path: String,
|
||||||
destination: Optional[InputFile] = None,
|
destination: Optional[InputFile] = None,
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,38 @@
|
||||||
from .utils import json
|
def _clean_message(text):
|
||||||
|
return text. \
|
||||||
|
lstrip('Error: '). \
|
||||||
class ValidationError(Exception):
|
lstrip('[Error]: '). \
|
||||||
pass
|
lstrip('Bad Request: ')
|
||||||
|
|
||||||
|
|
||||||
class TelegramAPIError(Exception):
|
class TelegramAPIError(Exception):
|
||||||
def __init__(self, message, method, status, body):
|
def __init__(self, message):
|
||||||
super(TelegramAPIError, self).__init__(
|
super(TelegramAPIError, self).__init__(_clean_message(message))
|
||||||
"A request to the Telegram API was unsuccessful.\n" + message)
|
|
||||||
self.method = method
|
|
||||||
self.status = status
|
|
||||||
self.body = body
|
|
||||||
|
|
||||||
def json(self):
|
|
||||||
if not self.body:
|
|
||||||
return None
|
|
||||||
try:
|
|
||||||
data = json.dumps(self.body)
|
|
||||||
except Exception:
|
|
||||||
data = None
|
|
||||||
return data
|
|
||||||
|
|
||||||
@property
|
class ValidationError(TelegramAPIError):
|
||||||
def parameters(self):
|
pass
|
||||||
from .types import ResponseParameters
|
|
||||||
data = self.json()
|
|
||||||
if data and 'parameters' in data:
|
class BadRequest(TelegramAPIError):
|
||||||
return ResponseParameters.deserialize(data['parameters'])
|
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