mirror of
https://github.com/aiogram/aiogram.git
synced 2026-04-08 16:37:47 +00:00
Update API, added some new features
This commit is contained in:
parent
c705858421
commit
7be5808136
34 changed files with 547 additions and 17 deletions
|
|
@ -2,6 +2,7 @@ from .client import session
|
|||
from .client.bot import Bot
|
||||
from .dispatcher import filters, handler
|
||||
from .dispatcher.dispatcher import Dispatcher
|
||||
from .dispatcher.flags.flags import FlagGenerator
|
||||
from .dispatcher.middlewares.base import BaseMiddleware
|
||||
from .dispatcher.router import Router
|
||||
from .utils.magic_filter import MagicFilter
|
||||
|
|
@ -18,6 +19,7 @@ except ImportError: # pragma: no cover
|
|||
F = MagicFilter()
|
||||
html = _html_decoration
|
||||
md = _markdown_decoration
|
||||
flags = FlagGenerator()
|
||||
|
||||
__all__ = (
|
||||
"__api_version__",
|
||||
|
|
@ -34,6 +36,7 @@ __all__ = (
|
|||
"F",
|
||||
"html",
|
||||
"md",
|
||||
"flags",
|
||||
)
|
||||
|
||||
__version__ = "3.0.0b1"
|
||||
|
|
|
|||
|
|
@ -533,6 +533,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
entities: Optional[List[MessageEntity]] = None,
|
||||
disable_web_page_preview: Optional[bool] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -551,6 +552,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param entities: A JSON-serialized list of special entities that appear in message text, which can be specified instead of *parse_mode*
|
||||
:param disable_web_page_preview: Disables link previews for links in this message
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -564,6 +566,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
entities=entities,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -576,6 +579,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
from_chat_id: Union[int, str],
|
||||
message_id: int,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
request_timeout: Optional[int] = None,
|
||||
) -> Message:
|
||||
"""
|
||||
|
|
@ -587,6 +591,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param from_chat_id: Unique identifier for the chat where the original message was sent (or channel username in the format :code:`@channelusername`)
|
||||
:param message_id: Message identifier in the chat specified in *from_chat_id*
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the forwarded message from forwarding and saving
|
||||
:param request_timeout: Request timeout
|
||||
:return: On success, the sent Message is returned.
|
||||
"""
|
||||
|
|
@ -595,6 +600,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
from_chat_id=from_chat_id,
|
||||
message_id=message_id,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
)
|
||||
return await self(call, request_timeout=request_timeout)
|
||||
|
||||
|
|
@ -607,6 +613,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode: Optional[str] = UNSET,
|
||||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -626,6 +633,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param parse_mode: Mode for parsing entities in the new caption. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
|
||||
:param caption_entities: A JSON-serialized list of special entities that appear in the new caption, which can be specified instead of *parse_mode*
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -640,6 +648,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -654,6 +663,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode: Optional[str] = UNSET,
|
||||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -672,6 +682,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param parse_mode: Mode for parsing entities in the photo caption. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
|
||||
:param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -685,6 +696,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -703,6 +715,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
title: Optional[str] = None,
|
||||
thumb: Optional[Union[InputFile, str]] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -726,6 +739,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param title: Track name
|
||||
:param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://<file_attach_name>' if the thumbnail was uploaded using multipart/form-data under <file_attach_name>. :ref:`More info on Sending Files » <sending-files>`
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -743,6 +757,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
title=title,
|
||||
thumb=thumb,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -759,6 +774,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
disable_content_type_detection: Optional[bool] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -779,6 +795,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
|
||||
:param disable_content_type_detection: Disables automatic server-side content type detection for files uploaded using multipart/form-data
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -794,6 +811,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities=caption_entities,
|
||||
disable_content_type_detection=disable_content_type_detection,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -813,6 +831,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
supports_streaming: Optional[bool] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -836,6 +855,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
|
||||
:param supports_streaming: Pass :code:`True`, if the uploaded video is suitable for streaming
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -854,6 +874,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities=caption_entities,
|
||||
supports_streaming=supports_streaming,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -872,6 +893,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode: Optional[str] = UNSET,
|
||||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -894,6 +916,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param parse_mode: Mode for parsing entities in the animation caption. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
|
||||
:param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -911,6 +934,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
parse_mode=parse_mode,
|
||||
caption_entities=caption_entities,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -926,6 +950,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities: Optional[List[MessageEntity]] = None,
|
||||
duration: Optional[int] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -945,6 +970,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param caption_entities: A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*
|
||||
:param duration: Duration of the voice message in seconds
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -959,6 +985,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
caption_entities=caption_entities,
|
||||
duration=duration,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -973,6 +1000,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
length: Optional[int] = None,
|
||||
thumb: Optional[Union[InputFile, str]] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -991,6 +1019,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param length: Video width and height, i.e. diameter of the video message
|
||||
:param thumb: Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://<file_attach_name>' if the thumbnail was uploaded using multipart/form-data under <file_attach_name>. :ref:`More info on Sending Files » <sending-files>`
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -1004,6 +1033,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
length=length,
|
||||
thumb=thumb,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -1015,6 +1045,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id: Union[int, str],
|
||||
media: List[Union[InputMediaAudio, InputMediaDocument, InputMediaPhoto, InputMediaVideo]],
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
request_timeout: Optional[int] = None,
|
||||
|
|
@ -1027,6 +1058,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
|
||||
:param media: A JSON-serialized array describing messages to be sent, must include 2-10 items
|
||||
:param disable_notification: Sends messages `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent messages from forwarding and saving
|
||||
:param reply_to_message_id: If the messages are a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param request_timeout: Request timeout
|
||||
|
|
@ -1036,6 +1068,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id=chat_id,
|
||||
media=media,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
)
|
||||
|
|
@ -1051,6 +1084,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
heading: Optional[int] = None,
|
||||
proximity_alert_radius: Optional[int] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -1071,6 +1105,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param heading: For live locations, a direction in which the user is moving, in degrees. Must be between 1 and 360 if specified.
|
||||
:param proximity_alert_radius: For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified.
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -1086,6 +1121,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
heading=heading,
|
||||
proximity_alert_radius=proximity_alert_radius,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -1177,6 +1213,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
google_place_id: Optional[str] = None,
|
||||
google_place_type: Optional[str] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -1199,6 +1236,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param google_place_id: Google Places identifier of the venue
|
||||
:param google_place_type: Google Places type of the venue. (See `supported types <https://developers.google.com/places/web-service/supported_types>`_.)
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -1216,6 +1254,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
google_place_id=google_place_id,
|
||||
google_place_type=google_place_type,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -1230,6 +1269,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
last_name: Optional[str] = None,
|
||||
vcard: Optional[str] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -1248,6 +1288,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param last_name: Contact's last name
|
||||
:param vcard: Additional data about the contact in the form of a `vCard <https://en.wikipedia.org/wiki/VCard>`_, 0-2048 bytes
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove keyboard or to force a reply from the user.
|
||||
|
|
@ -1261,6 +1302,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
last_name=last_name,
|
||||
vcard=vcard,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -1283,6 +1325,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
close_date: Optional[Union[datetime.datetime, datetime.timedelta, int]] = None,
|
||||
is_closed: Optional[bool] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -1309,6 +1352,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param close_date: Point in time (Unix timestamp) when the poll will be automatically closed. Must be at least 5 and no more than 600 seconds in the future. Can't be used together with *open_period*.
|
||||
:param is_closed: Pass :code:`True`, if the poll needs to be immediately closed. This can be useful for poll preview.
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -1330,6 +1374,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
close_date=close_date,
|
||||
is_closed=is_closed,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -1341,6 +1386,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id: Union[int, str],
|
||||
emoji: Optional[str] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -1356,6 +1402,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
|
||||
:param emoji: Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', '🎳', or '🎰'. Dice can have values 1-6 for '🎲', '🎯' and '🎳', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲'
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -1366,6 +1413,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id=chat_id,
|
||||
emoji=emoji,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -2512,6 +2560,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id: Union[int, str],
|
||||
sticker: Union[InputFile, str],
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[
|
||||
|
|
@ -2527,6 +2576,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param chat_id: Unique identifier for the target chat or username of the target channel (in the format :code:`@channelusername`)
|
||||
:param sticker: Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data. :ref:`More info on Sending Files » <sending-files>`
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: Additional interface options. A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_, `custom reply keyboard <https://core.telegram.org/bots#keyboards>`_, instructions to remove reply keyboard or to force a reply from the user.
|
||||
|
|
@ -2537,6 +2587,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id=chat_id,
|
||||
sticker=sticker,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -2798,6 +2849,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
send_email_to_provider: Optional[bool] = None,
|
||||
is_flexible: Optional[bool] = None,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
|
|
@ -2831,6 +2883,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param send_email_to_provider: Pass :code:`True`, if user's email address should be sent to provider
|
||||
:param is_flexible: Pass :code:`True`, if the final price depends on the shipping method
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_. If empty, one 'Pay :code:`total price`' button will be shown. If not empty, the first button must be a Pay button.
|
||||
|
|
@ -2861,6 +2914,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
send_email_to_provider=send_email_to_provider,
|
||||
is_flexible=is_flexible,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
@ -2960,6 +3014,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id: int,
|
||||
game_short_name: str,
|
||||
disable_notification: Optional[bool] = None,
|
||||
protect_content: Optional[bool] = None,
|
||||
reply_to_message_id: Optional[int] = None,
|
||||
allow_sending_without_reply: Optional[bool] = None,
|
||||
reply_markup: Optional[InlineKeyboardMarkup] = None,
|
||||
|
|
@ -2973,6 +3028,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
:param chat_id: Unique identifier for the target chat
|
||||
:param game_short_name: Short name of the game, serves as the unique identifier for the game. Set up your games via `Botfather <https://t.me/botfather>`_.
|
||||
:param disable_notification: Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound.
|
||||
:param protect_content: Protects the contents of the sent message from forwarding and saving
|
||||
:param reply_to_message_id: If the message is a reply, ID of the original message
|
||||
:param allow_sending_without_reply: Pass :code:`True`, if the message should be sent even if the specified replied-to message is not found
|
||||
:param reply_markup: A JSON-serialized object for an `inline keyboard <https://core.telegram.org/bots#inline-keyboards-and-on-the-fly-updating>`_. If empty, one 'Play game_title' button will be shown. If not empty, the first button must launch the game.
|
||||
|
|
@ -2983,6 +3039,7 @@ class Bot(ContextInstanceMixin["Bot"]):
|
|||
chat_id=chat_id,
|
||||
game_short_name=game_short_name,
|
||||
disable_notification=disable_notification,
|
||||
protect_content=protect_content,
|
||||
reply_to_message_id=reply_to_message_id,
|
||||
allow_sending_without_reply=allow_sending_without_reply,
|
||||
reply_markup=reply_markup,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from typing import Any, Awaitable, Callable, Dict, List, Optional, Tuple, Type,
|
|||
from magic_filter import MagicFilter
|
||||
|
||||
from aiogram.dispatcher.filters.base import BaseFilter
|
||||
from aiogram.dispatcher.flags.getter import extract_flags_from_object
|
||||
from aiogram.dispatcher.handler.base import BaseHandler
|
||||
|
||||
CallbackType = Callable[..., Awaitable[Any]]
|
||||
|
|
@ -71,6 +72,7 @@ class HandlerObject(CallableMixin):
|
|||
callback = inspect.unwrap(self.callback)
|
||||
if inspect.isclass(callback) and issubclass(callback, BaseHandler):
|
||||
self.awaitable = True
|
||||
self.flags.update(extract_flags_from_object(callback))
|
||||
|
||||
async def check(self, *args: Any, **kwargs: Any) -> Tuple[bool, Dict[str, Any]]:
|
||||
if not self.filters:
|
||||
|
|
|
|||
0
aiogram/dispatcher/flags/__init__.py
Normal file
0
aiogram/dispatcher/flags/__init__.py
Normal file
56
aiogram/dispatcher/flags/flags.py
Normal file
56
aiogram/dispatcher/flags/flags.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
from dataclasses import dataclass
|
||||
from typing import Any, Callable, Optional, Union, cast, overload
|
||||
|
||||
from magic_filter import AttrDict
|
||||
|
||||
from aiogram.dispatcher.flags.getter import extract_flags_from_object
|
||||
|
||||
|
||||
@dataclass
|
||||
class Flag:
|
||||
name: str
|
||||
value: Any
|
||||
|
||||
|
||||
@dataclass
|
||||
class FlagDecorator:
|
||||
flag: Flag
|
||||
|
||||
def with_value(self, value: Any) -> "FlagDecorator":
|
||||
new_flag = Flag(self.flag.name, value)
|
||||
return type(self)(new_flag)
|
||||
|
||||
@overload
|
||||
def __call__(self, value: Callable[..., Any]) -> Callable[..., Any]: # type: ignore
|
||||
pass
|
||||
|
||||
@overload
|
||||
def __call__(self, value: Any) -> "FlagDecorator":
|
||||
pass
|
||||
|
||||
@overload
|
||||
def __call__(self, **kwargs: Any) -> "FlagDecorator":
|
||||
pass
|
||||
|
||||
def __call__(
|
||||
self,
|
||||
value: Optional[Any] = None,
|
||||
**kwargs: Any,
|
||||
) -> Union[Callable[..., Any], "FlagDecorator"]:
|
||||
if value and kwargs:
|
||||
raise ValueError("The arguments `value` and **kwargs can not be used together")
|
||||
|
||||
if value is not None and callable(value):
|
||||
value.aiogram_flag = {
|
||||
**extract_flags_from_object(value),
|
||||
self.flag.name: self.flag.value,
|
||||
}
|
||||
return cast(Callable[..., Any], value)
|
||||
return self.with_value(AttrDict(kwargs) if value is None else value)
|
||||
|
||||
|
||||
class FlagGenerator:
|
||||
def __getattr__(self, name: str) -> FlagDecorator:
|
||||
if name[0] == "_":
|
||||
raise AttributeError("Flag name must NOT start with underscore")
|
||||
return FlagDecorator(Flag(name, True))
|
||||
35
aiogram/dispatcher/flags/getter.py
Normal file
35
aiogram/dispatcher/flags/getter.py
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
from typing import TYPE_CHECKING, Any, Dict, Optional, Union, cast
|
||||
|
||||
from magic_filter import AttrDict, MagicFilter
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from aiogram.dispatcher.event.handler import HandlerObject
|
||||
|
||||
|
||||
def extract_flags_from_object(obj: Any) -> Dict[str, Any]:
|
||||
if not hasattr(obj, "aiogram_flag"):
|
||||
return {}
|
||||
return cast(Dict[str, Any], obj.aiogram_flag)
|
||||
|
||||
|
||||
def extract_flags(handler: Union["HandlerObject", Dict[str, Any]]) -> Dict[str, Any]:
|
||||
if isinstance(handler, dict) and "handler" in handler:
|
||||
handler = handler["handler"]
|
||||
if not hasattr(handler, "flags"):
|
||||
return {}
|
||||
return handler.flags # type: ignore
|
||||
|
||||
|
||||
def get_flag(
|
||||
handler: Union["HandlerObject", Dict[str, Any]],
|
||||
name: str,
|
||||
*,
|
||||
default: Optional[Any] = None,
|
||||
) -> Any:
|
||||
flags = extract_flags(handler)
|
||||
return flags.get(name, default)
|
||||
|
||||
|
||||
def check_flags(handler: Union["HandlerObject", Dict[str, Any]], magic: MagicFilter) -> Any:
|
||||
flags = extract_flags(handler)
|
||||
return magic.resolve(AttrDict(flags))
|
||||
|
|
@ -134,7 +134,7 @@ class BaseRequestHandler(ABC):
|
|||
bot=bot, update=await request.json(loads=bot.session.json_loads)
|
||||
)
|
||||
)
|
||||
return web.json_response({})
|
||||
return web.json_response({}, dumps=bot.session.json_dumps)
|
||||
|
||||
async def _handle_request(self, bot: Bot, request: web.Request) -> web.Response:
|
||||
result = await self.dispatcher.feed_webhook_update(
|
||||
|
|
@ -143,8 +143,8 @@ class BaseRequestHandler(ABC):
|
|||
**self.data,
|
||||
)
|
||||
if result:
|
||||
return web.json_response(result)
|
||||
return web.json_response({})
|
||||
return web.json_response(result, dumps=bot.session.json_dumps)
|
||||
return web.json_response({}, dumps=bot.session.json_dumps)
|
||||
|
||||
async def handle(self, request: web.Request) -> web.Response:
|
||||
bot = await self.resolve_bot(request)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class CopyMessage(TelegramMethod[MessageId]):
|
|||
"""A JSON-serialized list of special entities that appear in the new caption, which can be specified instead of *parse_mode*"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ class ForwardMessage(TelegramMethod[Message]):
|
|||
"""Message identifier in the chat specified in *from_chat_id*"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the forwarded message from forwarding and saving"""
|
||||
|
||||
def build_request(self, bot: Bot) -> Request:
|
||||
data: Dict[str, Any] = self.dict()
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class SendAnimation(TelegramMethod[Message]):
|
|||
"""A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ class SendAudio(TelegramMethod[Message]):
|
|||
"""Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://<file_attach_name>' if the thumbnail was uploaded using multipart/form-data under <file_attach_name>. :ref:`More info on Sending Files » <sending-files>`"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -36,6 +36,8 @@ class SendContact(TelegramMethod[Message]):
|
|||
"""Additional data about the contact in the form of a `vCard <https://en.wikipedia.org/wiki/VCard>`_, 0-2048 bytes"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ class SendDice(TelegramMethod[Message]):
|
|||
"""Emoji on which the dice throw animation is based. Currently, must be one of '🎲', '🎯', '🏀', '⚽', '🎳', or '🎰'. Dice can have values 1-6 for '🎲', '🎯' and '🎳', values 1-5 for '🏀' and '⚽', and values 1-64 for '🎰'. Defaults to '🎲'"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ class SendDocument(TelegramMethod[Message]):
|
|||
"""Disables automatic server-side content type detection for files uploaded using multipart/form-data"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ class SendGame(TelegramMethod[Message]):
|
|||
"""Short name of the game, serves as the unique identifier for the game. Set up your games via `Botfather <https://t.me/botfather>`_."""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ class SendInvoice(TelegramMethod[Message]):
|
|||
"""Pass :code:`True`, if the final price depends on the shipping method"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class SendLocation(TelegramMethod[Message]):
|
|||
"""For live locations, a maximum distance for proximity alerts about approaching another chat member, in meters. Must be between 1 and 100000 if specified."""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ class SendMediaGroup(TelegramMethod[List[Message]]):
|
|||
"""A JSON-serialized array describing messages to be sent, must include 2-10 items"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends messages `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent messages from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the messages are a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ class SendMessage(TelegramMethod[Message]):
|
|||
"""Disables link previews for links in this message"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@ class SendPhoto(TelegramMethod[Message]):
|
|||
"""A JSON-serialized list of special entities that appear in the caption, which can be specified instead of *parse_mode*"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ class SendPoll(TelegramMethod[Message]):
|
|||
"""Pass :code:`True`, if the poll needs to be immediately closed. This can be useful for poll preview."""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@ class SendSticker(TelegramMethod[Message]):
|
|||
"""Sticker to send. Pass a file_id as String to send a file that exists on the Telegram servers (recommended), pass an HTTP URL as a String for Telegram to get a .WEBP file from the Internet, or upload a new one using multipart/form-data. :ref:`More info on Sending Files » <sending-files>`"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ class SendVenue(TelegramMethod[Message]):
|
|||
"""Google Places type of the venue. (See `supported types <https://developers.google.com/places/web-service/supported_types>`_.)"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ class SendVideo(TelegramMethod[Message]):
|
|||
"""Pass :code:`True`, if the uploaded video is suitable for streaming"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ class SendVideoNote(TelegramMethod[Message]):
|
|||
"""Thumbnail of the file sent; can be ignored if thumbnail generation for the file is supported server-side. The thumbnail should be in JPEG format and less than 200 kB in size. A thumbnail's width and height should not exceed 320. Ignored if the file is not uploaded using multipart/form-data. Thumbnails can't be reused and can be only uploaded as a new file, so you can pass 'attach://<file_attach_name>' if the thumbnail was uploaded using multipart/form-data under <file_attach_name>. :ref:`More info on Sending Files » <sending-files>`"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ class SendVoice(TelegramMethod[Message]):
|
|||
"""Duration of the voice message in seconds"""
|
||||
disable_notification: Optional[bool] = None
|
||||
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
|
||||
protect_content: Optional[bool] = None
|
||||
"""Protects the contents of the sent message from forwarding and saving"""
|
||||
reply_to_message_id: Optional[int] = None
|
||||
"""If the message is a reply, ID of the original message"""
|
||||
allow_sending_without_reply: Optional[bool] = None
|
||||
|
|
|
|||
|
|
@ -11,6 +11,6 @@ class BotCommand(MutableTelegramObject):
|
|||
"""
|
||||
|
||||
command: str
|
||||
"""Text of the command, 1-32 characters. Can contain only lowercase English letters, digits and underscores."""
|
||||
"""Text of the command; 1-32 characters. Can contain only lowercase English letters, digits and underscores."""
|
||||
description: str
|
||||
"""Description of the command, 3-256 characters."""
|
||||
"""Description of the command; 1-256 characters."""
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class Message(TelegramObject):
|
|||
forward_from_message_id: Optional[int] = None
|
||||
"""*Optional*. For messages forwarded from channels, identifier of the original message in the channel"""
|
||||
forward_signature: Optional[str] = None
|
||||
"""*Optional*. For messages forwarded from channels, signature of the post author if present"""
|
||||
"""*Optional*. For forwarded messages that were originally sent in channels or by an anonymous chat administrator, signature of the message sender if present"""
|
||||
forward_sender_name: Optional[str] = None
|
||||
"""*Optional*. Sender's name for messages forwarded from users who disallow adding a link to their account in forwarded messages"""
|
||||
forward_date: Optional[int] = None
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class MessageEntity(MutableTelegramObject):
|
|||
"""
|
||||
|
||||
type: str
|
||||
"""Type of the entity. Can be 'mention' (:code:`@username`), 'hashtag' (:code:`#hashtag`), 'cashtag' (:code:`$USD`), 'bot_command' (:code:`/start@jobs_bot`), 'url' (:code:`https://telegram.org`), 'email' (:code:`do-not-reply@telegram.org`), 'phone_number' (:code:`+1-212-555-0123`), 'bold' (**bold text**), 'italic' (*italic text*), 'underline' (underlined text), 'strikethrough' (strikethrough text), 'code' (monowidth string), 'pre' (monowidth block), 'text_link' (for clickable text URLs), 'text_mention' (for users `without usernames <https://telegram.org/blog/edit#new-mentions>`_)"""
|
||||
"""Type of the entity. Currently, can be 'mention' (:code:`@username`), 'hashtag' (:code:`#hashtag`), 'cashtag' (:code:`$USD`), 'bot_command' (:code:`/start@jobs_bot`), 'url' (:code:`https://telegram.org`), 'email' (:code:`do-not-reply@telegram.org`), 'phone_number' (:code:`+1-212-555-0123`), 'bold' (**bold text**), 'italic' (*italic text*), 'underline' (underlined text), 'strikethrough' (strikethrough text), 'spoiler' (spoiler message), 'code' (monowidth string), 'pre' (monowidth block), 'text_link' (for clickable text URLs), 'text_mention' (for users `without usernames <https://telegram.org/blog/edit#new-mentions>`_)"""
|
||||
offset: int
|
||||
"""Offset in UTF-16 code units to the start of the entity"""
|
||||
length: int
|
||||
|
|
|
|||
298
aiogram/utils/chat_action.py
Normal file
298
aiogram/utils/chat_action.py
Normal file
|
|
@ -0,0 +1,298 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
from asyncio import Event, Lock
|
||||
from contextlib import suppress
|
||||
from types import TracebackType
|
||||
from typing import Any, Awaitable, Callable, Dict, Optional, Type, Union
|
||||
|
||||
from aiogram import BaseMiddleware, Bot
|
||||
from aiogram.dispatcher.flags.getter import get_flag
|
||||
from aiogram.types import Message, TelegramObject
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
DEFAULT_INTERVAL = 5.0
|
||||
DEFAULT_INITIAL_SLEEP = 0.1
|
||||
|
||||
|
||||
class ChatActionSender:
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
chat_id: Union[str, int],
|
||||
action: str = "typing",
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INTERVAL,
|
||||
bot: Optional[Bot] = None,
|
||||
) -> None:
|
||||
if bot is None:
|
||||
bot = Bot.get_current(False)
|
||||
self.chat_id = chat_id
|
||||
self.action = action
|
||||
self.interval = interval
|
||||
self.initial_sleep = initial_sleep
|
||||
self.bot = bot
|
||||
|
||||
self._close_event = Event()
|
||||
self._running = False
|
||||
self._lock = Lock()
|
||||
|
||||
async def _worker(self) -> None:
|
||||
logger.debug(
|
||||
"Started chat action %r sender in chat_id=%s via bot id=%d",
|
||||
self.action,
|
||||
self.chat_id,
|
||||
self.bot.id,
|
||||
)
|
||||
try:
|
||||
counter = 0
|
||||
await asyncio.sleep(self.initial_sleep)
|
||||
while not self._close_event.is_set():
|
||||
start = time.monotonic()
|
||||
logger.debug(
|
||||
"Sent chat action %r to chat_id=%s via bot %d (already sent actions %d)",
|
||||
self.action,
|
||||
self.chat_id,
|
||||
self.bot.id,
|
||||
counter,
|
||||
)
|
||||
await self.bot.send_chat_action(chat_id=self.chat_id, action=self.action)
|
||||
counter += 1
|
||||
|
||||
interval = self.interval - (time.monotonic() - start)
|
||||
with suppress(asyncio.TimeoutError):
|
||||
await asyncio.wait_for(self._close_event.wait(), interval)
|
||||
finally:
|
||||
logger.debug(
|
||||
"Finished chat action %r sender in chat_id=%s via bot id=%d",
|
||||
self.action,
|
||||
self.chat_id,
|
||||
self.bot.id,
|
||||
)
|
||||
self._running = False
|
||||
|
||||
async def _run(self) -> None:
|
||||
async with self._lock:
|
||||
if self._running:
|
||||
raise RuntimeError("Already running")
|
||||
asyncio.create_task(self._worker())
|
||||
|
||||
def _stop(self) -> None:
|
||||
if not self._close_event.is_set():
|
||||
self._close_event.set()
|
||||
|
||||
async def __aenter__(self) -> "ChatActionSender":
|
||||
await self._run()
|
||||
return self
|
||||
|
||||
async def __aexit__(
|
||||
self,
|
||||
exc_type: Optional[Type[BaseException]],
|
||||
exc_value: Optional[BaseException],
|
||||
traceback: Optional[TracebackType],
|
||||
) -> Any:
|
||||
self._stop()
|
||||
|
||||
@classmethod
|
||||
def typing(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="typing",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def upload_photo(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="upload_photo",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def record_video(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="record_video",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def upload_video(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="upload_video",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def record_voice(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="record_voice",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def upload_voice(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="upload_voice",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def upload_document(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="upload_document",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def choose_sticker(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="choose_sticker",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def find_location(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="find_location",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def record_video_note(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="record_video_note",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def upload_video_note(
|
||||
cls,
|
||||
bot: Bot,
|
||||
chat_id: Union[int, str],
|
||||
interval: float = DEFAULT_INTERVAL,
|
||||
initial_sleep: float = DEFAULT_INITIAL_SLEEP,
|
||||
) -> "ChatActionSender":
|
||||
return cls(
|
||||
bot=bot,
|
||||
chat_id=chat_id,
|
||||
action="upload_video_note",
|
||||
interval=interval,
|
||||
initial_sleep=initial_sleep,
|
||||
)
|
||||
|
||||
|
||||
class ChatActionMiddleware(BaseMiddleware):
|
||||
async def __call__(
|
||||
self,
|
||||
handler: Callable[[TelegramObject, Dict[str, Any]], Awaitable[Any]],
|
||||
event: TelegramObject,
|
||||
data: Dict[str, Any],
|
||||
) -> Any:
|
||||
if not isinstance(event, Message):
|
||||
return await handler(event, data)
|
||||
bot = data["bot"]
|
||||
|
||||
chat_action = get_flag(data, "chat_action")
|
||||
kwargs = {}
|
||||
if isinstance(chat_action, dict):
|
||||
if initial_sleep := chat_action.get("initial_sleep"):
|
||||
kwargs["initial_sleep"] = initial_sleep
|
||||
if interval := chat_action.get("interval"):
|
||||
kwargs["interval"] = interval
|
||||
if action := chat_action.get("action"):
|
||||
kwargs["action"] = action
|
||||
elif isinstance(chat_action, bool):
|
||||
kwargs["action"] = "typing"
|
||||
else:
|
||||
kwargs["action"] = chat_action
|
||||
async with ChatActionSender(bot=bot, chat_id=event.chat.id, **kwargs):
|
||||
return await handler(event, data)
|
||||
|
|
@ -2,10 +2,14 @@ from abc import ABC, abstractmethod
|
|||
from typing import Any, Awaitable, Callable, Dict, Optional, Set, cast
|
||||
|
||||
try:
|
||||
from babel import Locale
|
||||
from babel import Locale, UnknownLocaleError
|
||||
except ImportError: # pragma: no cover
|
||||
Locale = None
|
||||
|
||||
class UnknownLocaleError(Exception): # type: ignore
|
||||
pass
|
||||
|
||||
|
||||
from aiogram import BaseMiddleware, Router
|
||||
from aiogram.dispatcher.fsm.context import FSMContext
|
||||
from aiogram.types import TelegramObject, User
|
||||
|
|
@ -116,7 +120,11 @@ class SimpleI18nMiddleware(I18nMiddleware):
|
|||
event_from_user: Optional[User] = data.get("event_from_user", None)
|
||||
if event_from_user is None:
|
||||
return self.i18n.default_locale
|
||||
locale = Locale.parse(event_from_user.language_code, sep="-")
|
||||
try:
|
||||
locale = Locale.parse(event_from_user.language_code, sep="-")
|
||||
except UnknownLocaleError:
|
||||
return self.i18n.default_locale
|
||||
|
||||
if locale.language not in self.i18n.available_locales:
|
||||
return self.i18n.default_locale
|
||||
return cast(str, locale.language)
|
||||
|
|
|
|||
46
poetry.lock
generated
46
poetry.lock
generated
|
|
@ -212,7 +212,7 @@ name = "certifi"
|
|||
version = "2021.10.8"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[[package]]
|
||||
|
|
@ -917,7 +917,7 @@ pytest = ">=3.5"
|
|||
|
||||
[[package]]
|
||||
name = "python-socks"
|
||||
version = "2.0.0"
|
||||
version = "2.0.2"
|
||||
description = "Core proxy (SOCKS4, SOCKS5, HTTP tunneling) functionality for Python"
|
||||
category = "main"
|
||||
optional = true
|
||||
|
|
@ -974,6 +974,36 @@ urllib3 = ">=1.21.1,<1.27"
|
|||
socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"]
|
||||
use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"]
|
||||
|
||||
[[package]]
|
||||
name = "sentry-sdk"
|
||||
version = "1.5.3"
|
||||
description = "Python client for Sentry (https://sentry.io)"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
|
||||
[package.dependencies]
|
||||
certifi = "*"
|
||||
urllib3 = ">=1.10.0"
|
||||
|
||||
[package.extras]
|
||||
aiohttp = ["aiohttp (>=3.5)"]
|
||||
beam = ["apache-beam (>=2.12)"]
|
||||
bottle = ["bottle (>=0.12.13)"]
|
||||
celery = ["celery (>=3)"]
|
||||
chalice = ["chalice (>=1.16.0)"]
|
||||
django = ["django (>=1.8)"]
|
||||
falcon = ["falcon (>=1.4)"]
|
||||
flask = ["flask (>=0.11)", "blinker (>=1.1)"]
|
||||
httpx = ["httpx (>=0.16.0)"]
|
||||
pure_eval = ["pure-eval", "executing", "asttokens"]
|
||||
pyspark = ["pyspark (>=2.4.4)"]
|
||||
quart = ["quart (>=0.16.1)", "blinker (>=1.1)"]
|
||||
rq = ["rq (>=0.6)"]
|
||||
sanic = ["sanic (>=0.8)"]
|
||||
sqlalchemy = ["sqlalchemy (>=1.2)"]
|
||||
tornado = ["tornado (>=5)"]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
|
|
@ -1242,7 +1272,7 @@ name = "urllib3"
|
|||
version = "1.26.7"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = true
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -1324,7 +1354,7 @@ redis = ["aioredis"]
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.8"
|
||||
content-hash = "27d602728b6dab256d184fbd44953030676edf320652ad828c6e1b4beaa80f8b"
|
||||
content-hash = "678dbb9bbf362c01757842a977f7b0f0f65638a657e3599b6125f0f4e42f4b6c"
|
||||
|
||||
[metadata.files]
|
||||
aiofiles = [
|
||||
|
|
@ -2003,8 +2033,8 @@ pytest-mypy = [
|
|||
{file = "pytest_mypy-0.8.1-py3-none-any.whl", hash = "sha256:6e68e8eb7ceeb7d1c83a1590912f784879f037b51adfb9c17b95c6b2fc57466b"},
|
||||
]
|
||||
python-socks = [
|
||||
{file = "python-socks-2.0.0.tar.gz", hash = "sha256:7944dad882846ac73e5f79e180c841e3895ee058e16855b7e8fff24f4cd0b90b"},
|
||||
{file = "python_socks-2.0.0-py3-none-any.whl", hash = "sha256:aac65671cbd3b0eb55b20f8558c8de3894a315536aaab3ec0a7b9d46ff89c1bf"},
|
||||
{file = "python-socks-2.0.2.tar.gz", hash = "sha256:aa9b7a53e81ae6b6e3ada602761012e470ea1c4cbcd5548f99b3fc102dce4fca"},
|
||||
{file = "python_socks-2.0.2-py3-none-any.whl", hash = "sha256:faa46857c79a8bf7def2e904ac839fb56755d7ab76c4cad12a131a85fec07241"},
|
||||
]
|
||||
pytz = [
|
||||
{file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"},
|
||||
|
|
@ -2100,6 +2130,10 @@ requests = [
|
|||
{file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"},
|
||||
{file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"},
|
||||
]
|
||||
sentry-sdk = [
|
||||
{file = "sentry-sdk-1.5.3.tar.gz", hash = "sha256:141da032f0fa4c56f9af6b361fda57360af1789576285bd1944561f9c274f9c0"},
|
||||
{file = "sentry_sdk-1.5.3-py2.py3-none-any.whl", hash = "sha256:9aeff2a47f4038460296b920bf4d269284e8454e1c67547ee002ccafd9c2442b"},
|
||||
]
|
||||
six = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ toml = "^0.10.2"
|
|||
pre-commit = "^2.15.0"
|
||||
packaging = "^20.3"
|
||||
typing-extensions = "^3.7.4"
|
||||
sentry-sdk = "^1.5.3"
|
||||
|
||||
|
||||
[tool.poetry.extras]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
from typing import Literal
|
||||
|
||||
import pytest
|
||||
|
||||
from aiogram.dispatcher.fsm.storage.base import DEFAULT_DESTINY, StorageKey
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue