aiogram/aiogram/exceptions.py
Alex Root Junior 3d63bf3b99
PoC Scenes (#1280)
* Base implementation

* Small refactoring + added possibility to specify post-action on handlers

* Move scene properties to config object

* Revise aiogram/scenes with wizard-based design pattern

Modified files in aiogram/scenes to incorporate the Wizard design pattern. Files affected are _marker.py, _registry.py, _wizard.py and __init__.py. The changes introduced a SceneWizard Class and ScenesManager, both of which aid in controlling navigation between different scenes or states. This helps clarifying the codebase, streamline scene transitions and offer more control over the app flow.

* Added example

* Small optimizations

* Replace ValueError with SceneException in scenes. Added error safety in scene resolver.

* str

* Added possibility to reset context on scene entered and to handle callback query in any state

* Remove inline markup in example

* Small changes

* Docs + example

* Small refactoring

* Remove scene inclusion methods from router

The methods for including scenes as sub-routers have been removed from the router.py file. Instead, the SceneRegistry class is now set to register scenes by default upon initializing. This streamlines the scene management process by removing redundant routers and making registration automatic.

* Init tests

* Small fix in tests

* Add support for State instance in the scene

The aiogram FSM scene now allows the use of State instance as an argument, enabling more customization. Modified the 'as_handler' method to receive **kwargs arguments, allowing passing of attributes to the handler. An additional type check has been also added to ensure the 'scene' is either a subclass of Scene or a string.

* Fixed test

* Expand test coverage for test_fsm module

The commit enhances tests for the test_fsm module to improve code reliability. It includes additional unit tests for the ObserverDecorator and ActionContainer classes and introduces new tests for the SceneHandlerWrapper class. This ensures the correct functionality of the decorator methods, the action container execution, and the handler wrapper.

* Reformat code

* Fixed long line in the example

* Skip some tests on PyPy

* Change mock return_value

* Compatibility...

* Compatibility...

* Compatibility...

* Added base changes description

* Scenes Tests (#1369)

* ADD tests for `SceneRegistry`

* ADD tests for `ScenesManager`

* ADD Changelog

* Revert "ADD Changelog"

This reverts commit 6dd9301252.

* Remove `@pytest.mark.asyncio`, Reformat code

* Scenes Tests. Part 2 (#1371)

* ADD tests for `SceneWizard`

* ADD tests for `Scene`

* Refactor ObserverDecorator to use on.message syntax in test_scene.py
Cover `Scene::__init_subclass__::if isinstance(value, ObserverDecorator):`

* Refactor `HistoryManager` in `aiogram/fsm/scene.py`
Removed condition that checked if 'history' is empty before calling 'update_data' in 'Scene'.

* ADD tests for `HistoryManager`

* Small changes in the documentation

* Small changes in the documentation

* Small changes in the documentation

---------

Co-authored-by: Andrew <11490628+andrew000@users.noreply.github.com>
2023-11-23 00:41:21 +02:00

199 lines
5 KiB
Python

from typing import Any, Optional
from aiogram.methods import TelegramMethod
from aiogram.methods.base import TelegramType
from aiogram.utils.link import docs_url
class AiogramError(Exception):
"""
Base exception for all aiogram errors.
"""
class DetailedAiogramError(AiogramError):
"""
Base exception for all aiogram errors with detailed message.
"""
url: Optional[str] = None
def __init__(self, message: str) -> None:
self.message = message
def __str__(self) -> str:
message = self.message
if self.url:
message += f"\n(background on this error at: {self.url})"
return message
def __repr__(self) -> str:
return f"{type(self).__name__}('{self}')"
class CallbackAnswerException(AiogramError):
"""
Exception for callback answer.
"""
class SceneException(AiogramError):
"""
Exception for scenes.
"""
class UnsupportedKeywordArgument(DetailedAiogramError):
"""
Exception raised when a keyword argument is passed as filter.
"""
url = docs_url("migration_2_to_3.html", fragment_="filtering-events")
class TelegramAPIError(DetailedAiogramError):
"""
Base exception for all Telegram API errors.
"""
label: str = "Telegram server says"
def __init__(
self,
method: TelegramMethod[TelegramType],
message: str,
) -> None:
super().__init__(message=message)
self.method = method
def __str__(self) -> str:
original_message = super().__str__()
return f"{self.label} - {original_message}"
class TelegramNetworkError(TelegramAPIError):
"""
Base exception for all Telegram network errors.
"""
label = "HTTP Client says"
class TelegramRetryAfter(TelegramAPIError):
"""
Exception raised when flood control exceeds.
"""
url = "https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this"
def __init__(
self,
method: TelegramMethod[TelegramType],
message: str,
retry_after: int,
) -> None:
description = f"Flood control exceeded on method {type(method).__name__!r}"
if chat_id := getattr(method, "chat_id", None):
description += f" in chat {chat_id}"
description += f". Retry in {retry_after} seconds."
description += f"\nOriginal description: {message}"
super().__init__(method=method, message=description)
self.retry_after = retry_after
class TelegramMigrateToChat(TelegramAPIError):
"""
Exception raised when chat has been migrated to a supergroup.
"""
url = "https://core.telegram.org/bots/api#responseparameters"
def __init__(
self,
method: TelegramMethod[TelegramType],
message: str,
migrate_to_chat_id: int,
) -> None:
description = f"The group has been migrated to a supergroup with id {migrate_to_chat_id}"
if chat_id := getattr(method, "chat_id", None):
description += f" from {chat_id}"
description += f"\nOriginal description: {message}"
super().__init__(method=method, message=message)
self.migrate_to_chat_id = migrate_to_chat_id
class TelegramBadRequest(TelegramAPIError):
"""
Exception raised when request is malformed.
"""
class TelegramNotFound(TelegramAPIError):
"""
Exception raised when chat, message, user, etc. not found.
"""
class TelegramConflictError(TelegramAPIError):
"""
Exception raised when bot token is already used by another application in polling mode.
"""
class TelegramUnauthorizedError(TelegramAPIError):
"""
Exception raised when bot token is invalid.
"""
class TelegramForbiddenError(TelegramAPIError):
"""
Exception raised when bot is kicked from chat or etc.
"""
class TelegramServerError(TelegramAPIError):
"""
Exception raised when Telegram server returns 5xx error.
"""
class RestartingTelegram(TelegramServerError):
"""
Exception raised when Telegram server is restarting.
It seems like this error is not used by Telegram anymore,
but it's still here for backward compatibility.
Currently, you should expect that Telegram can raise RetryAfter (with timeout 5 seconds)
error instead of this one.
"""
class TelegramEntityTooLarge(TelegramNetworkError):
"""
Exception raised when you are trying to send a file that is too large.
"""
url = "https://core.telegram.org/bots/api#sending-files"
class ClientDecodeError(AiogramError):
"""
Exception raised when client can't decode response. (Malformed response, etc.)
"""
def __init__(self, message: str, original: Exception, data: Any) -> None:
self.message = message
self.original = original
self.data = data
def __str__(self) -> str:
original_type = type(self.original)
return (
f"{self.message}\n"
f"Caused from error: "
f"{original_type.__module__}.{original_type.__name__}: {self.original}\n"
f"Content: {self.data}"
)