Disable old API exceptions

This commit is contained in:
jrootjunior 2019-12-11 15:25:28 +02:00
parent 1723a83697
commit 2451b88ff5
2 changed files with 474 additions and 475 deletions

View file

@ -82,484 +82,482 @@
- AIOGramWarning
- TimeoutWarning
"""
import time
# TODO: Use exceptions detector from `aiograph`.
# TODO: aiogram.utils.exceptions.BadRequest: Bad request: can't parse entities: unsupported start tag "function" at byte offset 0
# TODO: aiogram.utils.exceptions.TelegramAPIError: Gateway Timeout
_PREFIXES = ["error: ", "[error]: ", "bad request: ", "conflict: ", "not found: "]
def _clean_message(text):
for prefix in _PREFIXES:
if text.startswith(prefix):
text = text[len(prefix) :]
return (text[0].upper() + text[1:]).strip()
class TelegramAPIError(Exception):
def __init__(self, message=None):
super(TelegramAPIError, self).__init__(_clean_message(message))
class _MatchErrorMixin:
match = ""
text = None
__subclasses = []
def __init_subclass__(cls, **kwargs):
super(_MatchErrorMixin, cls).__init_subclass__(**kwargs)
# cls.match = cls.match.lower() if cls.match else ''
if not hasattr(cls, f"_{cls.__name__}__group"):
cls.__subclasses.append(cls)
@classmethod
def check(cls, message) -> bool:
"""
Compare pattern with message
:param message: always must be in lowercase
:return: bool
"""
return cls.match.lower() in message
@classmethod
def detect(cls, description):
description = description.lower()
for err in cls.__subclasses:
if err is cls:
continue
if err.check(description):
raise err(cls.text or description)
raise cls(description)
class AIOGramWarning(Warning):
pass
class TimeoutWarning(AIOGramWarning):
pass
class FSMStorageWarning(AIOGramWarning):
pass
class ValidationError(TelegramAPIError):
pass
class BadRequest(TelegramAPIError, _MatchErrorMixin):
__group = True
class MessageError(BadRequest):
__group = True
class MessageNotModified(MessageError):
"""
Will be raised when you try to set new text is equals to current text.
"""
match = "message is not modified"
class MessageToForwardNotFound(MessageError):
"""
Will be raised when you try to forward very old or deleted or unknown message.
"""
match = "message to forward not found"
class MessageToDeleteNotFound(MessageError):
"""
Will be raised when you try to delete very old or deleted or unknown message.
"""
match = "message to delete not found"
class MessageToReplyNotFound(MessageError):
"""
Will be raised when you try to reply to very old or deleted or unknown message.
"""
match = "message to reply not found"
class MessageIdentifierNotSpecified(MessageError):
match = "message identifier is not specified"
class MessageTextIsEmpty(MessageError):
match = "Message text is empty"
class MessageCantBeEdited(MessageError):
match = "message can't be edited"
class MessageCantBeDeleted(MessageError):
match = "message can't be deleted"
class MessageToEditNotFound(MessageError):
match = "message to edit not found"
class MessageIsTooLong(MessageError):
match = "message is too long"
class ToMuchMessages(MessageError):
"""
Will be raised when you try to send media group with more than 10 items.
"""
match = "Too much messages to send as an album"
class ObjectExpectedAsReplyMarkup(BadRequest):
match = "object expected as reply markup"
class InlineKeyboardExpected(BadRequest):
match = "inline keyboard expected"
class PollError(BadRequest):
__group = True
class PollCantBeStopped(PollError):
match = "poll can't be stopped"
class PollHasAlreadyBeenClosed(PollError):
match = "poll has already been closed"
class PollsCantBeSentToPrivateChats(PollError):
match = "polls can't be sent to private chats"
class PollSizeError(PollError):
__group = True
class PollMustHaveMoreOptions(PollSizeError):
match = "poll must have at least 2 option"
class PollCantHaveMoreOptions(PollSizeError):
match = "poll can't have more than 10 options"
class PollOptionsMustBeNonEmpty(PollSizeError):
match = "poll options must be non-empty"
class PollQuestionMustBeNonEmpty(PollSizeError):
match = "poll question must be non-empty"
class PollOptionsLengthTooLong(PollSizeError):
match = "poll options length must not exceed 100"
class PollQuestionLengthTooLong(PollSizeError):
match = "poll question length must not exceed 255"
class MessageWithPollNotFound(PollError, MessageError):
"""
Will be raised when you try to stop poll with message without poll
"""
match = "message with poll to stop not found"
class MessageIsNotAPoll(PollError, MessageError):
"""
Will be raised when you try to stop poll with message without poll
"""
match = "message is not a poll"
class ChatNotFound(BadRequest):
match = "chat not found"
class ChatIdIsEmpty(BadRequest):
match = "chat_id is empty"
class InvalidUserId(BadRequest):
match = "user_id_invalid"
text = "Invalid user id"
class ChatDescriptionIsNotModified(BadRequest):
match = "chat description is not modified"
class InvalidQueryID(BadRequest):
match = "query is too old and response timeout expired or query id is invalid"
class InvalidPeerID(BadRequest):
match = "PEER_ID_INVALID"
text = "Invalid peer ID"
class InvalidHTTPUrlContent(BadRequest):
match = "Failed to get HTTP URL content"
class ButtonURLInvalid(BadRequest):
match = "BUTTON_URL_INVALID"
text = "Button URL invalid"
class URLHostIsEmpty(BadRequest):
match = "URL host is empty"
class StartParamInvalid(BadRequest):
match = "START_PARAM_INVALID"
text = "Start param invalid"
class ButtonDataInvalid(BadRequest):
match = "BUTTON_DATA_INVALID"
text = "Button data invalid"
class WrongFileIdentifier(BadRequest):
match = "wrong file identifier/HTTP URL specified"
class GroupDeactivated(BadRequest):
match = "group is deactivated"
class PhotoAsInputFileRequired(BadRequest):
"""
Will be raised when you try to set chat photo from file ID.
"""
match = "Photo should be uploaded as an InputFile"
class InvalidStickersSet(BadRequest):
match = "STICKERSET_INVALID"
text = "Stickers set is invalid"
class NoStickerInRequest(BadRequest):
match = "there is no sticker in the request"
class ChatAdminRequired(BadRequest):
match = "CHAT_ADMIN_REQUIRED"
text = "Admin permissions is required!"
class NeedAdministratorRightsInTheChannel(BadRequest):
match = "need administrator rights in the channel chat"
text = "Admin permissions is required!"
class NotEnoughRightsToPinMessage(BadRequest):
match = "not enough rights to pin a message"
class MethodNotAvailableInPrivateChats(BadRequest):
match = "method is available only for supergroups and channel"
class CantDemoteChatCreator(BadRequest):
match = "can't demote chat creator"
class CantRestrictSelf(BadRequest):
match = "can't restrict self"
text = "Admin can't restrict self."
class NotEnoughRightsToRestrict(BadRequest):
match = "not enough rights to restrict/unrestrict chat member"
class PhotoDimensions(BadRequest):
match = "PHOTO_INVALID_DIMENSIONS"
text = "Invalid photo dimensions"
class UnavailableMembers(BadRequest):
match = "supergroup members are unavailable"
class TypeOfFileMismatch(BadRequest):
match = "type of file mismatch"
class WrongRemoteFileIdSpecified(BadRequest):
match = "wrong remote file id specified"
class PaymentProviderInvalid(BadRequest):
match = "PAYMENT_PROVIDER_INVALID"
text = "payment provider invalid"
class CurrencyTotalAmountInvalid(BadRequest):
match = "currency_total_amount_invalid"
text = "currency total amount invalid"
class BadWebhook(BadRequest):
__group = True
class WebhookRequireHTTPS(BadWebhook):
match = "HTTPS url must be provided for webhook"
text = "bad webhook: " + match
class BadWebhookPort(BadWebhook):
match = "Webhook can be set up only on ports 80, 88, 443 or 8443"
text = "bad webhook: " + match
class BadWebhookAddrInfo(BadWebhook):
match = "getaddrinfo: Temporary failure in name resolution"
text = "bad webhook: " + match
class BadWebhookNoAddressAssociatedWithHostname(BadWebhook):
match = "failed to resolve host: no address associated with hostname"
class CantParseUrl(BadRequest):
match = "can't parse URL"
class UnsupportedUrlProtocol(BadRequest):
match = "unsupported URL protocol"
class CantParseEntities(BadRequest):
match = "can't parse entities"
class ResultIdDuplicate(BadRequest):
match = "result_id_duplicate"
text = "Result ID duplicate"
class BotDomainInvalid(BadRequest):
match = "bot_domain_invalid"
text = "Invalid bot domain"
class NotFound(TelegramAPIError, _MatchErrorMixin):
__group = True
class MethodNotKnown(NotFound):
match = "method not found"
class ConflictError(TelegramAPIError, _MatchErrorMixin):
__group = True
class TerminatedByOtherGetUpdates(ConflictError):
match = "terminated by other getUpdates request"
text = (
"Terminated by other getUpdates request; "
"Make sure that only one bot instance is running"
)
class CantGetUpdates(ConflictError):
match = "can't use getUpdates method while webhook is active"
class Unauthorized(TelegramAPIError, _MatchErrorMixin):
__group = True
class BotKicked(Unauthorized):
match = "bot was kicked from a chat"
class BotBlocked(Unauthorized):
match = "bot was blocked by the user"
class UserDeactivated(Unauthorized):
match = "user is deactivated"
class CantInitiateConversation(Unauthorized):
match = "bot can't initiate conversation with a user"
class CantTalkWithBots(Unauthorized):
match = "bot can't send messages to bots"
class NetworkError(TelegramAPIError):
pass
class RestartingTelegram(TelegramAPIError):
def __init__(self):
super(RestartingTelegram, self).__init__(
"The Telegram Bot API service is restarting. Wait few second."
)
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
class Throttled(TelegramAPIError):
def __init__(self, **kwargs):
from ..dispatcher.storage import DELTA, EXCEEDED_COUNT, KEY, LAST_CALL, RATE_LIMIT, RESULT
self.key = kwargs.pop(KEY, "<None>")
self.called_at = kwargs.pop(LAST_CALL, time.time())
self.rate = kwargs.pop(RATE_LIMIT, None)
self.result = kwargs.pop(RESULT, False)
self.exceeded_count = kwargs.pop(EXCEEDED_COUNT, 0)
self.delta = kwargs.pop(DELTA, 0)
self.user = kwargs.pop("user", None)
self.chat = kwargs.pop("chat", None)
def __str__(self):
return (
f"Rate limit exceeded! (Limit: {self.rate} s, "
f"exceeded: {self.exceeded_count}, "
f"time delta: {round(self.delta, 3)} s)"
)
# _PREFIXES = ["error: ", "[error]: ", "bad request: ", "conflict: ", "not found: "]
#
# def _clean_message(text):
# for prefix in _PREFIXES:
# if text.startswith(prefix):
# text = text[len(prefix) :]
# return (text[0].upper() + text[1:]).strip()
#
#
#
# class _MatchErrorMixin:
# match = ""
# text = None
#
# __subclasses = []
#
# def __init_subclass__(cls, **kwargs):
# super(_MatchErrorMixin, cls).__init_subclass__(**kwargs)
# # cls.match = cls.match.lower() if cls.match else ''
# if not hasattr(cls, f"_{cls.__name__}__group"):
# cls.__subclasses.append(cls)
#
# @classmethod
# def check(cls, message) -> bool:
# """
# Compare pattern with message
#
# :param message: always must be in lowercase
# :return: bool
# """
# return cls.match.lower() in message
#
# @classmethod
# def detect(cls, description):
# description = description.lower()
# for err in cls.__subclasses:
# if err is cls:
# continue
# if err.check(description):
# raise err(cls.text or description)
# raise cls(description)
#
#
# class AIOGramWarning(Warning):
# pass
#
#
# class TimeoutWarning(AIOGramWarning):
# pass
#
#
# class FSMStorageWarning(AIOGramWarning):
# pass
#
#
# class ValidationError(TelegramAPIError):
# pass
#
#
# class BadRequest(TelegramAPIError, _MatchErrorMixin):
# __group = True
#
#
# class MessageError(BadRequest):
# __group = True
#
#
# class MessageNotModified(MessageError):
# """
# Will be raised when you try to set new text is equals to current text.
# """
#
# match = "message is not modified"
#
#
# class MessageToForwardNotFound(MessageError):
# """
# Will be raised when you try to forward very old or deleted or unknown message.
# """
#
# match = "message to forward not found"
#
#
# class MessageToDeleteNotFound(MessageError):
# """
# Will be raised when you try to delete very old or deleted or unknown message.
# """
#
# match = "message to delete not found"
#
#
# class MessageToReplyNotFound(MessageError):
# """
# Will be raised when you try to reply to very old or deleted or unknown message.
# """
#
# match = "message to reply not found"
#
#
# class MessageIdentifierNotSpecified(MessageError):
# match = "message identifier is not specified"
#
#
# class MessageTextIsEmpty(MessageError):
# match = "Message text is empty"
#
#
# class MessageCantBeEdited(MessageError):
# match = "message can't be edited"
#
#
# class MessageCantBeDeleted(MessageError):
# match = "message can't be deleted"
#
#
# class MessageToEditNotFound(MessageError):
# match = "message to edit not found"
#
#
# class MessageIsTooLong(MessageError):
# match = "message is too long"
#
#
# class ToMuchMessages(MessageError):
# """
# Will be raised when you try to send media group with more than 10 items.
# """
#
# match = "Too much messages to send as an album"
#
#
# class ObjectExpectedAsReplyMarkup(BadRequest):
# match = "object expected as reply markup"
#
#
# class InlineKeyboardExpected(BadRequest):
# match = "inline keyboard expected"
#
#
# class PollError(BadRequest):
# __group = True
#
#
# class PollCantBeStopped(PollError):
# match = "poll can't be stopped"
#
#
# class PollHasAlreadyBeenClosed(PollError):
# match = "poll has already been closed"
#
#
# class PollsCantBeSentToPrivateChats(PollError):
# match = "polls can't be sent to private chats"
#
#
# class PollSizeError(PollError):
# __group = True
#
#
# class PollMustHaveMoreOptions(PollSizeError):
# match = "poll must have at least 2 option"
#
#
# class PollCantHaveMoreOptions(PollSizeError):
# match = "poll can't have more than 10 options"
#
#
# class PollOptionsMustBeNonEmpty(PollSizeError):
# match = "poll options must be non-empty"
#
#
# class PollQuestionMustBeNonEmpty(PollSizeError):
# match = "poll question must be non-empty"
#
#
# class PollOptionsLengthTooLong(PollSizeError):
# match = "poll options length must not exceed 100"
#
#
# class PollQuestionLengthTooLong(PollSizeError):
# match = "poll question length must not exceed 255"
#
#
# class MessageWithPollNotFound(PollError, MessageError):
# """
# Will be raised when you try to stop poll with message without poll
# """
#
# match = "message with poll to stop not found"
#
#
# class MessageIsNotAPoll(PollError, MessageError):
# """
# Will be raised when you try to stop poll with message without poll
# """
#
# match = "message is not a poll"
#
#
# class ChatNotFound(BadRequest):
# match = "chat not found"
#
#
# class ChatIdIsEmpty(BadRequest):
# match = "chat_id is empty"
#
#
# class InvalidUserId(BadRequest):
# match = "user_id_invalid"
# text = "Invalid user id"
#
#
# class ChatDescriptionIsNotModified(BadRequest):
# match = "chat description is not modified"
#
#
# class InvalidQueryID(BadRequest):
# match = "query is too old and response timeout expired or query id is invalid"
#
#
# class InvalidPeerID(BadRequest):
# match = "PEER_ID_INVALID"
# text = "Invalid peer ID"
#
#
# class InvalidHTTPUrlContent(BadRequest):
# match = "Failed to get HTTP URL content"
#
#
# class ButtonURLInvalid(BadRequest):
# match = "BUTTON_URL_INVALID"
# text = "Button URL invalid"
#
#
# class URLHostIsEmpty(BadRequest):
# match = "URL host is empty"
#
#
# class StartParamInvalid(BadRequest):
# match = "START_PARAM_INVALID"
# text = "Start param invalid"
#
#
# class ButtonDataInvalid(BadRequest):
# match = "BUTTON_DATA_INVALID"
# text = "Button data invalid"
#
#
# class WrongFileIdentifier(BadRequest):
# match = "wrong file identifier/HTTP URL specified"
#
#
# class GroupDeactivated(BadRequest):
# match = "group is deactivated"
#
#
# class PhotoAsInputFileRequired(BadRequest):
# """
# Will be raised when you try to set chat photo from file ID.
# """
#
# match = "Photo should be uploaded as an InputFile"
#
#
# class InvalidStickersSet(BadRequest):
# match = "STICKERSET_INVALID"
# text = "Stickers set is invalid"
#
#
# class NoStickerInRequest(BadRequest):
# match = "there is no sticker in the request"
#
#
# class ChatAdminRequired(BadRequest):
# match = "CHAT_ADMIN_REQUIRED"
# text = "Admin permissions is required!"
#
#
# class NeedAdministratorRightsInTheChannel(BadRequest):
# match = "need administrator rights in the channel chat"
# text = "Admin permissions is required!"
#
#
# class NotEnoughRightsToPinMessage(BadRequest):
# match = "not enough rights to pin a message"
#
#
# class MethodNotAvailableInPrivateChats(BadRequest):
# match = "method is available only for supergroups and channel"
#
#
# class CantDemoteChatCreator(BadRequest):
# match = "can't demote chat creator"
#
#
# class CantRestrictSelf(BadRequest):
# match = "can't restrict self"
# text = "Admin can't restrict self."
#
#
# class NotEnoughRightsToRestrict(BadRequest):
# match = "not enough rights to restrict/unrestrict chat member"
#
#
# class PhotoDimensions(BadRequest):
# match = "PHOTO_INVALID_DIMENSIONS"
# text = "Invalid photo dimensions"
#
#
# class UnavailableMembers(BadRequest):
# match = "supergroup members are unavailable"
#
#
# class TypeOfFileMismatch(BadRequest):
# match = "type of file mismatch"
#
#
# class WrongRemoteFileIdSpecified(BadRequest):
# match = "wrong remote file id specified"
#
#
# class PaymentProviderInvalid(BadRequest):
# match = "PAYMENT_PROVIDER_INVALID"
# text = "payment provider invalid"
#
#
# class CurrencyTotalAmountInvalid(BadRequest):
# match = "currency_total_amount_invalid"
# text = "currency total amount invalid"
#
#
# class BadWebhook(BadRequest):
# __group = True
#
#
# class WebhookRequireHTTPS(BadWebhook):
# match = "HTTPS url must be provided for webhook"
# text = "bad webhook: " + match
#
#
# class BadWebhookPort(BadWebhook):
# match = "Webhook can be set up only on ports 80, 88, 443 or 8443"
# text = "bad webhook: " + match
#
#
# class BadWebhookAddrInfo(BadWebhook):
# match = "getaddrinfo: Temporary failure in name resolution"
# text = "bad webhook: " + match
#
#
# class BadWebhookNoAddressAssociatedWithHostname(BadWebhook):
# match = "failed to resolve host: no address associated with hostname"
#
#
# class CantParseUrl(BadRequest):
# match = "can't parse URL"
#
#
# class UnsupportedUrlProtocol(BadRequest):
# match = "unsupported URL protocol"
#
#
# class CantParseEntities(BadRequest):
# match = "can't parse entities"
#
#
# class ResultIdDuplicate(BadRequest):
# match = "result_id_duplicate"
# text = "Result ID duplicate"
#
#
# class BotDomainInvalid(BadRequest):
# match = "bot_domain_invalid"
# text = "Invalid bot domain"
#
#
# class NotFound(TelegramAPIError, _MatchErrorMixin):
# __group = True
#
#
# class MethodNotKnown(NotFound):
# match = "method not found"
#
#
# class ConflictError(TelegramAPIError, _MatchErrorMixin):
# __group = True
#
#
# class TerminatedByOtherGetUpdates(ConflictError):
# match = "terminated by other getUpdates request"
# text = (
# "Terminated by other getUpdates request; "
# "Make sure that only one bot instance is running"
# )
#
#
# class CantGetUpdates(ConflictError):
# match = "can't use getUpdates method while webhook is active"
#
#
# class Unauthorized(TelegramAPIError, _MatchErrorMixin):
# __group = True
#
#
# class BotKicked(Unauthorized):
# match = "bot was kicked from a chat"
#
#
# class BotBlocked(Unauthorized):
# match = "bot was blocked by the user"
#
#
# class UserDeactivated(Unauthorized):
# match = "user is deactivated"
#
#
# class CantInitiateConversation(Unauthorized):
# match = "bot can't initiate conversation with a user"
#
#
# class CantTalkWithBots(Unauthorized):
# match = "bot can't send messages to bots"
#
#
# class NetworkError(TelegramAPIError):
# pass
#
#
# class RestartingTelegram(TelegramAPIError):
# def __init__(self):
# super(RestartingTelegram, self).__init__(
# "The Telegram Bot API service is restarting. Wait few second."
# )
#
#
# 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
#
#
# class Throttled(TelegramAPIError):
# def __init__(self, **kwargs):
# from ..dispatcher.storage import DELTA, EXCEEDED_COUNT, KEY, LAST_CALL, RATE_LIMIT, RESULT
#
# self.key = kwargs.pop(KEY, "<None>")
# self.called_at = kwargs.pop(LAST_CALL, time.time())
# self.rate = kwargs.pop(RATE_LIMIT, None)
# self.result = kwargs.pop(RESULT, False)
# self.exceeded_count = kwargs.pop(EXCEEDED_COUNT, 0)
# self.delta = kwargs.pop(DELTA, 0)
# self.user = kwargs.pop("user", None)
# self.chat = kwargs.pop("chat", None)
#
# def __str__(self):
# return (
# f"Rate limit exceeded! (Limit: {self.rate} s, "
# f"exceeded: {self.exceeded_count}, "
# f"time delta: {round(self.delta, 3)} s)"
# )

View file

@ -92,6 +92,7 @@ class TestDispatcher:
index += 1
if index == 42:
break
assert index == 42
@pytest.mark.asyncio
async def test_silent_call_request(self, bot: MockedBot, caplog):