mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Migration guide 2.x -> 3.0 (#1143)
* Initial commit for docs cleanup * Update migration guide * More docs * Added changes description * Small fixes
This commit is contained in:
parent
2ecf9cefd7
commit
56f0d9d220
24 changed files with 363 additions and 85 deletions
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _enums:
|
||||||
|
|
||||||
#####
|
#####
|
||||||
Enums
|
Enums
|
||||||
#####
|
#####
|
||||||
|
|
|
||||||
1
CHANGES/1143.doc.rst
Normal file
1
CHANGES/1143.doc.rst
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Improved docs, added basic migration guide (will be expanded later)
|
||||||
|
|
@ -53,6 +53,12 @@ DEFAULT_TIMEOUT: Final[float] = 60.0
|
||||||
|
|
||||||
|
|
||||||
class BaseSession(abc.ABC):
|
class BaseSession(abc.ABC):
|
||||||
|
"""
|
||||||
|
This is base class for all HTTP sessions in aiogram.
|
||||||
|
|
||||||
|
If you want to create your own session, you must inherit from this class.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
api: TelegramAPIServer = PRODUCTION,
|
api: TelegramAPIServer = PRODUCTION,
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ class Router:
|
||||||
self.chat_member = TelegramEventObserver(router=self, event_name="chat_member")
|
self.chat_member = TelegramEventObserver(router=self, event_name="chat_member")
|
||||||
self.chat_join_request = TelegramEventObserver(router=self, event_name="chat_join_request")
|
self.chat_join_request = TelegramEventObserver(router=self, event_name="chat_join_request")
|
||||||
|
|
||||||
self.errors = TelegramEventObserver(router=self, event_name="error")
|
self.errors = self.error = TelegramEventObserver(router=self, event_name="error")
|
||||||
|
|
||||||
self.startup = EventObserver()
|
self.startup = EventObserver()
|
||||||
self.shutdown = EventObserver()
|
self.shutdown = EventObserver()
|
||||||
|
|
@ -184,6 +184,12 @@ class Router:
|
||||||
router.sub_routers.append(self)
|
router.sub_routers.append(self)
|
||||||
|
|
||||||
def include_routers(self, *routers: Router) -> None:
|
def include_routers(self, *routers: Router) -> None:
|
||||||
|
"""
|
||||||
|
Attach multiple routers.
|
||||||
|
|
||||||
|
:param routers:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
if not routers:
|
if not routers:
|
||||||
raise ValueError("At least one router must be provided")
|
raise ValueError("At least one router must be provided")
|
||||||
for router in routers:
|
for router in routers:
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,16 @@ from aiogram.utils.link import docs_url
|
||||||
|
|
||||||
|
|
||||||
class AiogramError(Exception):
|
class AiogramError(Exception):
|
||||||
pass
|
"""
|
||||||
|
Base exception for all aiogram errors.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class DetailedAiogramError(AiogramError):
|
class DetailedAiogramError(AiogramError):
|
||||||
|
"""
|
||||||
|
Base exception for all aiogram errors with detailed message.
|
||||||
|
"""
|
||||||
|
|
||||||
url: Optional[str] = None
|
url: Optional[str] = None
|
||||||
|
|
||||||
def __init__(self, message: str) -> None:
|
def __init__(self, message: str) -> None:
|
||||||
|
|
@ -26,14 +32,24 @@ class DetailedAiogramError(AiogramError):
|
||||||
|
|
||||||
|
|
||||||
class CallbackAnswerException(AiogramError):
|
class CallbackAnswerException(AiogramError):
|
||||||
pass
|
"""
|
||||||
|
Exception for callback answer.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class UnsupportedKeywordArgument(DetailedAiogramError):
|
class UnsupportedKeywordArgument(DetailedAiogramError):
|
||||||
|
"""
|
||||||
|
Exception raised when a keyword argument is passed as filter.
|
||||||
|
"""
|
||||||
|
|
||||||
url = docs_url("migration_2_to_3.html", fragment_="filtering-events")
|
url = docs_url("migration_2_to_3.html", fragment_="filtering-events")
|
||||||
|
|
||||||
|
|
||||||
class TelegramAPIError(DetailedAiogramError):
|
class TelegramAPIError(DetailedAiogramError):
|
||||||
|
"""
|
||||||
|
Base exception for all Telegram API errors.
|
||||||
|
"""
|
||||||
|
|
||||||
label: str = "Telegram server says"
|
label: str = "Telegram server says"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
@ -50,10 +66,18 @@ class TelegramAPIError(DetailedAiogramError):
|
||||||
|
|
||||||
|
|
||||||
class TelegramNetworkError(TelegramAPIError):
|
class TelegramNetworkError(TelegramAPIError):
|
||||||
|
"""
|
||||||
|
Base exception for all Telegram network errors.
|
||||||
|
"""
|
||||||
|
|
||||||
label = "HTTP Client says"
|
label = "HTTP Client says"
|
||||||
|
|
||||||
|
|
||||||
class TelegramRetryAfter(TelegramAPIError):
|
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"
|
url = "https://core.telegram.org/bots/faq#my-bot-is-hitting-limits-how-do-i-avoid-this"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
@ -73,6 +97,10 @@ class TelegramRetryAfter(TelegramAPIError):
|
||||||
|
|
||||||
|
|
||||||
class TelegramMigrateToChat(TelegramAPIError):
|
class TelegramMigrateToChat(TelegramAPIError):
|
||||||
|
"""
|
||||||
|
Exception raised when chat has been migrated to a supergroup.
|
||||||
|
"""
|
||||||
|
|
||||||
url = "https://core.telegram.org/bots/api#responseparameters"
|
url = "https://core.telegram.org/bots/api#responseparameters"
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
@ -90,38 +118,66 @@ class TelegramMigrateToChat(TelegramAPIError):
|
||||||
|
|
||||||
|
|
||||||
class TelegramBadRequest(TelegramAPIError):
|
class TelegramBadRequest(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when request is malformed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TelegramNotFound(TelegramAPIError):
|
class TelegramNotFound(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when chat, message, user, etc. not found.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TelegramConflictError(TelegramAPIError):
|
class TelegramConflictError(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when bot token is already used by another application in polling mode.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TelegramUnauthorizedError(TelegramAPIError):
|
class TelegramUnauthorizedError(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when bot token is invalid.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TelegramForbiddenError(TelegramAPIError):
|
class TelegramForbiddenError(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when bot is kicked from chat or etc.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class TelegramServerError(TelegramAPIError):
|
class TelegramServerError(TelegramAPIError):
|
||||||
pass
|
"""
|
||||||
|
Exception raised when Telegram server returns 5xx error.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
class RestartingTelegram(TelegramServerError):
|
class RestartingTelegram(TelegramServerError):
|
||||||
pass
|
"""
|
||||||
|
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):
|
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"
|
url = "https://core.telegram.org/bots/api#sending-files"
|
||||||
|
|
||||||
|
|
||||||
class ClientDecodeError(AiogramError):
|
class ClientDecodeError(AiogramError):
|
||||||
|
"""
|
||||||
|
Exception raised when client can't decode response. (Malformed response, etc.)
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, message: str, original: Exception, data: Any) -> None:
|
def __init__(self, message: str, original: Exception, data: Any) -> None:
|
||||||
self.message = message
|
self.message = message
|
||||||
self.original = original
|
self.original = original
|
||||||
|
|
|
||||||
|
|
@ -532,7 +532,7 @@ def as_marked_list(*items: NodeType, marker: str = "- ") -> Text:
|
||||||
Wrap elements as marked list
|
Wrap elements as marked list
|
||||||
|
|
||||||
:param items:
|
:param items:
|
||||||
:param marker: line marker, by default is :code:`- `
|
:param marker: line marker, by default is '- '
|
||||||
:return: Text
|
:return: Text
|
||||||
"""
|
"""
|
||||||
return as_list(*(Text(marker, item) for item in items))
|
return as_list(*(Text(marker, item) for item in items))
|
||||||
|
|
@ -544,7 +544,7 @@ def as_numbered_list(*items: NodeType, start: int = 1, fmt: str = "{}. ") -> Tex
|
||||||
|
|
||||||
:param items:
|
:param items:
|
||||||
:param start: initial number, by default 1
|
:param start: initial number, by default 1
|
||||||
:param fmt: number format, by default :code:`{}. `
|
:param fmt: number format, by default '{}. '
|
||||||
:return: Text
|
:return: Text
|
||||||
"""
|
"""
|
||||||
return as_list(*(Text(fmt.format(index), item) for index, item in enumerate(items, start)))
|
return as_list(*(Text(fmt.format(index), item) for index, item in enumerate(items, start)))
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _enums:
|
||||||
|
|
||||||
#####
|
#####
|
||||||
Enums
|
Enums
|
||||||
#####
|
#####
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
Use Custom API server
|
Use Custom API server
|
||||||
=====================
|
=====================
|
||||||
|
|
||||||
.. autoclass:: aiogram.client.telegram.TelegramAPIServer
|
|
||||||
:members:
|
|
||||||
|
|
||||||
For example, if you want to use self-hosted API server:
|
For example, if you want to use self-hosted API server:
|
||||||
|
|
||||||
.. code-block:: python3
|
.. code-block:: python
|
||||||
|
|
||||||
session = AiohttpSession(
|
session = AiohttpSession(
|
||||||
api=TelegramAPIServer.from_base('http://localhost:8082')
|
api=TelegramAPIServer.from_base('http://localhost:8082')
|
||||||
)
|
)
|
||||||
bot = Bot(..., session=session)
|
bot = Bot(..., session=session)
|
||||||
|
|
||||||
|
.. autoclass:: aiogram.client.telegram.TelegramAPIServer
|
||||||
|
:members:
|
||||||
|
|
|
||||||
|
|
@ -8,3 +8,4 @@ Client sessions is used for interacting with API server.
|
||||||
custom_server
|
custom_server
|
||||||
base
|
base
|
||||||
aiohttp
|
aiohttp
|
||||||
|
middleware
|
||||||
|
|
|
||||||
75
docs/api/session/middleware.rst
Normal file
75
docs/api/session/middleware.rst
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
##########################
|
||||||
|
Client session middlewares
|
||||||
|
##########################
|
||||||
|
|
||||||
|
In some cases you may want to add some middlewares to the client session to customize the behavior of the client.
|
||||||
|
|
||||||
|
Some useful cases that is:
|
||||||
|
|
||||||
|
- Log the outgoing requests
|
||||||
|
- Customize the request parameters
|
||||||
|
- Handle rate limiting errors and retry the request
|
||||||
|
- others ...
|
||||||
|
|
||||||
|
So, you can do it using client session middlewares.
|
||||||
|
A client session middleware is a function (or callable class) that receives the request and the next middleware to call.
|
||||||
|
The middleware can modify the request and then call the next middleware to continue the request processing.
|
||||||
|
|
||||||
|
How to register client session middleware?
|
||||||
|
==========================================
|
||||||
|
|
||||||
|
Register using register method
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
bot.session.middleware(RequestLogging(ignore_methods=[GetUpdates]))
|
||||||
|
|
||||||
|
Register using decorator
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@bot.session.middleware()
|
||||||
|
async def my_middleware(
|
||||||
|
make_request: NextRequestMiddlewareType[TelegramType],
|
||||||
|
bot: "Bot",
|
||||||
|
method: TelegramMethod[TelegramType],
|
||||||
|
) -> Response[TelegramType]:
|
||||||
|
# do something with request
|
||||||
|
return await make_request(bot, method)
|
||||||
|
|
||||||
|
|
||||||
|
Example
|
||||||
|
=======
|
||||||
|
|
||||||
|
Class based session middleware
|
||||||
|
------------------------------
|
||||||
|
|
||||||
|
.. literalinclude:: ../../../aiogram/client/session/middlewares/request_logging.py
|
||||||
|
:lines: 16-
|
||||||
|
:language: python
|
||||||
|
:linenos:
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
this middlewware is already implemented inside aiogram, so, if you want to use it you can
|
||||||
|
just import it :code:`from aiogram.client.session.middlewares.request_logging import RequestLogging`
|
||||||
|
|
||||||
|
|
||||||
|
Function based session middleware
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def __call__(
|
||||||
|
self,
|
||||||
|
make_request: NextRequestMiddlewareType[TelegramType],
|
||||||
|
bot: "Bot",
|
||||||
|
method: TelegramMethod[TelegramType],
|
||||||
|
) -> Response[TelegramType]:
|
||||||
|
try:
|
||||||
|
# do something with request
|
||||||
|
return await make_request(bot, method)
|
||||||
|
finally:
|
||||||
|
# do something after request
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
##########
|
|
||||||
ErrorEvent
|
|
||||||
##########
|
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: aiogram.types.error_event
|
|
||||||
:members:
|
|
||||||
:member-order: bysource
|
|
||||||
:undoc-members: True
|
|
||||||
:exclude-members: model_config,model_fields
|
|
||||||
|
|
@ -28,7 +28,6 @@ extensions = [
|
||||||
"sphinx.ext.autodoc",
|
"sphinx.ext.autodoc",
|
||||||
"sphinx.ext.ifconfig",
|
"sphinx.ext.ifconfig",
|
||||||
"sphinx.ext.intersphinx",
|
"sphinx.ext.intersphinx",
|
||||||
"sphinx-prompt",
|
|
||||||
"sphinx_substitution_extensions",
|
"sphinx_substitution_extensions",
|
||||||
"sphinx_copybutton",
|
"sphinx_copybutton",
|
||||||
"sphinxcontrib.towncrier.ext",
|
"sphinxcontrib.towncrier.ext",
|
||||||
|
|
@ -67,6 +66,6 @@ texinfo_documents = [
|
||||||
|
|
||||||
# add_module_names = False
|
# add_module_names = False
|
||||||
|
|
||||||
towncrier_draft_autoversion_mode = 'draft'
|
towncrier_draft_autoversion_mode = "draft"
|
||||||
towncrier_draft_include_empty = False
|
towncrier_draft_include_empty = False
|
||||||
towncrier_draft_working_directory = Path(__file__).parent.parent
|
towncrier_draft_working_directory = Path(__file__).parent.parent
|
||||||
|
|
|
||||||
49
docs/dispatcher/errors.rst
Normal file
49
docs/dispatcher/errors.rst
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
######
|
||||||
|
Errors
|
||||||
|
######
|
||||||
|
|
||||||
|
|
||||||
|
Handling errors
|
||||||
|
===============
|
||||||
|
|
||||||
|
Is recommended way that you should use errors inside handlers using try-except block,
|
||||||
|
but in common cases you can use global errors handler at router or dispatcher level.
|
||||||
|
|
||||||
|
If you specify errors handler for router - it will be used for all handlers inside this router.
|
||||||
|
|
||||||
|
If you specify errors handler for dispatcher - it will be used for all handlers inside all routers.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@router.error(ExceptionTypeFilter(MyCustomException), F.update.message.as_("message"))
|
||||||
|
async def handle_my_custom_exception(event: ErrorEvent, message: Message):
|
||||||
|
# do something with error
|
||||||
|
await message.answer("Oops, something went wrong!")
|
||||||
|
|
||||||
|
|
||||||
|
@router.error()
|
||||||
|
async def error_handler(event: ErrorEvent):
|
||||||
|
logger.critical("Critical error caused by %s", event.exception, exc_info=True)
|
||||||
|
# do something with error
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
.. _error-event:
|
||||||
|
|
||||||
|
ErrorEvent
|
||||||
|
==========
|
||||||
|
|
||||||
|
.. automodule:: aiogram.types.error_event
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
:undoc-members: True
|
||||||
|
:exclude-members: model_config,model_fields
|
||||||
|
|
||||||
|
.. _error-types:
|
||||||
|
|
||||||
|
Error types
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. automodule:: aiogram.exceptions
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _callback-data-factory
|
||||||
|
|
||||||
==============================
|
==============================
|
||||||
Callback Data Factory & Filter
|
Callback Data Factory & Filter
|
||||||
==============================
|
==============================
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ Dispatcher is subclass of router and should be always is root router.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
|
|
||||||
observer
|
|
||||||
router
|
router
|
||||||
dispatcher
|
dispatcher
|
||||||
class_based_handlers/index
|
class_based_handlers/index
|
||||||
|
|
@ -25,3 +24,4 @@ Dispatcher is subclass of router and should be always is root router.
|
||||||
middlewares
|
middlewares
|
||||||
finite_state_machine/index
|
finite_state_machine/index
|
||||||
flags
|
flags
|
||||||
|
errors
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _middlewares:
|
||||||
|
|
||||||
===========
|
===========
|
||||||
Middlewares
|
Middlewares
|
||||||
===========
|
===========
|
||||||
|
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
########
|
|
||||||
Observer
|
|
||||||
########
|
|
||||||
|
|
||||||
Observer is used for filtering and handling different events. That is part of internal API with some public methods and is recommended to don't use methods is not listed here.
|
|
||||||
|
|
||||||
In `aiogram` framework is available two variants of observer:
|
|
||||||
|
|
||||||
- `EventObserver <#eventobserver>`__
|
|
||||||
- `TelegramEventObserver <#telegrameventobserver>`__
|
|
||||||
|
|
||||||
|
|
||||||
EventObserver
|
|
||||||
=============
|
|
||||||
|
|
||||||
.. autoclass:: aiogram.dispatcher.event.event.EventObserver
|
|
||||||
:members: register, trigger, __call__
|
|
||||||
:member-order: bysource
|
|
||||||
|
|
||||||
|
|
||||||
TelegramEventObserver
|
|
||||||
=====================
|
|
||||||
|
|
||||||
.. autoclass:: aiogram.dispatcher.event.telegram.TelegramEventObserver
|
|
||||||
:members: register, trigger, __call__, bind_filter, middleware, outer_middleware
|
|
||||||
:member-order: bysource
|
|
||||||
|
|
@ -3,10 +3,12 @@ Router
|
||||||
######
|
######
|
||||||
|
|
||||||
.. autoclass:: aiogram.dispatcher.router.Router
|
.. autoclass:: aiogram.dispatcher.router.Router
|
||||||
:members: __init__, include_router
|
:members: __init__, include_router, include_routers, resolve_used_update_types
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
.. _Event observers:
|
||||||
|
|
||||||
Event observers
|
Event observers
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|
@ -19,19 +21,6 @@ Here is the list of available observers and examples of how to register handlers
|
||||||
|
|
||||||
In these examples only decorator-style registering handlers are used, but if you don't like @decorators just use :obj:`<event type>.register(...)` method instead.
|
In these examples only decorator-style registering handlers are used, but if you don't like @decorators just use :obj:`<event type>.register(...)` method instead.
|
||||||
|
|
||||||
Update
|
|
||||||
------
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@router.update()
|
|
||||||
async def message_handler(update: types.Update) -> Any: pass
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
By default Router already has an update handler which route all event types to another observers.
|
|
||||||
|
|
||||||
|
|
||||||
Message
|
Message
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
@ -143,9 +132,12 @@ Errors
|
||||||
@router.errors()
|
@router.errors()
|
||||||
async def error_handler(exception: ErrorEvent) -> Any: pass
|
async def error_handler(exception: ErrorEvent) -> Any: pass
|
||||||
|
|
||||||
Is useful for handling errors from other handlers
|
Is useful for handling errors from other handlers, error event described :ref:`here <error-event>`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.. _Nested routers:
|
||||||
|
|
||||||
Nested routers
|
Nested routers
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
|
@ -159,8 +151,8 @@ Nested routers
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:caption: module_2.py
|
:caption: module_1.py
|
||||||
:name: module_2
|
:name: module_1
|
||||||
|
|
||||||
router2 = Router()
|
router2 = Router()
|
||||||
|
|
||||||
|
|
@ -170,7 +162,7 @@ Example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
:caption: module_2.py
|
:caption: module_2.py
|
||||||
:name: module_1
|
:name: module_2
|
||||||
|
|
||||||
from module_2 import router2
|
from module_2 import router2
|
||||||
|
|
||||||
|
|
@ -179,6 +171,22 @@ Example:
|
||||||
router1.include_router(router2)
|
router1.include_router(router2)
|
||||||
|
|
||||||
|
|
||||||
|
Update
|
||||||
|
------
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@dispatcher.update()
|
||||||
|
async def message_handler(update: types.Update) -> Any: pass
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The only root Router (Dispatcher) can handle this type of event.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Dispatcher already has default handler for this event type, so you can use it for handling all updates that are not handled by any other handlers.
|
||||||
|
|
||||||
How it works?
|
How it works?
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Contents
|
||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
|
|
||||||
install
|
install
|
||||||
|
migration_2_to_3
|
||||||
api/index
|
api/index
|
||||||
dispatcher/index
|
dispatcher/index
|
||||||
utils/index
|
utils/index
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,6 @@
|
||||||
Installation
|
Installation
|
||||||
############
|
############
|
||||||
|
|
||||||
Stable (2.x)
|
|
||||||
============
|
|
||||||
|
|
||||||
From PyPI
|
From PyPI
|
||||||
---------
|
---------
|
||||||
|
|
||||||
|
|
@ -35,10 +32,3 @@ From GitHub
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
pip install https://github.com/aiogram/aiogram/archive/refs/heads/dev-3.x.zip
|
pip install https://github.com/aiogram/aiogram/archive/refs/heads/dev-3.x.zip
|
||||||
|
|
||||||
From AUR
|
|
||||||
--------
|
|
||||||
|
|
||||||
.. code-block:: bash
|
|
||||||
|
|
||||||
yay -S python-aiogram3
|
|
||||||
|
|
|
||||||
114
docs/migration_2_to_3.rst
Normal file
114
docs/migration_2_to_3.rst
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
==========================
|
||||||
|
Migration FAQ (2.x -> 3.0)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. danger::
|
||||||
|
|
||||||
|
This guide is still in progress.
|
||||||
|
|
||||||
|
This version introduces much many breaking changes and architectural improvements,
|
||||||
|
helping to reduce global variables count in your code, provides useful mechanisms
|
||||||
|
to separate your code to modules or just make sharable modules via packages on the PyPi,
|
||||||
|
makes middlewares and filters more controllable and others.
|
||||||
|
|
||||||
|
On this page you can read about points that changed corresponding to last stable 2.x version.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This page is most like a detailed changelog than a migration guide,
|
||||||
|
but it will be updated in the future.
|
||||||
|
|
||||||
|
Feel free to contribute to this page, if you find something that is not mentioned here.
|
||||||
|
|
||||||
|
|
||||||
|
Dispatcher
|
||||||
|
==========
|
||||||
|
|
||||||
|
- :class:`Dispatcher` class no longer accepts the `Bot` instance into the initializer,
|
||||||
|
it should be passed to dispatcher only for starting polling or handling event from webhook.
|
||||||
|
Also this way adds possibility to use multiple bot instances at the same time ("multibot")
|
||||||
|
- :class:`Dispatcher` now can be extended with another Dispatcher-like
|
||||||
|
thing named :class:`Router` (:ref:`Read more » <Nested routers>`).
|
||||||
|
With routes you can easily separate your code to multiple modules
|
||||||
|
and may be share this modules between projects.
|
||||||
|
- Removed the **_handler** suffix from all event handler decorators and registering methods.
|
||||||
|
(:ref:`Read more » <Event observers>`)
|
||||||
|
- Executor entirely removed, now you can use Dispatcher directly to start polling or webhook.
|
||||||
|
|
||||||
|
Filtering events
|
||||||
|
================
|
||||||
|
|
||||||
|
- Keyword filters can no more be used, use filters explicitly. (`Read more » <https://github.com/aiogram/aiogram/issues/942>`_)
|
||||||
|
- In due to keyword filters was removed all enabled by default filters (state and content_type now is not enabled),
|
||||||
|
so you should specify them explicitly if you want to use.
|
||||||
|
For example instead of using :code:`@dp.message_handler(content_types=ContentType.PHOTO)`
|
||||||
|
you should use :code:`@router.message(F.photo)`
|
||||||
|
- Most of common filters is replaced by "magic filter". (:ref:`Read more » <magic-filters>`)
|
||||||
|
- Now by default message handler receives any content type,
|
||||||
|
if you want specific one just add the filters (Magic or any other)
|
||||||
|
- State filter now is not enabled by default, that's mean if you using :code:`state="*"` in v2
|
||||||
|
then you should not pass any state filter in v3, and vice versa,
|
||||||
|
if the state in v2 is not specified now you should specify the state.
|
||||||
|
- Added possibility to register per-router global filters, that helps to reduces
|
||||||
|
the number of repetitions in the code and makes easily way to control
|
||||||
|
for what each router will be used.
|
||||||
|
|
||||||
|
Bot API
|
||||||
|
=======
|
||||||
|
|
||||||
|
- Now all API methods is classes with validation (via `pydantic <https://docs.pydantic.dev/>`_)
|
||||||
|
(all API calls is also available as methods in the Bot class).
|
||||||
|
- Added more pre-defined Enums and moved into `aiogram.enums` sub-package. For example chat type enum now is
|
||||||
|
:class:`aiogram.enums.ChatType` instead of :class:`aiogram.types.chat.ChatType`.
|
||||||
|
(:ref:`Read more » <enums>`)
|
||||||
|
- Separated HTTP client session into container that can be reused between different
|
||||||
|
Bot instances in the application.
|
||||||
|
- API Exceptions is no more classified by specific message in due to Telegram has no documented error codes.
|
||||||
|
But all errors is classified by HTTP status code and for each method only one case can be caused with the same code,
|
||||||
|
so in most cases you should check that only error type (by status-code) without checking error message.
|
||||||
|
(:ref:`Read more » <error-types>`)
|
||||||
|
|
||||||
|
Middlewares
|
||||||
|
===========
|
||||||
|
|
||||||
|
- Middlewares can now control a execution context, e.g. using context managers (:ref:`Read more » <middlewares>`)
|
||||||
|
- All contextual data now is shared between middlewares, filters and handlers to end-to-end use.
|
||||||
|
For example now you can easily pass some data into context inside middleware and
|
||||||
|
get it in the filters layer as the same way as in the handlers via keyword arguments.
|
||||||
|
- Added mechanism named **flags**, that helps to customize handler behavior
|
||||||
|
in conjunction with middlewares. (:ref:`Read more » <flags>`)
|
||||||
|
|
||||||
|
Keyboard Markup
|
||||||
|
===============
|
||||||
|
|
||||||
|
- Now :class:`aiogram.types.inline_keyboard_markup.InlineKeyboardMarkup`
|
||||||
|
and :class:`aiogram.types.reply_keyboard_markup.ReplyKeyboardMarkup` has no methods to extend it,
|
||||||
|
instead you have to use markup builders :class:`aiogram.utils.keyboard.ReplyKeyboardBuilder`
|
||||||
|
and :class:`aiogram.utils.keyboard.KeyboardBuilder` respectively
|
||||||
|
(:ref:`Read more » <keyboard-builder>`)
|
||||||
|
|
||||||
|
|
||||||
|
Callbacks data
|
||||||
|
==============
|
||||||
|
|
||||||
|
- Callback data factory now is strictly typed via `pydantic <https://docs.pydantic.dev/>`_ models
|
||||||
|
(:ref:`Read more » <callback-data-factory>`)
|
||||||
|
|
||||||
|
Finite State machine
|
||||||
|
====================
|
||||||
|
|
||||||
|
- State filter will no more added to all handlers, you will need to specify state if you want
|
||||||
|
- Added possibility to change FSM strategy, for example if you want to control state
|
||||||
|
for each user in chat topics instead of user in chat you can specify it in the Dispatcher.
|
||||||
|
|
||||||
|
Sending Files
|
||||||
|
=============
|
||||||
|
|
||||||
|
- From now you should wrap sending files into InputFile object before send instead of passing
|
||||||
|
IO object directly to the API method. (:ref:`Read more » <sending-files>`)
|
||||||
|
|
||||||
|
Webhook
|
||||||
|
=======
|
||||||
|
|
||||||
|
- Simplified aiohttp web app configuration
|
||||||
|
- By default added possibility to upload files when you use reply into webhook
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
.. _formatting-tool
|
.. _formatting-tool:
|
||||||
|
|
||||||
==========
|
==========
|
||||||
Formatting
|
Formatting
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
.. _keyboard-builder
|
||||||
================
|
================
|
||||||
Keyboard builder
|
Keyboard builder
|
||||||
================
|
================
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,6 @@ docs = [
|
||||||
"sphinx-autobuild~=2021.3.14",
|
"sphinx-autobuild~=2021.3.14",
|
||||||
"sphinx-copybutton~=0.5.2",
|
"sphinx-copybutton~=0.5.2",
|
||||||
"furo~=2023.7.26",
|
"furo~=2023.7.26",
|
||||||
"sphinx-prompt~=1.7.0",
|
|
||||||
"Sphinx-Substitution-Extensions~=2022.2.16",
|
"Sphinx-Substitution-Extensions~=2022.2.16",
|
||||||
"towncrier~=23.6.0",
|
"towncrier~=23.6.0",
|
||||||
"pygments~=2.15.1",
|
"pygments~=2.15.1",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue