Added support for Telegram Bot API 9.6

This commit is contained in:
sycho 2026-04-04 03:40:42 +08:00
parent 00c1130938
commit 985fe5dab3
No known key found for this signature in database
GPG key ID: 04B385DB0C97A01E
41 changed files with 696 additions and 71 deletions

View file

@ -1 +1 @@
9.5
9.6

View file

@ -49,3 +49,4 @@ extract:
- reply_to_checklist_task_id
- suggested_post_info
- is_paid_post
- reply_to_poll_option_id

View file

@ -1,3 +1,4 @@
explanation_parse_mode: parse_mode
question_parse_mode: parse_mode
description_parse_mode: parse_mode
protect_content: protect_content

View file

@ -1,7 +1,7 @@
{
"api": {
"version": "9.5",
"release_date": "2026-03-01"
"version": "9.6",
"release_date": "2026-04-03"
},
"items": [
{

View file

@ -0,0 +1,5 @@
annotations:
addition_date:
parsed_type:
type: std
name: DateTime

23
CHANGES/1793.misc.rst Normal file
View file

@ -0,0 +1,23 @@
Updated to `Bot API 9.6 <https://core.telegram.org/bots/api-changelog#april-3-2026>`_
**Managed Bots:**
- Added :class:`aiogram.types.managed_bot_updated.ManagedBotUpdated` and :class:`aiogram.types.managed_bot_created.ManagedBotCreated` types
- Added :class:`aiogram.types.keyboard_button_request_managed_bot.KeyboardButtonRequestManagedBot` type and :code:`request_managed_bot` field to :class:`aiogram.types.keyboard_button.KeyboardButton`
- Added :class:`aiogram.types.prepared_keyboard_button.PreparedKeyboardButton` type
- Added :class:`aiogram.methods.get_managed_bot_token.GetManagedBotToken`, :class:`aiogram.methods.replace_managed_bot_token.ReplaceManagedBotToken`, and :class:`aiogram.methods.save_prepared_keyboard_button.SavePreparedKeyboardButton` methods
- Added :code:`managed_bot` field to :class:`aiogram.types.update.Update`
- Added :code:`managed_bot_created` field to :class:`aiogram.types.message.Message`
- Added :code:`can_manage_bots` field to :class:`aiogram.types.user.User`
**Polls:**
- Replaced :code:`correct_option_id` with :code:`correct_option_ids` in :class:`aiogram.types.poll.Poll` and :class:`aiogram.methods.send_poll.SendPoll` — quizzes now support multiple correct answers
- Added :code:`allows_revoting`, :code:`description`, :code:`description_entities` fields to :class:`aiogram.types.poll.Poll`
- Added :code:`persistent_id`, :code:`added_by_user`, :code:`added_by_chat`, :code:`addition_date` fields to :class:`aiogram.types.poll_option.PollOption`
- Added :code:`option_persistent_ids` field to :class:`aiogram.types.poll_answer.PollAnswer`
- Added :code:`allows_revoting`, :code:`shuffle_options`, :code:`allow_adding_options`, :code:`hide_results_until_closes`, :code:`description`, :code:`description_parse_mode`, :code:`description_entities` parameters to :class:`aiogram.methods.send_poll.SendPoll`
- Added :class:`aiogram.types.poll_option_added.PollOptionAdded` and :class:`aiogram.types.poll_option_deleted.PollOptionDeleted` types
- Added :code:`poll_option_added`, :code:`poll_option_deleted`, :code:`reply_to_poll_option_id` fields to :class:`aiogram.types.message.Message`
- Added :code:`poll_option_id` field to :class:`aiogram.types.reply_parameters.ReplyParameters`
- Maximum poll duration increased to 2,628,000 seconds (~30.4 days)

View file

@ -52,7 +52,7 @@ Features
- Asynchronous (`asyncio docs <https://docs.python.org/3/library/asyncio.html>`_, :pep:`492`)
- Has type hints (:pep:`484`) and can be used with `mypy <http://mypy-lang.org/>`_
- Supports `PyPy <https://www.pypy.org/>`_
- Supports `Telegram Bot API 9.5 <https://core.telegram.org/bots/api>`_ and gets fast updates to the latest versions of the Bot API
- Supports `Telegram Bot API 9.6 <https://core.telegram.org/bots/api>`_ and gets fast updates to the latest versions of the Bot API
- Telegram Bot API integration code was `autogenerated <https://github.com/aiogram/tg-codegen>`_ and can be easily re-generated when API gets updated
- Updates router (Blueprints)
- Has Finite State Machine

View file

@ -1,2 +1,2 @@
__version__ = "3.26.0"
__api_version__ = "9.5"
__version__ = "3.27.0"
__api_version__ = "9.6"

View file

@ -80,6 +80,7 @@ from ..methods import (
GetFile,
GetForumTopicIconStickers,
GetGameHighScores,
GetManagedBotToken,
GetMe,
GetMyCommands,
GetMyDefaultAdministratorRights,
@ -110,11 +111,13 @@ from ..methods import (
RemoveUserVerification,
ReopenForumTopic,
ReopenGeneralForumTopic,
ReplaceManagedBotToken,
ReplaceStickerInSet,
RepostStory,
RestrictChatMember,
RevokeChatInviteLink,
SavePreparedInlineMessage,
SavePreparedKeyboardButton,
SendAnimation,
SendAudio,
SendChatAction,
@ -216,6 +219,7 @@ from ..types import (
InputProfilePhotoUnion,
InputSticker,
InputStoryContentUnion,
KeyboardButton,
LabeledPrice,
LinkPreviewOptions,
MaskPosition,
@ -228,6 +232,7 @@ from ..types import (
PassportElementErrorUnion,
Poll,
PreparedInlineMessage,
PreparedKeyboardButton,
ReactionTypeUnion,
ReplyMarkupUnion,
ReplyParameters,
@ -1797,6 +1802,46 @@ class Bot:
call = GetMe()
return await self(call, request_timeout=request_timeout)
async def get_managed_bot_token(
self,
user_id: int,
request_timeout: int | None = None,
) -> str:
"""
Use this method to get the token of a managed bot. Returns the token as *String* on success.
Source: https://core.telegram.org/bots/api#getmanagedbottoken
:param user_id: User identifier of the managed bot whose token will be returned
:param request_timeout: Request timeout
:return: Returns the token as *String* on success.
"""
call = GetManagedBotToken(
user_id=user_id,
)
return await self(call, request_timeout=request_timeout)
async def replace_managed_bot_token(
self,
user_id: int,
request_timeout: int | None = None,
) -> str:
"""
Use this method to revoke the current token of a managed bot and generate a new one. Returns the new token as *String* on success.
Source: https://core.telegram.org/bots/api#replacemanagedbottoken
:param user_id: User identifier of the managed bot whose token will be replaced
:param request_timeout: Request timeout
:return: Returns the new token as *String* on success.
"""
call = ReplaceManagedBotToken(
user_id=user_id,
)
return await self(call, request_timeout=request_timeout)
async def get_my_commands(
self,
scope: BotCommandScopeUnion | None = None,
@ -3008,13 +3053,20 @@ class Bot:
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
allows_revoting: bool | None = None,
shuffle_options: bool | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
open_period: int | None = None,
close_date: DateTimeUnion | None = None,
is_closed: bool | None = None,
description: str | None = None,
description_parse_mode: str | Default | None = Default("parse_mode"),
description_entities: list[MessageEntity] | None = None,
disable_notification: bool | None = None,
protect_content: bool | Default | None = Default("protect_content"),
allow_paid_broadcast: bool | None = None,
@ -3040,13 +3092,20 @@ class Bot:
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param allows_revoting: Pass :code:`True`, if the poll allows to change chosen answer options
:param shuffle_options: Pass :code:`True`, if the poll options must be shown in random order
:param allow_adding_options: Pass :code:`True`, if answer options can be added to the poll after creation
:param hide_results_until_closes: Pass :code:`True`, if poll results must be shown only after the poll closes
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
:param open_period: Amount of time in seconds the poll will be active after creation, 5-600. Can't be used together with *close_date*.
: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 open_period: Amount of time in seconds the poll will be active after creation, 5-2628000. Can't be used together with *close_date*.
:param close_date: Point in time (Unix timestamp) when the poll will be automatically closed. Must be at least 5 and no more than 2628000 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 description: Description of the poll to be sent, 0-1024 characters after entities parsing
:param description_parse_mode: Mode for parsing entities in the poll description.
:param description_entities: A JSON-serialized list of special entities that appear in the poll description
: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 allow_paid_broadcast: Pass :code:`True` to allow up to 1000 messages per second, ignoring `broadcasting limits <https://core.telegram.org/bots/faq#how-can-i-message-all-of-my-bot-39s-subscribers-at-once>`_ for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance
@ -3070,13 +3129,20 @@ class Bot:
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
allow_adding_options=allow_adding_options,
hide_results_until_closes=hide_results_until_closes,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,
open_period=open_period,
close_date=close_date,
is_closed=is_closed,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
disable_notification=disable_notification,
protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast,
@ -4883,6 +4949,29 @@ class Bot:
)
return await self(call, request_timeout=request_timeout)
async def save_prepared_keyboard_button(
self,
user_id: int,
button: KeyboardButton,
request_timeout: int | None = None,
) -> PreparedKeyboardButton:
"""
Stores a keyboard button that can be used by a user within a Mini App. Returns a :class:`aiogram.types.prepared_keyboard_button.PreparedKeyboardButton` object.
Source: https://core.telegram.org/bots/api#savepreparedkeyboardbutton
:param user_id: Unique identifier of the target user that can use the button
:param button: A JSON-serialized object describing the button to be saved. The button must be of the type *request_users*, *request_chat*, or *request_managed_bot*
:param request_timeout: Request timeout
:return: Returns a :class:`aiogram.types.prepared_keyboard_button.PreparedKeyboardButton` object.
"""
call = SavePreparedKeyboardButton(
user_id=user_id,
button=button,
)
return await self(call, request_timeout=request_timeout)
async def send_gift(
self,
gift_id: str,

View file

@ -183,4 +183,8 @@ class UserContextMiddleware(BaseMiddleware):
return EventContext(
user=event.purchased_paid_media.from_user,
)
if event.managed_bot:
return EventContext(
user=event.managed_bot.user,
)
return EventContext()

View file

@ -85,6 +85,7 @@ class Router:
router=self,
event_name="purchased_paid_media",
)
self.managed_bot = TelegramEventObserver(router=self, event_name="managed_bot")
self.errors = self.error = TelegramEventObserver(router=self, event_name="error")
@ -115,6 +116,7 @@ class Router:
"edited_business_message": self.edited_business_message,
"business_message": self.business_message,
"purchased_paid_media": self.purchased_paid_media,
"managed_bot": self.managed_bot,
"error": self.errors,
}

View file

@ -73,6 +73,9 @@ class ContentType(str, Enum):
SUGGESTED_POST_DECLINED = "suggested_post_declined"
SUGGESTED_POST_PAID = "suggested_post_paid"
SUGGESTED_POST_REFUNDED = "suggested_post_refunded"
MANAGED_BOT_CREATED = "managed_bot_created"
POLL_OPTION_ADDED = "poll_option_added"
POLL_OPTION_DELETED = "poll_option_deleted"
VIDEO_CHAT_SCHEDULED = "video_chat_scheduled"
VIDEO_CHAT_STARTED = "video_chat_started"
VIDEO_CHAT_ENDED = "video_chat_ended"

View file

@ -31,3 +31,4 @@ class UpdateType(str, Enum):
CHAT_JOIN_REQUEST = "chat_join_request"
CHAT_BOOST = "chat_boost"
REMOVED_CHAT_BOOST = "removed_chat_boost"
MANAGED_BOT = "managed_bot"

View file

@ -62,6 +62,7 @@ from .get_custom_emoji_stickers import GetCustomEmojiStickers
from .get_file import GetFile
from .get_forum_topic_icon_stickers import GetForumTopicIconStickers
from .get_game_high_scores import GetGameHighScores
from .get_managed_bot_token import GetManagedBotToken
from .get_me import GetMe
from .get_my_commands import GetMyCommands
from .get_my_default_administrator_rights import GetMyDefaultAdministratorRights
@ -92,11 +93,13 @@ from .remove_my_profile_photo import RemoveMyProfilePhoto
from .remove_user_verification import RemoveUserVerification
from .reopen_forum_topic import ReopenForumTopic
from .reopen_general_forum_topic import ReopenGeneralForumTopic
from .replace_managed_bot_token import ReplaceManagedBotToken
from .replace_sticker_in_set import ReplaceStickerInSet
from .repost_story import RepostStory
from .restrict_chat_member import RestrictChatMember
from .revoke_chat_invite_link import RevokeChatInviteLink
from .save_prepared_inline_message import SavePreparedInlineMessage
from .save_prepared_keyboard_button import SavePreparedKeyboardButton
from .send_animation import SendAnimation
from .send_audio import SendAudio
from .send_chat_action import SendChatAction
@ -231,6 +234,7 @@ __all__ = (
"GetForumTopicIconStickers",
"GetGameHighScores",
"GetMe",
"GetManagedBotToken",
"GetMyCommands",
"GetMyDefaultAdministratorRights",
"GetMyDescription",
@ -261,12 +265,14 @@ __all__ = (
"ReopenForumTopic",
"ReopenGeneralForumTopic",
"ReplaceStickerInSet",
"ReplaceManagedBotToken",
"RepostStory",
"Request",
"Response",
"RestrictChatMember",
"RevokeChatInviteLink",
"SavePreparedInlineMessage",
"SavePreparedKeyboardButton",
"SendAnimation",
"SendAudio",
"SendChatAction",

View file

@ -0,0 +1,32 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramMethod
class GetManagedBotToken(TelegramMethod[str]):
"""
Use this method to get the token of a managed bot. Returns the token as *String* on success.
Source: https://core.telegram.org/bots/api#getmanagedbottoken
"""
__returning__ = str
__api_method__ = "getManagedBotToken"
user_id: int
"""User identifier of the managed bot whose token will be returned"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
user_id: int,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
user_id=user_id,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,32 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramMethod
class ReplaceManagedBotToken(TelegramMethod[str]):
"""
Use this method to revoke the current token of a managed bot and generate a new one. Returns the new token as *String* on success.
Source: https://core.telegram.org/bots/api#replacemanagedbottoken
"""
__returning__ = str
__api_method__ = "replaceManagedBotToken"
user_id: int
"""User identifier of the managed bot whose token will be replaced"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
user_id: int,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
user_id=user_id,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,37 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from ..types import KeyboardButton, PreparedKeyboardButton
from .base import TelegramMethod
class SavePreparedKeyboardButton(TelegramMethod[PreparedKeyboardButton]):
"""
Stores a keyboard button that can be used by a user within a Mini App. Returns a :class:`aiogram.types.prepared_keyboard_button.PreparedKeyboardButton` object.
Source: https://core.telegram.org/bots/api#savepreparedkeyboardbutton
"""
__returning__ = PreparedKeyboardButton
__api_method__ = "savePreparedKeyboardButton"
user_id: int
"""Unique identifier of the target user that can use the button"""
button: KeyboardButton
"""A JSON-serialized object describing the button to be saved. The button must be of the type *request_users*, *request_chat*, or *request_managed_bot*"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
user_id: int,
button: KeyboardButton,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
user_id=user_id,
button=button,
**__pydantic_kwargs,
)

View file

@ -47,8 +47,16 @@ class SendPoll(TelegramMethod[Message]):
"""Poll type, 'quiz' or 'regular', defaults to 'regular'"""
allows_multiple_answers: bool | None = None
""":code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`"""
correct_option_id: int | None = None
"""0-based identifier of the correct answer option, required for polls in quiz mode"""
allows_revoting: bool | None = None
"""Pass :code:`True`, if the poll allows to change chosen answer options, defaults to :code:`False` for quizzes and to :code:`True` for regular polls"""
shuffle_options: bool | None = None
"""Pass :code:`True`, if the poll options must be shown in random order"""
allow_adding_options: bool | None = None
"""Pass :code:`True`, if answer options can be added to the poll after creation; not supported for anonymous polls and quizzes"""
hide_results_until_closes: bool | None = None
"""Pass :code:`True`, if poll results must be shown only after the poll closes"""
correct_option_ids: list[int] | None = None
"""A JSON-serialized list of monotonically increasing 0-based identifiers of the correct answer options, required for polls in quiz mode"""
explanation: str | None = None
"""Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing"""
explanation_parse_mode: str | Default | None = Default("parse_mode")
@ -56,11 +64,17 @@ class SendPoll(TelegramMethod[Message]):
explanation_entities: list[MessageEntity] | None = None
"""A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*"""
open_period: int | None = None
"""Amount of time in seconds the poll will be active after creation, 5-600. Can't be used together with *close_date*."""
"""Amount of time in seconds the poll will be active after creation, 5-2628000. Can't be used together with *close_date*."""
close_date: DateTimeUnion | None = None
"""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*."""
"""Point in time (Unix timestamp) when the poll will be automatically closed. Must be at least 5 and no more than 2628000 seconds in the future. Can't be used together with *open_period*."""
is_closed: bool | None = None
"""Pass :code:`True` if the poll needs to be immediately closed. This can be useful for poll preview."""
description: str | None = None
"""Description of the poll to be sent, 0-1024 characters after entities parsing"""
description_parse_mode: str | Default | None = Default("parse_mode")
"""Mode for parsing entities in the poll description. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details."""
description_entities: list[MessageEntity] | None = None
"""A JSON-serialized list of special entities that appear in the poll description, which can be specified instead of *description_parse_mode*"""
disable_notification: bool | None = None
"""Sends the message `silently <https://telegram.org/blog/channels-2-0#silent-messages>`_. Users will receive a notification with no sound."""
protect_content: bool | Default | None = Default("protect_content")
@ -101,13 +115,20 @@ class SendPoll(TelegramMethod[Message]):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
allows_revoting: bool | None = None,
shuffle_options: bool | None = None,
allow_adding_options: bool | None = None,
hide_results_until_closes: bool | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
open_period: int | None = None,
close_date: DateTimeUnion | None = None,
is_closed: bool | None = None,
description: str | None = None,
description_parse_mode: str | Default | None = Default("parse_mode"),
description_entities: list[MessageEntity] | None = None,
disable_notification: bool | None = None,
protect_content: bool | Default | None = Default("protect_content"),
allow_paid_broadcast: bool | None = None,
@ -133,13 +154,20 @@ class SendPoll(TelegramMethod[Message]):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
allows_revoting=allows_revoting,
shuffle_options=shuffle_options,
allow_adding_options=allow_adding_options,
hide_results_until_closes=hide_results_until_closes,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,
open_period=open_period,
close_date=close_date,
is_closed=is_closed,
description=description,
description_parse_mode=description_parse_mode,
description_entities=description_entities,
disable_notification=disable_notification,
protect_content=protect_content,
allow_paid_broadcast=allow_paid_broadcast,

View file

@ -171,6 +171,7 @@ from .invoice import Invoice
from .keyboard_button import KeyboardButton
from .keyboard_button_poll_type import KeyboardButtonPollType
from .keyboard_button_request_chat import KeyboardButtonRequestChat
from .keyboard_button_request_managed_bot import KeyboardButtonRequestManagedBot
from .keyboard_button_request_user import KeyboardButtonRequestUser
from .keyboard_button_request_users import KeyboardButtonRequestUsers
from .labeled_price import LabeledPrice
@ -178,6 +179,8 @@ from .link_preview_options import LinkPreviewOptions
from .location import Location
from .location_address import LocationAddress
from .login_url import LoginUrl
from .managed_bot_created import ManagedBotCreated
from .managed_bot_updated import ManagedBotUpdated
from .mask_position import MaskPosition
from .maybe_inaccessible_message import MaybeInaccessibleMessage
from .maybe_inaccessible_message_union import MaybeInaccessibleMessageUnion
@ -232,8 +235,11 @@ from .photo_size import PhotoSize
from .poll import Poll
from .poll_answer import PollAnswer
from .poll_option import PollOption
from .poll_option_added import PollOptionAdded
from .poll_option_deleted import PollOptionDeleted
from .pre_checkout_query import PreCheckoutQuery
from .prepared_inline_message import PreparedInlineMessage
from .prepared_keyboard_button import PreparedKeyboardButton
from .proximity_alert_triggered import ProximityAlertTriggered
from .reaction_count import ReactionCount
from .reaction_type import ReactionType
@ -495,6 +501,7 @@ __all__ = (
"KeyboardButton",
"KeyboardButtonPollType",
"KeyboardButtonRequestChat",
"KeyboardButtonRequestManagedBot",
"KeyboardButtonRequestUser",
"KeyboardButtonRequestUsers",
"LabeledPrice",
@ -502,6 +509,8 @@ __all__ = (
"Location",
"LocationAddress",
"LoginUrl",
"ManagedBotCreated",
"ManagedBotUpdated",
"MaskPosition",
"MaybeInaccessibleMessage",
"MaybeInaccessibleMessageUnion",
@ -554,8 +563,11 @@ __all__ = (
"Poll",
"PollAnswer",
"PollOption",
"PollOptionAdded",
"PollOptionDeleted",
"PreCheckoutQuery",
"PreparedInlineMessage",
"PreparedKeyboardButton",
"ProximityAlertTriggered",
"ReactionCount",
"ReactionType",

View file

@ -1783,7 +1783,7 @@ class ChatJoinRequest(TelegramObject):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -1819,7 +1819,7 @@ class ChatJoinRequest(TelegramObject):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -1852,7 +1852,7 @@ class ChatJoinRequest(TelegramObject):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,
@ -1881,7 +1881,7 @@ class ChatJoinRequest(TelegramObject):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -1917,7 +1917,7 @@ class ChatJoinRequest(TelegramObject):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -1950,7 +1950,7 @@ class ChatJoinRequest(TelegramObject):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,

View file

@ -924,7 +924,7 @@ class ChatMemberUpdated(TelegramObject):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -960,7 +960,7 @@ class ChatMemberUpdated(TelegramObject):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -993,7 +993,7 @@ class ChatMemberUpdated(TelegramObject):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,

View file

@ -1746,7 +1746,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -1782,7 +1782,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -1819,7 +1819,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,
@ -1848,7 +1848,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -1883,7 +1883,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -1919,7 +1919,7 @@ class InaccessibleMessage(MaybeInaccessibleMessage):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,

View file

@ -9,6 +9,7 @@ from .base import MutableTelegramObject
if TYPE_CHECKING:
from .keyboard_button_poll_type import KeyboardButtonPollType
from .keyboard_button_request_chat import KeyboardButtonRequestChat
from .keyboard_button_request_managed_bot import KeyboardButtonRequestManagedBot
from .keyboard_button_request_user import KeyboardButtonRequestUser
from .keyboard_button_request_users import KeyboardButtonRequestUsers
from .web_app_info import WebAppInfo
@ -31,6 +32,8 @@ class KeyboardButton(MutableTelegramObject):
"""*Optional*. If specified, pressing the button will open a list of suitable users. Identifiers of selected users will be sent to the bot in a 'users_shared' service message. Available in private chats only."""
request_chat: KeyboardButtonRequestChat | None = None
"""*Optional*. If specified, pressing the button will open a list of suitable chats. Tapping on a chat will send its identifier to the bot in a 'chat_shared' service message. Available in private chats only."""
request_managed_bot: KeyboardButtonRequestManagedBot | None = None
"""*Optional*. If specified, pressing the button will request creation or selection of a managed bot. Available in private chats only."""
request_contact: bool | None = None
"""*Optional*. If :code:`True`, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only."""
request_location: bool | None = None
@ -59,6 +62,7 @@ class KeyboardButton(MutableTelegramObject):
style: str | None = None,
request_users: KeyboardButtonRequestUsers | None = None,
request_chat: KeyboardButtonRequestChat | None = None,
request_managed_bot: KeyboardButtonRequestManagedBot | None = None,
request_contact: bool | None = None,
request_location: bool | None = None,
request_poll: KeyboardButtonPollType | None = None,
@ -76,6 +80,7 @@ class KeyboardButton(MutableTelegramObject):
style=style,
request_users=request_users,
request_chat=request_chat,
request_managed_bot=request_managed_bot,
request_contact=request_contact,
request_location=request_location,
request_poll=request_poll,

View file

@ -0,0 +1,37 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
class KeyboardButtonRequestManagedBot(TelegramObject):
"""
This object defines the parameters for the creation of a managed bot. Information about the created bot will be shared with the bot using the update *managed_bot* and a :class:`aiogram.types.message.Message` with the field *managed_bot_created*.
Source: https://core.telegram.org/bots/api#keyboardbuttonrequestmanagedbot
"""
request_id: int
"""Signed 32-bit identifier of the request. Must be unique within the message"""
suggested_name: str | None = None
"""*Optional*. Suggested name for the bot"""
suggested_username: str | None = None
"""*Optional*. Suggested username for the bot"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
request_id: int,
suggested_name: str | None = None,
suggested_username: str | None = None,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
request_id=request_id,
suggested_name=suggested_name,
suggested_username=suggested_username,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,34 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from pydantic import Field
from .base import TelegramObject
if TYPE_CHECKING:
from .user import User
class ManagedBotCreated(TelegramObject):
"""
This object represents a service message about a bot created to be managed by the current bot.
Source: https://core.telegram.org/bots/api#managedbotcreated
"""
managed_bot: User = Field(alias="bot")
"""Information about the bot. The bot's token can be fetched using the method getManagedBotToken."""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
bot: User,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
bot=bot,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,38 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from pydantic import Field
from .base import TelegramObject
if TYPE_CHECKING:
from .user import User
class ManagedBotUpdated(TelegramObject):
"""
This object represents the creation or token update of a managed bot.
Source: https://core.telegram.org/bots/api#managedbotupdated
"""
user: User
"""The user who created or updated the managed bot"""
managed_bot: User = Field(alias="bot")
"""Information about the managed bot. Token of the bot can be fetched using the method getManagedBotToken."""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
user: User,
bot: User,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
user=user,
bot=bot,
**__pydantic_kwargs,
)

View file

@ -90,6 +90,7 @@ if TYPE_CHECKING:
from .labeled_price import LabeledPrice
from .link_preview_options import LinkPreviewOptions
from .location import Location
from .managed_bot_created import ManagedBotCreated
from .maybe_inaccessible_message_union import MaybeInaccessibleMessageUnion
from .media_union import MediaUnion
from .message_auto_delete_timer_changed import MessageAutoDeleteTimerChanged
@ -100,6 +101,8 @@ if TYPE_CHECKING:
from .passport_data import PassportData
from .photo_size import PhotoSize
from .poll import Poll
from .poll_option_added import PollOptionAdded
from .poll_option_deleted import PollOptionDeleted
from .proximity_alert_triggered import ProximityAlertTriggered
from .reaction_type_union import ReactionTypeUnion
from .refunded_payment import RefundedPayment
@ -177,6 +180,8 @@ class Message(MaybeInaccessibleMessage):
"""*Optional*. For replies to a story, the original story"""
reply_to_checklist_task_id: int | None = None
"""*Optional*. Identifier of the specific checklist task that is being replied to"""
reply_to_poll_option_id: str | None = None
"""*Optional*. Persistent identifier of the specific poll option that is being replied to"""
via_bot: User | None = None
"""*Optional*. Bot through which the message was sent"""
edit_date: int | None = None
@ -327,8 +332,14 @@ class Message(MaybeInaccessibleMessage):
"""*Optional*. A giveaway with public winners was completed"""
giveaway_completed: GiveawayCompleted | None = None
"""*Optional*. Service message: a giveaway without public winners was completed"""
managed_bot_created: ManagedBotCreated | None = None
"""*Optional*. Service message: a bot was created to be managed by the current bot"""
paid_message_price_changed: PaidMessagePriceChanged | None = None
"""*Optional*. Service message: the price for paid messages has changed in the chat"""
poll_option_added: PollOptionAdded | None = None
"""*Optional*. Service message: an option was added to a poll"""
poll_option_deleted: PollOptionDeleted | None = None
"""*Optional*. Service message: an option was removed from a poll"""
suggested_post_approved: SuggestedPostApproved | None = None
"""*Optional*. Service message: a suggested post was approved"""
suggested_post_approval_failed: SuggestedPostApprovalFailed | None = None
@ -413,6 +424,7 @@ class Message(MaybeInaccessibleMessage):
quote: TextQuote | None = None,
reply_to_story: Story | None = None,
reply_to_checklist_task_id: int | None = None,
reply_to_poll_option_id: str | None = None,
via_bot: User | None = None,
edit_date: int | None = None,
has_protected_content: bool | None = None,
@ -488,7 +500,10 @@ class Message(MaybeInaccessibleMessage):
giveaway: Giveaway | None = None,
giveaway_winners: GiveawayWinners | None = None,
giveaway_completed: GiveawayCompleted | None = None,
managed_bot_created: ManagedBotCreated | None = None,
paid_message_price_changed: PaidMessagePriceChanged | None = None,
poll_option_added: PollOptionAdded | None = None,
poll_option_deleted: PollOptionDeleted | None = None,
suggested_post_approved: SuggestedPostApproved | None = None,
suggested_post_approval_failed: SuggestedPostApprovalFailed | None = None,
suggested_post_declined: SuggestedPostDeclined | None = None,
@ -533,6 +548,7 @@ class Message(MaybeInaccessibleMessage):
quote=quote,
reply_to_story=reply_to_story,
reply_to_checklist_task_id=reply_to_checklist_task_id,
reply_to_poll_option_id=reply_to_poll_option_id,
via_bot=via_bot,
edit_date=edit_date,
has_protected_content=has_protected_content,
@ -608,7 +624,10 @@ class Message(MaybeInaccessibleMessage):
giveaway=giveaway,
giveaway_winners=giveaway_winners,
giveaway_completed=giveaway_completed,
managed_bot_created=managed_bot_created,
paid_message_price_changed=paid_message_price_changed,
poll_option_added=poll_option_added,
poll_option_deleted=poll_option_deleted,
suggested_post_approved=suggested_post_approved,
suggested_post_approval_failed=suggested_post_approval_failed,
suggested_post_declined=suggested_post_declined,
@ -764,6 +783,12 @@ class Message(MaybeInaccessibleMessage):
return ContentType.GIFT_UPGRADE_SENT
if self.paid_message_price_changed:
return ContentType.PAID_MESSAGE_PRICE_CHANGED
if self.managed_bot_created:
return ContentType.MANAGED_BOT_CREATED
if self.poll_option_added:
return ContentType.POLL_OPTION_ADDED
if self.poll_option_deleted:
return ContentType.POLL_OPTION_DELETED
if self.suggested_post_approved:
return ContentType.SUGGESTED_POST_APPROVED
if self.suggested_post_approval_failed:
@ -2444,7 +2469,7 @@ class Message(MaybeInaccessibleMessage):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -2479,7 +2504,7 @@ class Message(MaybeInaccessibleMessage):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -2515,7 +2540,7 @@ class Message(MaybeInaccessibleMessage):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,
@ -2540,7 +2565,7 @@ class Message(MaybeInaccessibleMessage):
is_anonymous: bool | None = None,
type: str | None = None,
allows_multiple_answers: bool | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_parse_mode: str | Default | None = Default("parse_mode"),
explanation_entities: list[MessageEntity] | None = None,
@ -2576,7 +2601,7 @@ class Message(MaybeInaccessibleMessage):
:param is_anonymous: :code:`True`, if the poll needs to be anonymous, defaults to :code:`True`
:param type: Poll type, 'quiz' or 'regular', defaults to 'regular'
:param allows_multiple_answers: :code:`True`, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to :code:`False`
:param correct_option_id: 0-based identifier of the correct answer option, required for polls in quiz mode
:param correct_option_ids: A JSON-serialized list of 0-based identifiers of the correct answer options, required for polls in quiz mode
:param explanation: Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most 2 line feeds after entities parsing
:param explanation_parse_mode: Mode for parsing entities in the explanation. See `formatting options <https://core.telegram.org/bots/api#formatting-options>`_ for more details.
:param explanation_entities: A JSON-serialized list of special entities that appear in the poll explanation. It can be specified instead of *explanation_parse_mode*
@ -2613,7 +2638,7 @@ class Message(MaybeInaccessibleMessage):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_parse_mode=explanation_parse_mode,
explanation_entities=explanation_entities,

View file

@ -33,10 +33,12 @@ class Poll(TelegramObject):
"""Poll type, currently can be 'regular' or 'quiz'"""
allows_multiple_answers: bool
""":code:`True`, if the poll allows multiple answers"""
allows_revoting: bool
""":code:`True`, if voters can change their answer"""
question_entities: list[MessageEntity] | None = None
"""*Optional*. Special entities that appear in the *question*. Currently, only custom emoji entities are allowed in poll questions"""
correct_option_id: int | None = None
"""*Optional*. 0-based identifier of the correct answer option. Available only for polls in the quiz mode, which are closed, or was sent (not forwarded) by the bot or to the private chat with the bot."""
correct_option_ids: list[int] | None = None
"""*Optional*. 0-based identifiers of the correct answer options. Available only for polls in the quiz mode, which are closed, or was sent (not forwarded) by the bot or to the private chat with the bot."""
explanation: str | None = None
"""*Optional*. Text that is shown when a user chooses an incorrect answer or taps on the lamp icon in a quiz-style poll, 0-200 characters"""
explanation_entities: list[MessageEntity] | None = None
@ -45,6 +47,10 @@ class Poll(TelegramObject):
"""*Optional*. Amount of time in seconds the poll will be active after creation"""
close_date: DateTime | None = None
"""*Optional*. Point in time (Unix timestamp) when the poll will be automatically closed"""
description: str | None = None
"""*Optional*. Poll description"""
description_entities: list[MessageEntity] | None = None
"""*Optional*. Special entities that appear in the *description*"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -61,12 +67,15 @@ class Poll(TelegramObject):
is_anonymous: bool,
type: str,
allows_multiple_answers: bool,
allows_revoting: bool,
question_entities: list[MessageEntity] | None = None,
correct_option_id: int | None = None,
correct_option_ids: list[int] | None = None,
explanation: str | None = None,
explanation_entities: list[MessageEntity] | None = None,
open_period: int | None = None,
close_date: DateTime | None = None,
description: str | None = None,
description_entities: list[MessageEntity] | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -82,11 +91,14 @@ class Poll(TelegramObject):
is_anonymous=is_anonymous,
type=type,
allows_multiple_answers=allows_multiple_answers,
allows_revoting=allows_revoting,
question_entities=question_entities,
correct_option_id=correct_option_id,
correct_option_ids=correct_option_ids,
explanation=explanation,
explanation_entities=explanation_entities,
open_period=open_period,
close_date=close_date,
description=description,
description_entities=description_entities,
**__pydantic_kwargs,
)

View file

@ -24,27 +24,25 @@ class PollAnswer(TelegramObject):
"""*Optional*. The chat that changed the answer to the poll, if the voter is anonymous"""
user: User | None = None
"""*Optional*. The user that changed the answer to the poll, if the voter isn't anonymous"""
option_persistent_ids: list[str]
"""Persistent identifiers of the chosen options. May be empty if the vote was retracted."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__,
*,
poll_id: str,
option_ids: list[int],
option_persistent_ids: list[str],
voter_chat: Chat | None = None,
user: User | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(
poll_id=poll_id,
option_ids=option_ids,
option_persistent_ids=option_persistent_ids,
voter_chat=voter_chat,
user=user,
**__pydantic_kwargs,

View file

@ -3,9 +3,12 @@ from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
from .custom import DateTime
if TYPE_CHECKING:
from .chat import Chat
from .message_entity import MessageEntity
from .user import User
class PollOption(TelegramObject):
@ -15,32 +18,42 @@ class PollOption(TelegramObject):
Source: https://core.telegram.org/bots/api#polloption
"""
persistent_id: str
"""Unique identifier of the option, persistent across option additions and deletions"""
text: str
"""Option text, 1-100 characters"""
voter_count: int
"""Number of users that voted for this option"""
text_entities: list[MessageEntity] | None = None
"""*Optional*. Special entities that appear in the option *text*. Currently, only custom emoji entities are allowed in poll option texts"""
added_by_user: User | None = None
"""*Optional*. The user who added the option, if it was added after poll creation"""
added_by_chat: Chat | None = None
"""*Optional*. The chat that added the option, if it was added after poll creation"""
addition_date: DateTime | None = None
"""*Optional*. Point in time (Unix timestamp) when the option was added"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
# This section was auto-generated via `butcher`
def __init__(
__pydantic__self__,
*,
persistent_id: str,
text: str,
voter_count: int,
text_entities: list[MessageEntity] | None = None,
added_by_user: User | None = None,
added_by_chat: Chat | None = None,
addition_date: DateTime | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
# This method was auto-generated via `butcher`
# Is needed only for type checking and IDE support without any additional plugins
super().__init__(
persistent_id=persistent_id,
text=text,
voter_count=voter_count,
text_entities=text_entities,
added_by_user=added_by_user,
added_by_chat=added_by_chat,
addition_date=addition_date,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,45 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
if TYPE_CHECKING:
from .maybe_inaccessible_message_union import MaybeInaccessibleMessageUnion
from .message_entity import MessageEntity
class PollOptionAdded(TelegramObject):
"""
This object represents a service message about an option added to a poll.
Source: https://core.telegram.org/bots/api#polloptionadded
"""
option_persistent_id: str
"""Unique identifier of the added option"""
option_text: str
"""Text of the added option, 1-100 characters"""
poll_message: MaybeInaccessibleMessageUnion | None = None
"""*Optional*. The message containing the poll to which the option was added. Note that the :class:`aiogram.types.message.Message` object in this field will not contain the *reply_to_message* field even if it itself is a reply."""
option_text_entities: list[MessageEntity] | None = None
"""*Optional*. Special entities that appear in the option text. Currently, only custom emoji entities are allowed in poll option texts"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
option_persistent_id: str,
option_text: str,
poll_message: MaybeInaccessibleMessageUnion | None = None,
option_text_entities: list[MessageEntity] | None = None,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
option_persistent_id=option_persistent_id,
option_text=option_text,
poll_message=poll_message,
option_text_entities=option_text_entities,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,45 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
if TYPE_CHECKING:
from .maybe_inaccessible_message_union import MaybeInaccessibleMessageUnion
from .message_entity import MessageEntity
class PollOptionDeleted(TelegramObject):
"""
This object represents a service message about an option deleted from a poll.
Source: https://core.telegram.org/bots/api#polloptiondeleted
"""
option_persistent_id: str
"""Unique identifier of the deleted option"""
option_text: str
"""Text of the deleted option, 1-100 characters"""
poll_message: MaybeInaccessibleMessageUnion | None = None
"""*Optional*. The message containing the poll from which the option was deleted. Note that the :class:`aiogram.types.message.Message` object in this field will not contain the *reply_to_message* field even if it itself is a reply."""
option_text_entities: list[MessageEntity] | None = None
"""*Optional*. Special entities that appear in the option text. Currently, only custom emoji entities are allowed in poll option texts"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
option_persistent_id: str,
option_text: str,
poll_message: MaybeInaccessibleMessageUnion | None = None,
option_text_entities: list[MessageEntity] | None = None,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
option_persistent_id=option_persistent_id,
option_text=option_text,
poll_message=poll_message,
option_text_entities=option_text_entities,
**__pydantic_kwargs,
)

View file

@ -0,0 +1,29 @@
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from .base import TelegramObject
class PreparedKeyboardButton(TelegramObject):
"""
This object represents a prepared keyboard button that allows bots to request users, chats, and managed bots from Mini Apps.
Source: https://core.telegram.org/bots/api#preparedkeyboardbutton
"""
id: str
"""Unique identifier of the prepared button"""
if TYPE_CHECKING:
def __init__(
__pydantic__self__,
*,
id: str,
**__pydantic_kwargs: Any,
) -> None:
super().__init__(
id=id,
**__pydantic_kwargs,
)

View file

@ -33,6 +33,8 @@ class ReplyParameters(TelegramObject):
"""*Optional*. Position of the quote in the original message in UTF-16 code units"""
checklist_task_id: int | None = None
"""*Optional*. Identifier of the specific checklist task to be replied to"""
poll_option_id: str | None = None
"""*Optional*. Persistent identifier of a specific poll option to reply to"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -51,6 +53,7 @@ class ReplyParameters(TelegramObject):
quote_entities: list[MessageEntity] | None = None,
quote_position: int | None = None,
checklist_task_id: int | None = None,
poll_option_id: str | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -66,5 +69,6 @@ class ReplyParameters(TelegramObject):
quote_entities=quote_entities,
quote_position=quote_position,
checklist_task_id=checklist_task_id,
poll_option_id=poll_option_id,
**__pydantic_kwargs,
)

View file

@ -15,6 +15,7 @@ if TYPE_CHECKING:
from .chat_member_updated import ChatMemberUpdated
from .chosen_inline_result import ChosenInlineResult
from .inline_query import InlineQuery
from .managed_bot_updated import ManagedBotUpdated
from .message import Message
from .message_reaction_count_updated import MessageReactionCountUpdated
from .message_reaction_updated import MessageReactionUpdated
@ -82,6 +83,8 @@ class Update(TelegramObject):
"""*Optional*. A chat boost was added or changed. The bot must be an administrator in the chat to receive these updates."""
removed_chat_boost: ChatBoostRemoved | None = None
"""*Optional*. A boost was removed from a chat. The bot must be an administrator in the chat to receive these updates."""
managed_bot: ManagedBotUpdated | None = None
"""*Optional*. A managed bot was created or its token was updated"""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -114,6 +117,7 @@ class Update(TelegramObject):
chat_join_request: ChatJoinRequest | None = None,
chat_boost: ChatBoostUpdated | None = None,
removed_chat_boost: ChatBoostRemoved | None = None,
managed_bot: ManagedBotUpdated | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -145,6 +149,7 @@ class Update(TelegramObject):
chat_join_request=chat_join_request,
chat_boost=chat_boost,
removed_chat_boost=removed_chat_boost,
managed_bot=managed_bot,
**__pydantic_kwargs,
)
@ -206,6 +211,8 @@ class Update(TelegramObject):
return "business_message"
if self.purchased_paid_media:
return "purchased_paid_media"
if self.managed_bot:
return "managed_bot"
raise UpdateTypeLookupError("Update does not contain any known event type.")

View file

@ -47,6 +47,8 @@ class User(TelegramObject):
"""*Optional*. :code:`True`, if the bot has forum topic mode enabled in private chats. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
allows_users_to_create_topics: bool | None = None
"""*Optional*. :code:`True`, if the bot allows users to create and delete topics in private chats. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
can_manage_bots: bool | None = None
"""*Optional*. :code:`True`, if the bot can create other bots it controls. Returned only in :class:`aiogram.methods.get_me.GetMe`."""
if TYPE_CHECKING:
# DO NOT EDIT MANUALLY!!!
@ -70,6 +72,7 @@ class User(TelegramObject):
has_main_web_app: bool | None = None,
has_topics_enabled: bool | None = None,
allows_users_to_create_topics: bool | None = None,
can_manage_bots: bool | None = None,
**__pydantic_kwargs: Any,
) -> None:
# DO NOT EDIT MANUALLY!!!
@ -92,6 +95,7 @@ class User(TelegramObject):
has_main_web_app=has_main_web_app,
has_topics_enabled=has_topics_enabled,
allows_users_to_create_topics=allows_users_to_create_topics,
can_manage_bots=can_manage_bots,
**__pydantic_kwargs,
)

View file

@ -17,22 +17,23 @@ class TestSendPoll:
id="QA",
question="Q",
options=[
PollOption(text="A", voter_count=0),
PollOption(text="B", voter_count=0),
PollOption(persistent_id="1", text="A", voter_count=0),
PollOption(persistent_id="2", text="B", voter_count=0),
],
is_closed=False,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=0,
correct_option_ids=[0],
),
chat=Chat(id=42, type="private"),
),
)
response: Message = await bot.send_poll(
chat_id=42, question="Q?", options=["A", "B"], correct_option_id=0, type="quiz"
chat_id=42, question="Q?", options=["A", "B"], correct_option_ids=[0], type="quiz"
)
bot.get_request()
assert response == prepare_result.result

View file

@ -11,13 +11,17 @@ class TestStopPoll:
result=Poll(
id="QA",
question="Q",
options=[PollOption(text="A", voter_count=0), PollOption(text="B", voter_count=0)],
options=[
PollOption(persistent_id="1", text="A", voter_count=0),
PollOption(persistent_id="2", text="B", voter_count=0),
],
is_closed=False,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=0,
correct_option_ids=[0],
),
)

View file

@ -76,6 +76,7 @@ from aiogram.types import (
InputMediaPhoto,
Invoice,
Location,
ManagedBotCreated,
MessageAutoDeleteTimerChanged,
MessageEntity,
PaidMediaInfo,
@ -85,6 +86,8 @@ from aiogram.types import (
PhotoSize,
Poll,
PollOption,
PollOptionAdded,
PollOptionDeleted,
ProximityAlertTriggered,
ReactionTypeCustomEmoji,
RefundedPayment,
@ -426,15 +429,16 @@ TEST_MESSAGE_POLL = Message(
id="QA",
question="Q",
options=[
PollOption(text="A", voter_count=0),
PollOption(text="B", voter_count=0),
PollOption(persistent_id="1", text="A", voter_count=0),
PollOption(persistent_id="2", text="B", voter_count=0),
],
is_closed=False,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=1,
correct_option_ids=[1],
),
chat=Chat(id=42, type="private"),
from_user=User(id=42, is_bot=False, first_name="Test"),
@ -858,6 +862,27 @@ TEST_MESSAGE_SUGGESTED_POST_REFUNDED = Message(
from_user=User(id=42, is_bot=False, first_name="Test"),
suggested_post_refunded=SuggestedPostRefunded(reason="post_deleted"),
)
TEST_MESSAGE_MANAGED_BOT_CREATED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=User(id=42, is_bot=False, first_name="Test"),
managed_bot_created=ManagedBotCreated(bot=User(id=100, is_bot=True, first_name="ManagedBot")),
)
TEST_MESSAGE_POLL_OPTION_ADDED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=User(id=42, is_bot=False, first_name="Test"),
poll_option_added=PollOptionAdded(option_persistent_id="1", option_text="New option"),
)
TEST_MESSAGE_POLL_OPTION_DELETED = Message(
message_id=42,
date=datetime.datetime.now(),
chat=Chat(id=42, type="private"),
from_user=User(id=42, is_bot=False, first_name="Test"),
poll_option_deleted=PollOptionDeleted(option_persistent_id="1", option_text="Old option"),
)
MESSAGES_AND_CONTENT_TYPES = [
[TEST_MESSAGE_TEXT, ContentType.TEXT],
@ -937,6 +962,9 @@ MESSAGES_AND_CONTENT_TYPES = [
[TEST_MESSAGE_SUGGESTED_POST_DECLINED, ContentType.SUGGESTED_POST_DECLINED],
[TEST_MESSAGE_SUGGESTED_POST_PAID, ContentType.SUGGESTED_POST_PAID],
[TEST_MESSAGE_SUGGESTED_POST_REFUNDED, ContentType.SUGGESTED_POST_REFUNDED],
[TEST_MESSAGE_MANAGED_BOT_CREATED, ContentType.MANAGED_BOT_CREATED],
[TEST_MESSAGE_POLL_OPTION_ADDED, ContentType.POLL_OPTION_ADDED],
[TEST_MESSAGE_POLL_OPTION_DELETED, ContentType.POLL_OPTION_DELETED],
[TEST_MESSAGE_UNKNOWN, ContentType.UNKNOWN],
]
@ -1013,6 +1041,9 @@ MESSAGES_AND_COPY_METHODS = [
[TEST_MESSAGE_SUGGESTED_POST_DECLINED, None],
[TEST_MESSAGE_SUGGESTED_POST_PAID, None],
[TEST_MESSAGE_SUGGESTED_POST_REFUNDED, None],
[TEST_MESSAGE_MANAGED_BOT_CREATED, None],
[TEST_MESSAGE_POLL_OPTION_ADDED, None],
[TEST_MESSAGE_POLL_OPTION_DELETED, None],
[TEST_MESSAGE_UNKNOWN, None],
]

View file

@ -30,6 +30,7 @@ from aiogram.types import (
ChatMemberUpdated,
ChosenInlineResult,
InlineQuery,
ManagedBotUpdated,
Message,
MessageReactionCountUpdated,
MessageReactionUpdated,
@ -380,15 +381,16 @@ class TestDispatcher:
id="poll id",
question="Q?",
options=[
PollOption(text="A1", voter_count=2),
PollOption(text="A2", voter_count=3),
PollOption(persistent_id="1", text="A1", voter_count=2),
PollOption(persistent_id="2", text="A2", voter_count=3),
],
is_closed=False,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=1,
correct_option_ids=[1],
),
),
False,
@ -402,6 +404,7 @@ class TestDispatcher:
poll_id="poll id",
user=User(id=42, is_bot=False, first_name="Test"),
option_ids=[42],
option_persistent_ids=["1"],
),
),
False,
@ -600,6 +603,18 @@ class TestDispatcher:
False,
True,
),
pytest.param(
"managed_bot",
Update(
update_id=42,
managed_bot=ManagedBotUpdated(
user=User(id=42, is_bot=False, first_name="Test"),
bot=User(id=100, is_bot=True, first_name="ManagedBot"),
),
),
False,
True,
),
],
)
async def test_listen_update(
@ -655,15 +670,16 @@ class TestDispatcher:
id="poll id",
question="Q?",
options=[
PollOption(text="A1", voter_count=2),
PollOption(text="A2", voter_count=3),
PollOption(persistent_id="1", text="A1", voter_count=2),
PollOption(persistent_id="2", text="A2", voter_count=3),
],
is_closed=False,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=0,
correct_option_ids=[0],
),
)
)

View file

@ -9,13 +9,14 @@ class TestShippingQueryHandler:
event = Poll(
id="query",
question="Q?",
options=[PollOption(text="A1", voter_count=1)],
options=[PollOption(persistent_id="1", text="A1", voter_count=1)],
is_closed=True,
is_anonymous=False,
type="quiz",
allows_multiple_answers=False,
allows_revoting=False,
total_voter_count=0,
correct_option_id=0,
correct_option_ids=[0],
)
class MyHandler(PollHandler):