From 4db765f3a791c8cf66d72c4e43da1f3097067e08 Mon Sep 17 00:00:00 2001 From: Alex Root Junior Date: Sat, 1 Oct 2022 22:51:16 +0300 Subject: [PATCH] Partial update docs --- README.rst | 4 +- aiogram/dispatcher/router.py | 2 +- aiogram/filters/base.py | 5 ++ aiogram/types/error_event.py | 6 ++ docs/api/types/error_event.rst | 9 ++ docs/api/types/index.rst | 9 ++ docs/conf.py | 2 + .../class_based_handlers/callback_query.rst | 2 +- .../filters/chat_member_updated.rst | 4 +- docs/dispatcher/filters/command.rst | 1 + docs/dispatcher/filters/content_types.rst | 33 -------- docs/dispatcher/filters/index.rst | 82 +++---------------- docs/dispatcher/filters/magic_data.rst | 3 +- docs/dispatcher/filters/text.rst | 9 +- docs/dispatcher/flags.rst | 2 +- docs/dispatcher/router.rst | 13 ++- examples/own_filter.py | 18 ++++ 17 files changed, 81 insertions(+), 123 deletions(-) create mode 100644 docs/api/types/error_event.rst delete mode 100644 docs/dispatcher/filters/content_types.rst create mode 100644 examples/own_filter.py diff --git a/README.rst b/README.rst index 3be42b83..b387bcc1 100644 --- a/README.rst +++ b/README.rst @@ -62,14 +62,16 @@ Features - Asynchronous (`asyncio docs `_, :pep:`492`) - Has type hints (:pep:`484`) and can be used with `mypy `_ - Supports `PyPy `_ -- Supports `Telegram Bot API 5.3 `_ +- Supports `Telegram Bot API 6.3 `_ and gets fast updates to the latest versions of the Bot API - Telegram Bot API integration code was `autogenerated `_ and can be easily re-generated when API gets updated - Updates router (Blueprints) - Has Finite State Machine +- Uses powerful :ref:`magic filters ` - Middlewares (incoming updates and API calls) - Provides `Replies into Webhook `_ - Integrated I18n/L10n support with GNU Gettext (or Fluent) + .. warning:: It is strongly advised that you have prior experience working diff --git a/aiogram/dispatcher/router.py b/aiogram/dispatcher/router.py index d73b653a..9bb12cfd 100644 --- a/aiogram/dispatcher/router.py +++ b/aiogram/dispatcher/router.py @@ -21,7 +21,7 @@ class Router: - By decorator - :obj:`@router.()` """ - def __init__(self, name: Optional[str] = None) -> None: + def __init__(self, *, name: Optional[str] = None) -> None: """ :param name: Optional router name, can be useful for debugging """ diff --git a/aiogram/filters/base.py b/aiogram/filters/base.py index 2a9b816e..9e2e21b8 100644 --- a/aiogram/filters/base.py +++ b/aiogram/filters/base.py @@ -34,6 +34,11 @@ class Filter(ABC): return invert_f(self) def update_handler_flags(self, flags: Dict[str, Any]) -> None: + """ + Also if you want to extend handler flags with using this filter you should implement this method + + :param flags: existing flags, can be updated directly + """ pass def _signature_to_string(self, *args: Any, **kwargs: Any) -> str: diff --git a/aiogram/types/error_event.py b/aiogram/types/error_event.py index 6ab03303..ef376a16 100644 --- a/aiogram/types/error_event.py +++ b/aiogram/types/error_event.py @@ -3,8 +3,14 @@ from aiogram.types.base import MutableTelegramObject class ErrorEvent(MutableTelegramObject): + """ + Internal event, should be used to receive errors while processing Updates from Telegram + """ + update: Update + """Received update""" exception: Exception + """Exception""" class Config: arbitrary_types_allowed = True diff --git a/docs/api/types/error_event.rst b/docs/api/types/error_event.rst new file mode 100644 index 00000000..77fae204 --- /dev/null +++ b/docs/api/types/error_event.rst @@ -0,0 +1,9 @@ +########## +ErrorEvent +########## + + +.. automodule:: aiogram.types.error_event + :members: + :member-order: bysource + :undoc-members: True diff --git a/docs/api/types/index.rst b/docs/api/types/index.rst index abcfe205..32b33b53 100644 --- a/docs/api/types/index.rst +++ b/docs/api/types/index.rst @@ -189,3 +189,12 @@ Games game callback_game game_high_score + + +Internal events +=============== + +.. toctree:: + :maxdepth: 1 + + error_event diff --git a/docs/conf.py b/docs/conf.py index 41b2791b..3b0e1c91 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -62,3 +62,5 @@ texinfo_documents = [ "Miscellaneous", ), ] + +add_module_names = False diff --git a/docs/dispatcher/class_based_handlers/callback_query.rst b/docs/dispatcher/class_based_handlers/callback_query.rst index 856b27bd..98012af3 100644 --- a/docs/dispatcher/class_based_handlers/callback_query.rst +++ b/docs/dispatcher/class_based_handlers/callback_query.rst @@ -3,7 +3,7 @@ CallbackQueryHandler #################### -.. automodule:: aiogram.handler.callback_query +.. automodule:: aiogram.handlers.callback_query :members: :member-order: bysource :undoc-members: True diff --git a/docs/dispatcher/filters/chat_member_updated.rst b/docs/dispatcher/filters/chat_member_updated.rst index dd283171..6b2fff00 100644 --- a/docs/dispatcher/filters/chat_member_updated.rst +++ b/docs/dispatcher/filters/chat_member_updated.rst @@ -86,10 +86,10 @@ Handle user leave or join events from aiogram.filters import IS_MEMBER, IS_NOT_MEMBER - @router.chat_member(ChatMemberUpdatedFilter(member_status_changed=IS_MEMBER >> IS_NOT_MEMBER)) + @router.chat_member(ChatMemberUpdatedFilter(IS_MEMBER >> IS_NOT_MEMBER)) async def on_user_leave(event: ChatMemberUpdated): ... - @router.chat_member(ChatMemberUpdatedFilter(member_status_changed=IS_NOT_MEMBER >> IS_MEMBER)) + @router.chat_member(ChatMemberUpdatedFilter(IS_NOT_MEMBER >> IS_MEMBER)) async def on_user_join(event: ChatMemberUpdated): ... Or construct your own terms via using pre-defined set of statuses and transitions. diff --git a/docs/dispatcher/filters/command.rst b/docs/dispatcher/filters/command.rst index d899cabb..e926c081 100644 --- a/docs/dispatcher/filters/command.rst +++ b/docs/dispatcher/filters/command.rst @@ -22,6 +22,7 @@ Usage 2. Handle command by regexp pattern: :code:`Command(re.compile(r"item_(\d+)"))` 3. Match command by multiple variants: :code:`Command("item", re.compile(r"item_(\d+)"))` 4. Handle commands in public chats intended for other bots: :code:`Command("command", ignore_mention=True)` +5. Use :class:`aiogram.types.bot_command.BotCommand` object as command reference :code:`Command(BotCommand(command="command", description="My awesome command")` .. warning:: diff --git a/docs/dispatcher/filters/content_types.rst b/docs/dispatcher/filters/content_types.rst deleted file mode 100644 index c20170bf..00000000 --- a/docs/dispatcher/filters/content_types.rst +++ /dev/null @@ -1,33 +0,0 @@ -================== -ContentTypesFilter -================== - -.. autoclass:: aiogram.filters.content_types.ContentTypesFilter - :members: - :member-order: bysource - :undoc-members: False - -Can be imported: - -- :code:`from aiogram.filters.content_types import ContentTypesFilter` -- :code:`from aiogram.filters import ContentTypesFilter` - -Or used from filters factory by passing corresponding arguments to handler registration line - -Usage -===== - -1. Single content type: :code:`ContentTypesFilter(content_types=["sticker"])` or :code:`ContentTypesFilter(content_types="sticker")` -2. Multiple content types: :code:`ContentTypesFilter(content_types=["sticker", "photo"])` -3. Recommended: With usage of `ContentType` helper: :code:`ContentTypesFilter(content_types=[ContentType.PHOTO])` -4. Any content type: :code:`ContentTypesFilter(content_types=[ContentType.ANY])` - -Allowed handlers -================ - -Allowed update types for this filter: - -- :code:`message` -- :code:`edited_message` -- :code:`channel_post` -- :code:`edited_channel_post` diff --git a/docs/dispatcher/filters/index.rst b/docs/dispatcher/filters/index.rst index d9e56c75..9eed36c3 100644 --- a/docs/dispatcher/filters/index.rst +++ b/docs/dispatcher/filters/index.rst @@ -2,13 +2,6 @@ Filtering events ================ - -.. danger:: - - Note that the design of filters will be changed in 3.0b5 - - `Read more >> `_ - Filters is needed for routing updates to the specific handler. Searching of handler is always stops on first match set of filters are pass. @@ -23,91 +16,40 @@ Here is list of builtin filters: :maxdepth: 1 command - content_types text chat_member_updated - exception magic_filters magic_data callback_data + exception -Own filters specification +Writing own filters ========================= Filters can be: - Asynchronous function (:code:`async def my_filter(*args, **kwargs): pass`) - - Synchronous function (:code:`def my_filter(*args, **kwargs): pass`) - - Anonymous function (:code:`lambda event: True`) - - Any awaitable object - -- Subclass of :class:`aiogram.filters.base.BaseFilter` - +- Subclass of :class:`aiogram.filters.base.Filter` - Instances of :ref:`MagicFilter ` -Filters should return bool or dict. +and should return bool or dict. If the dictionary is passed as result of filter - resulted data will be propagated to the next filters and handler as keywords arguments. -Writing bound filters -===================== +Base class for own filters +-------------------------- -.. autoclass:: aiogram.filters.base.BaseFilter - :members: __call__ +.. autoclass:: aiogram.filters.base.Filter + :members: __call__,update_handler_flags :member-order: bysource :undoc-members: False +Own filter example +------------------ + For example if you need to make simple text filter: -.. code-block:: python - - from aiogram.filters import BaseFilter - - - class MyText(BaseFilter): - my_text: str - - async def __call__(self, message: Message) -> bool: - return message.text == self.my_text - - - router.message.bind_filter(MyText) - - @router.message(my_text="hello") - async def my_handler(message: Message): ... - -.. note:: - - Bound filters is always recursive propagates to the nested routers but will be available - in nested routers only after attaching routers so that's mean you will need to - include routers before registering handlers. - -Resolving filters with default value -==================================== - -Bound Filters with only default arguments will be automatically applied with default values -to each handler in the router and nested routers to which this filter is bound. - -For example, although we do not specify :code:`chat_type` in the handler filters, -but since the filter has a default value, the filter will be applied to the handler -with a default value :code:`private`: - -.. code-block:: python - - class ChatType(BaseFilter): - chat_type: str = "private" - - async def __call__(self, message: Message , event_chat: Chat) -> bool: - if event_chat: - return event_chat.type == chat_type - else: - return False - - - router.message.bind_filter(ChatType) - - @router.message() - async def my_handler(message: Message): ... +.. literalinclude:: ../../../examples/own_filter.py diff --git a/docs/dispatcher/filters/magic_data.rst b/docs/dispatcher/filters/magic_data.rst index 86294a69..0d0f093b 100644 --- a/docs/dispatcher/filters/magic_data.rst +++ b/docs/dispatcher/filters/magic_data.rst @@ -9,7 +9,6 @@ MagicData Can be imported: -- :code:`from aiogram.filters.magic_data import MagicData` - :code:`from aiogram.filters import MagicData` Or used from filters factory by passing corresponding arguments to handler registration line @@ -17,7 +16,7 @@ Or used from filters factory by passing corresponding arguments to handler regis Usage ===== -#. :code:`MagicData(magic_data=F.event.from_user.id == F.config.admin_id)` (Note that :code:`config` should be passed from middleware) +#. :code:`MagicData(F.event.from_user.id == F.config.admin_id)` (Note that :code:`config` should be passed from middleware) Allowed handlers diff --git a/docs/dispatcher/filters/text.rst b/docs/dispatcher/filters/text.rst index 2a40c333..5ae8d22a 100644 --- a/docs/dispatcher/filters/text.rst +++ b/docs/dispatcher/filters/text.rst @@ -11,7 +11,6 @@ Can be imported: - :code:`from aiogram.filters.text import Text` - :code:`from aiogram.filters import Text` -- :code:`from.filters import Text` Or used from filters factory by passing corresponding arguments to handler registration line @@ -19,11 +18,11 @@ Usage ===== #. Text equals with the specified value: :code:`Text(text="text") # value == 'text'` -#. Text starts with the specified value: :code:`Text(text_startswith="text") # value.startswith('text')` -#. Text ends with the specified value: :code:`Text(text_endswith="text") # value.endswith('text')` -#. Text contains the specified value: :code:`Text(text_contains="text") # value in 'text'` +#. Text starts with the specified value: :code:`Text(startswith="text") # value.startswith('text')` +#. Text ends with the specified value: :code:`Text(endswith="text") # value.endswith('text')` +#. Text contains the specified value: :code:`Text(contains="text") # value in 'text'` #. Any of previous listed filters can be list, set or tuple of strings that's mean any of listed value should be equals/startswith/endswith/contains: :code:`Text(text=["text", "spam"])` -#. Ignore case can be combined with any previous listed filter: :code:`Text(text="Text", text_ignore_case=True) # value.lower() == 'text'.lower()` +#. Ignore case can be combined with any previous listed filter: :code:`Text(text="Text", ignore_case=True) # value.lower() == 'text'.lower()` Allowed handlers ================ diff --git a/docs/dispatcher/flags.rst b/docs/dispatcher/flags.rst index cc8cff3f..1b36bd1e 100644 --- a/docs/dispatcher/flags.rst +++ b/docs/dispatcher/flags.rst @@ -42,7 +42,7 @@ Via filters .. code-block:: python - class Command(BaseFilter): + class Command(Filter): ... def update_handler_flags(self, flags: Dict[str, Any]) -> None: diff --git a/docs/dispatcher/router.rst b/docs/dispatcher/router.rst index 22446990..617c1f89 100644 --- a/docs/dispatcher/router.rst +++ b/docs/dispatcher/router.rst @@ -44,8 +44,8 @@ Message (For example text, sticker and document are always of different content types of message) - Recommended way to check field availability before usage or use - :class:`aiogram.filters.content_types.ContentTypesFilter` + Recommended way to check field availability before usage, for example via :ref:`magic filter `: + :code:`F.text` to handle text, :code:`F.sticker` to handle stickers only and etc. .. code-block:: python @@ -141,7 +141,7 @@ Errors .. code-block:: python @router.errors() - async def error_handler(exception: Exception) -> Any: pass + async def error_handler(exception: ErrorEvent) -> Any: pass Is useful for handling errors from other handlers @@ -152,9 +152,8 @@ Nested routers .. warning:: Routers by the way can be nested to an another routers with some limitations: - - 1. Router **CAN NOT** include itself - 1. Routers **CAN NOT** be used for circular including (router 1 include router 2, router 2 include router 3, router 3 include router 1) + 1. Router **CAN NOT** include itself + 1. Routers **CAN NOT** be used for circular including (router 1 include router 2, router 2 include router 3, router 3 include router 1) Example: @@ -170,7 +169,7 @@ Example: .. code-block:: python - :caption: module_12.py + :caption: module_2.py :name: module_1 from module_2 import router2 diff --git a/examples/own_filter.py b/examples/own_filter.py new file mode 100644 index 00000000..89101920 --- /dev/null +++ b/examples/own_filter.py @@ -0,0 +1,18 @@ +from aiogram import Router +from aiogram.filters import Filter +from aiogram.types import Message + +router = Router() + + +class MyFilter(Filter): + def __init__(self, my_text: str) -> None: + self.my_text = my_text + + async def __call__(self, message: Message) -> bool: + return message.text == self.my_text + + +@router.message(MyFilter("hello")) +async def my_handler(message: Message): + ...