mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-11 18:01:04 +00:00
Remove filters factory, introduce docs translation (#978)
* Rewrite filters * Update README.rst * Fixed tests * Small optimization of the Text filter (TY to @bomzheg) * Remove dataclass slots argument in due to the only Python 3.10 has an slots argument * Fixed mypy * Update tests * Disable Python 3.11 * Fixed #1013: Empty mention should be None instead of empty string. * Added #990 to the changelog * Added #942 to the changelog * Fixed coverage * Update poetry and dependencies * Fixed mypy * Remove deprecated code * Added more tests, update pyproject.toml * Partial update docs * Added initial Docs translation files * Added more changes * Added log message when connection is established in polling process * Fixed action * Disable lint for PyPy * Added changelog for docs translation
This commit is contained in:
parent
94030903ec
commit
f4251382e8
610 changed files with 61738 additions and 1687 deletions
|
|
@ -3,7 +3,7 @@ CallbackQueryHandler
|
|||
####################
|
||||
|
||||
|
||||
.. automodule:: aiogram.handler.callback_query
|
||||
.. automodule:: aiogram.handlers.callback_query
|
||||
:members:
|
||||
:member-order: bysource
|
||||
:undoc-members: True
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ Command
|
|||
=======
|
||||
|
||||
.. autoclass:: aiogram.filters.command.Command
|
||||
:members:
|
||||
:members: __init__
|
||||
:member-order: bysource
|
||||
:undoc-members: False
|
||||
|
||||
|
|
@ -18,10 +18,11 @@ When filter is passed the :class:`aiogram.filters.command.CommandObject` will be
|
|||
Usage
|
||||
=====
|
||||
|
||||
1. Filter single variant of commands: :code:`Command(commands=["start"])` or :code:`Command(commands="start")`
|
||||
2. Handle command by regexp pattern: :code:`Command(commands=[re.compile(r"item_(\d+)")])`
|
||||
3. Match command by multiple variants: :code:`Command(commands=["item", re.compile(r"item_(\d+)")])`
|
||||
4. Handle commands in public chats intended for other bots: :code:`Command(commands=["command"], commands_ignore_mention=True)`
|
||||
1. Filter single variant of commands: :code:`Command("start")`
|
||||
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::
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
|
@ -2,13 +2,6 @@
|
|||
Filtering events
|
||||
================
|
||||
|
||||
|
||||
.. danger::
|
||||
|
||||
Note that the design of filters will be changed in 3.0b5
|
||||
|
||||
`Read more >> <https://github.com/aiogram/aiogram/issues/942>`_
|
||||
|
||||
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 <magic-filters>`
|
||||
|
||||
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 == self.chat_type
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
router.message.bind_filter(ChatType)
|
||||
|
||||
@router.message()
|
||||
async def my_handler(message: Message): ...
|
||||
.. literalinclude:: ../../../examples/own_filter.py
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
====
|
||||
=========
|
||||
MagicData
|
||||
====
|
||||
=========
|
||||
|
||||
.. autoclass:: aiogram.filters.magic_data.MagicData
|
||||
:members:
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
================
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 <magic-filters>`:
|
||||
: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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue