diff --git a/aiogram/api/client/bot.py b/aiogram/api/client/bot.py index 95dab879..1b53f8b4 100644 --- a/aiogram/api/client/bot.py +++ b/aiogram/api/client/bot.py @@ -979,6 +979,11 @@ class Bot(BaseBot): chat_id: Union[int, str], question: str, options: List[str], + is_anonymous: Optional[bool] = None, + type: Optional[str] = None, + allows_multiple_answers: Optional[bool] = None, + correct_option_id: Optional[int] = None, + is_closed: Optional[bool] = None, disable_notification: Optional[bool] = None, reply_to_message_id: Optional[int] = None, reply_markup: Optional[ @@ -986,16 +991,21 @@ class Bot(BaseBot): ] = None, ) -> Message: """ - Use this method to send a native poll. A native poll can't be sent to a private chat. On - success, the sent Message is returned. + Use this method to send a native poll. On success, the sent Message is returned. Source: https://core.telegram.org/bots/api#sendpoll :param chat_id: Unique identifier for the target chat or username of the target channel - (in the format @channelusername). A native poll can't be sent to a private - chat. + (in the format @channelusername) :param question: Poll question, 1-255 characters :param options: List of answer options, 2-10 strings 1-100 characters each + :param is_anonymous: True, if the poll needs to be anonymous, defaults to True + :param type: Poll type, 'quiz' or 'regular', defaults to 'regular' + :param allows_multiple_answers: True, if the poll allows multiple answers, ignored for + polls in quiz mode, defaults to False + :param correct_option_id: 0-based identifier of the correct answer option, required for + polls in quiz mode + :param is_closed: Pass True, if the poll needs to be immediately closed :param disable_notification: Sends the message silently. Users will receive a notification with no sound. :param reply_to_message_id: If the message is a reply, ID of the original message @@ -1008,6 +1018,11 @@ class Bot(BaseBot): chat_id=chat_id, question=question, options=options, + is_anonymous=is_anonymous, + type=type, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, disable_notification=disable_notification, reply_to_message_id=reply_to_message_id, reply_markup=reply_markup, diff --git a/aiogram/api/methods/send_poll.py b/aiogram/api/methods/send_poll.py index b229368a..eb901d59 100644 --- a/aiogram/api/methods/send_poll.py +++ b/aiogram/api/methods/send_poll.py @@ -12,8 +12,7 @@ from .base import Request, TelegramMethod class SendPoll(TelegramMethod[Message]): """ - Use this method to send a native poll. A native poll can't be sent to a private chat. On - success, the sent Message is returned. + Use this method to send a native poll. On success, the sent Message is returned. Source: https://core.telegram.org/bots/api#sendpoll """ @@ -22,11 +21,22 @@ class SendPoll(TelegramMethod[Message]): chat_id: Union[int, str] """Unique identifier for the target chat or username of the target channel (in the format - @channelusername). A native poll can't be sent to a private chat.""" + @channelusername)""" question: str """Poll question, 1-255 characters""" options: List[str] """List of answer options, 2-10 strings 1-100 characters each""" + is_anonymous: Optional[bool] = None + """True, if the poll needs to be anonymous, defaults to True""" + type: Optional[str] = None + """Poll type, 'quiz' or 'regular', defaults to 'regular'""" + allows_multiple_answers: Optional[bool] = None + """True, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to + False""" + correct_option_id: Optional[int] = None + """0-based identifier of the correct answer option, required for polls in quiz mode""" + is_closed: Optional[bool] = None + """Pass True, if the poll needs to be immediately closed""" disable_notification: Optional[bool] = None """Sends the message silently. Users will receive a notification with no sound.""" reply_to_message_id: Optional[int] = None diff --git a/aiogram/api/types/__init__.py b/aiogram/api/types/__init__.py index 07d604e4..fc94a7a7 100644 --- a/aiogram/api/types/__init__.py +++ b/aiogram/api/types/__init__.py @@ -54,6 +54,7 @@ from .input_text_message_content import InputTextMessageContent from .input_venue_message_content import InputVenueMessageContent from .invoice import Invoice from .keyboard_button import KeyboardButton +from .keyboard_button_poll_type import KeyboardButtonPollType from .labeled_price import LabeledPrice from .location import Location from .login_url import LoginUrl @@ -75,6 +76,7 @@ from .passport_element_error_unspecified import PassportElementErrorUnspecified from .passport_file import PassportFile from .photo_size import PhotoSize from .poll import Poll +from .poll_answer import PollAnswer from .poll_option import PollOption from .pre_checkout_query import PreCheckoutQuery from .reply_keyboard_markup import ReplyKeyboardMarkup @@ -117,11 +119,13 @@ __all__ = ( "Location", "Venue", "PollOption", + "PollAnswer", "Poll", "UserProfilePhotos", "File", "ReplyKeyboardMarkup", "KeyboardButton", + "KeyboardButtonPollType", "ReplyKeyboardRemove", "InlineKeyboardMarkup", "InlineKeyboardButton", diff --git a/aiogram/api/types/callback_query.py b/aiogram/api/types/callback_query.py index dae35ce9..87f1ad42 100644 --- a/aiogram/api/types/callback_query.py +++ b/aiogram/api/types/callback_query.py @@ -7,8 +7,8 @@ from pydantic import Field from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .user import User from .message import Message + from .user import User class CallbackQuery(TelegramObject): diff --git a/aiogram/api/types/chat.py b/aiogram/api/types/chat.py index f56cc9df..2e3163b2 100644 --- a/aiogram/api/types/chat.py +++ b/aiogram/api/types/chat.py @@ -5,9 +5,9 @@ from typing import TYPE_CHECKING, Optional from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .message import Message - from .chat_photo import ChatPhoto from .chat_permissions import ChatPermissions + from .chat_photo import ChatPhoto + from .message import Message class Chat(TelegramObject): diff --git a/aiogram/api/types/chosen_inline_result.py b/aiogram/api/types/chosen_inline_result.py index 9e1fac63..f6dfdede 100644 --- a/aiogram/api/types/chosen_inline_result.py +++ b/aiogram/api/types/chosen_inline_result.py @@ -7,8 +7,8 @@ from pydantic import Field from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .user import User from .location import Location + from .user import User class ChosenInlineResult(TelegramObject): diff --git a/aiogram/api/types/game.py b/aiogram/api/types/game.py index a4caf9c9..0d4d8510 100644 --- a/aiogram/api/types/game.py +++ b/aiogram/api/types/game.py @@ -5,9 +5,9 @@ from typing import TYPE_CHECKING, List, Optional from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .photo_size import PhotoSize - from .message_entity import MessageEntity from .animation import Animation + from .message_entity import MessageEntity + from .photo_size import PhotoSize class Game(TelegramObject): diff --git a/aiogram/api/types/inline_query.py b/aiogram/api/types/inline_query.py index 57576c23..d57f94ed 100644 --- a/aiogram/api/types/inline_query.py +++ b/aiogram/api/types/inline_query.py @@ -7,8 +7,8 @@ from pydantic import Field from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .user import User from .location import Location + from .user import User class InlineQuery(TelegramObject): diff --git a/aiogram/api/types/inline_query_result_article.py b/aiogram/api/types/inline_query_result_article.py index 776bfc8c..0c34bdb5 100644 --- a/aiogram/api/types/inline_query_result_article.py +++ b/aiogram/api/types/inline_query_result_article.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultArticle(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_audio.py b/aiogram/api/types/inline_query_result_audio.py index 3a42ff08..0290ee7e 100644 --- a/aiogram/api/types/inline_query_result_audio.py +++ b/aiogram/api/types/inline_query_result_audio.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultAudio(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_audio.py b/aiogram/api/types/inline_query_result_cached_audio.py index 941750d6..8f6fe23f 100644 --- a/aiogram/api/types/inline_query_result_cached_audio.py +++ b/aiogram/api/types/inline_query_result_cached_audio.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedAudio(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_document.py b/aiogram/api/types/inline_query_result_cached_document.py index 6299228b..860dbcc8 100644 --- a/aiogram/api/types/inline_query_result_cached_document.py +++ b/aiogram/api/types/inline_query_result_cached_document.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedDocument(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_gif.py b/aiogram/api/types/inline_query_result_cached_gif.py index b30c190c..f237c5fb 100644 --- a/aiogram/api/types/inline_query_result_cached_gif.py +++ b/aiogram/api/types/inline_query_result_cached_gif.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedGif(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py b/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py index 9b3a0bc8..0b770121 100644 --- a/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py +++ b/aiogram/api/types/inline_query_result_cached_mpeg4_gif.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_photo.py b/aiogram/api/types/inline_query_result_cached_photo.py index 9f518f02..1c163285 100644 --- a/aiogram/api/types/inline_query_result_cached_photo.py +++ b/aiogram/api/types/inline_query_result_cached_photo.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedPhoto(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_sticker.py b/aiogram/api/types/inline_query_result_cached_sticker.py index d91284d2..52c21c6d 100644 --- a/aiogram/api/types/inline_query_result_cached_sticker.py +++ b/aiogram/api/types/inline_query_result_cached_sticker.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedSticker(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_video.py b/aiogram/api/types/inline_query_result_cached_video.py index b415dd6b..3114e9e2 100644 --- a/aiogram/api/types/inline_query_result_cached_video.py +++ b/aiogram/api/types/inline_query_result_cached_video.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedVideo(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_cached_voice.py b/aiogram/api/types/inline_query_result_cached_voice.py index 5b267b43..4ba72004 100644 --- a/aiogram/api/types/inline_query_result_cached_voice.py +++ b/aiogram/api/types/inline_query_result_cached_voice.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultCachedVoice(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_contact.py b/aiogram/api/types/inline_query_result_contact.py index 00c85b0b..e394fd2f 100644 --- a/aiogram/api/types/inline_query_result_contact.py +++ b/aiogram/api/types/inline_query_result_contact.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultContact(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_document.py b/aiogram/api/types/inline_query_result_document.py index a71df0e6..97fb5209 100644 --- a/aiogram/api/types/inline_query_result_document.py +++ b/aiogram/api/types/inline_query_result_document.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultDocument(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_gif.py b/aiogram/api/types/inline_query_result_gif.py index bcc32338..3f4abfb4 100644 --- a/aiogram/api/types/inline_query_result_gif.py +++ b/aiogram/api/types/inline_query_result_gif.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultGif(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_location.py b/aiogram/api/types/inline_query_result_location.py index e51aa96c..22498ebb 100644 --- a/aiogram/api/types/inline_query_result_location.py +++ b/aiogram/api/types/inline_query_result_location.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultLocation(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_mpeg4_gif.py b/aiogram/api/types/inline_query_result_mpeg4_gif.py index a73c667f..8edaf79b 100644 --- a/aiogram/api/types/inline_query_result_mpeg4_gif.py +++ b/aiogram/api/types/inline_query_result_mpeg4_gif.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultMpeg4Gif(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_photo.py b/aiogram/api/types/inline_query_result_photo.py index 00bc9153..0a08bdc1 100644 --- a/aiogram/api/types/inline_query_result_photo.py +++ b/aiogram/api/types/inline_query_result_photo.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultPhoto(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_venue.py b/aiogram/api/types/inline_query_result_venue.py index e441a4cd..902db9a2 100644 --- a/aiogram/api/types/inline_query_result_venue.py +++ b/aiogram/api/types/inline_query_result_venue.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultVenue(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_video.py b/aiogram/api/types/inline_query_result_video.py index 8ebffeb9..ecc3663a 100644 --- a/aiogram/api/types/inline_query_result_video.py +++ b/aiogram/api/types/inline_query_result_video.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultVideo(InlineQueryResult): diff --git a/aiogram/api/types/inline_query_result_voice.py b/aiogram/api/types/inline_query_result_voice.py index 831fb496..d04ca805 100644 --- a/aiogram/api/types/inline_query_result_voice.py +++ b/aiogram/api/types/inline_query_result_voice.py @@ -7,8 +7,8 @@ from pydantic import Field from .inline_query_result import InlineQueryResult if TYPE_CHECKING: # pragma: no cover - from .input_message_content import InputMessageContent from .inline_keyboard_markup import InlineKeyboardMarkup + from .input_message_content import InputMessageContent class InlineQueryResultVoice(InlineQueryResult): diff --git a/aiogram/api/types/keyboard_button.py b/aiogram/api/types/keyboard_button.py index f2513994..60aebcb7 100644 --- a/aiogram/api/types/keyboard_button.py +++ b/aiogram/api/types/keyboard_button.py @@ -1,17 +1,22 @@ from __future__ import annotations -from typing import Optional +from typing import TYPE_CHECKING, Optional from .base import TelegramObject +if TYPE_CHECKING: # pragma: no cover + from .keyboard_button_poll_type import KeyboardButtonPollType + class KeyboardButton(TelegramObject): """ This object represents one button of the reply keyboard. For simple text buttons String can be - used instead of this object to specify text of the button. Optional fields are mutually - exclusive. + used instead of this object to specify text of the button. Optional fields request_contact, + request_location, and request_poll are mutually exclusive. Note: request_contact and request_location options will only work in Telegram versions - released after 9 April, 2016. Older clients will ignore them. + released after 9 April, 2016. Older clients will receive unsupported message. + Note: request_poll option will only work in Telegram versions released after 23 January, 2020. + Older clients will receive unsupported message. Source: https://core.telegram.org/bots/api#keyboardbutton """ @@ -25,3 +30,6 @@ class KeyboardButton(TelegramObject): request_location: Optional[bool] = None """If True, the user's current location will be sent when the button is pressed. Available in private chats only""" + request_poll: Optional[KeyboardButtonPollType] = None + """If specified, the user will be asked to create a poll and send it to the bot when the + button is pressed. Available in private chats only""" diff --git a/aiogram/api/types/keyboard_button_poll_type.py b/aiogram/api/types/keyboard_button_poll_type.py new file mode 100644 index 00000000..f66ade56 --- /dev/null +++ b/aiogram/api/types/keyboard_button_poll_type.py @@ -0,0 +1,19 @@ +from __future__ import annotations + +from typing import Optional + +from .base import TelegramObject + + +class KeyboardButtonPollType(TelegramObject): + """ + This object represents type of a poll, which is allowed to be created and sent when the + corresponding button is pressed. + + Source: https://core.telegram.org/bots/api#keyboardbuttonpolltype + """ + + type: Optional[str] = None + """If quiz is passed, the user will be allowed to create only polls in the quiz mode. If + regular is passed, only regular polls will be allowed. Otherwise, the user will be allowed + to create a poll of any type.""" diff --git a/aiogram/api/types/message.py b/aiogram/api/types/message.py index dbfdd9e9..60f61f24 100644 --- a/aiogram/api/types/message.py +++ b/aiogram/api/types/message.py @@ -9,26 +9,26 @@ from ...utils import helper from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .photo_size import PhotoSize - from .location import Location - from .contact import Contact - from .game import Game - from .message_entity import MessageEntity - from .invoice import Invoice from .animation import Animation - from .venue import Venue - from .user import User - from .passport_data import PassportData - from .video_note import VideoNote from .audio import Audio - from .successful_payment import SuccessfulPayment - from .sticker import Sticker - from .poll import Poll from .chat import Chat + from .contact import Contact from .document import Document + from .game import Game from .inline_keyboard_markup import InlineKeyboardMarkup - from .voice import Voice + from .invoice import Invoice + from .location import Location + from .message_entity import MessageEntity + from .passport_data import PassportData + from .photo_size import PhotoSize + from .poll import Poll + from .sticker import Sticker + from .successful_payment import SuccessfulPayment + from .user import User + from .venue import Venue from .video import Video + from .video_note import VideoNote + from .voice import Voice class Message(TelegramObject): diff --git a/aiogram/api/types/message_entity.py b/aiogram/api/types/message_entity.py index a08e4306..54c11a46 100644 --- a/aiogram/api/types/message_entity.py +++ b/aiogram/api/types/message_entity.py @@ -31,3 +31,5 @@ class MessageEntity(TelegramObject): """For 'text_link' only, url that will be opened after user taps on the text""" user: Optional[User] = None """For 'text_mention' only, the mentioned user""" + language: Optional[str] = None + """For 'pre' only, the programming language of the entity text""" diff --git a/aiogram/api/types/passport_data.py b/aiogram/api/types/passport_data.py index f6e84ce8..da625263 100644 --- a/aiogram/api/types/passport_data.py +++ b/aiogram/api/types/passport_data.py @@ -5,8 +5,8 @@ from typing import TYPE_CHECKING, List from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .encrypted_passport_element import EncryptedPassportElement from .encrypted_credentials import EncryptedCredentials + from .encrypted_passport_element import EncryptedPassportElement class PassportData(TelegramObject): diff --git a/aiogram/api/types/poll.py b/aiogram/api/types/poll.py index 1ee74656..4fe97330 100644 --- a/aiogram/api/types/poll.py +++ b/aiogram/api/types/poll.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import TYPE_CHECKING, List +from typing import TYPE_CHECKING, List, Optional from .base import TelegramObject @@ -21,5 +21,17 @@ class Poll(TelegramObject): """Poll question, 1-255 characters""" options: List[PollOption] """List of poll options""" + total_voter_count: int + """Total number of users that voted in the poll""" is_closed: bool """True, if the poll is closed""" + is_anonymous: bool + """True, if the poll is anonymous""" + type: str + """Poll type, currently can be 'regular' or 'quiz'""" + allows_multiple_answers: bool + """True, if the poll allows multiple answers""" + correct_option_id: Optional[int] = None + """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.""" diff --git a/aiogram/api/types/poll_answer.py b/aiogram/api/types/poll_answer.py new file mode 100644 index 00000000..a0498019 --- /dev/null +++ b/aiogram/api/types/poll_answer.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING, List + +from .base import TelegramObject + +if TYPE_CHECKING: # pragma: no cover + from .user import User + + +class PollAnswer(TelegramObject): + """ + This object represents an answer of a user in a non-anonymous poll. + + Source: https://core.telegram.org/bots/api#pollanswer + """ + + poll_id: str + """Unique poll identifier""" + user: User + """The user, who changed the answer to the poll""" + option_ids: List[int] + """0-based identifiers of answer options, chosen by the user. May be empty if the user + retracted their vote.""" diff --git a/aiogram/api/types/update.py b/aiogram/api/types/update.py index 90c468f4..fa89aa74 100644 --- a/aiogram/api/types/update.py +++ b/aiogram/api/types/update.py @@ -5,13 +5,14 @@ from typing import TYPE_CHECKING, Optional from .base import TelegramObject if TYPE_CHECKING: # pragma: no cover - from .inline_query import InlineQuery - from .shipping_query import ShippingQuery - from .message import Message from .callback_query import CallbackQuery - from .poll import Poll - from .pre_checkout_query import PreCheckoutQuery from .chosen_inline_result import ChosenInlineResult + from .inline_query import InlineQuery + from .message import Message + from .poll import Poll + from .poll_answer import PollAnswer + from .pre_checkout_query import PreCheckoutQuery + from .shipping_query import ShippingQuery class Update(TelegramObject): @@ -51,3 +52,6 @@ class Update(TelegramObject): poll: Optional[Poll] = None """New poll state. Bots receive only updates about stopped polls and polls, which are sent by the bot""" + poll_answer: Optional[PollAnswer] = None + """A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls + that were sent by the bot itself.""" diff --git a/aiogram/api/types/user.py b/aiogram/api/types/user.py index 70175f40..f46d3f2b 100644 --- a/aiogram/api/types/user.py +++ b/aiogram/api/types/user.py @@ -24,6 +24,12 @@ class User(TelegramObject): """User‘s or bot’s username""" language_code: Optional[str] = None """IETF language tag of the user's language""" + can_join_groups: Optional[bool] = None + """True, if the bot can be invited to groups. Returned only in getMe.""" + can_read_all_group_messages: Optional[bool] = None + """True, if privacy mode is disabled for the bot. Returned only in getMe.""" + supports_inline_queries: Optional[bool] = None + """True, if the bot supports inline queries. Returned only in getMe.""" @property def full_name(self): diff --git a/docs/api/methods/delete_webhook.md b/docs/api/methods/delete_webhook.md index e4584685..888b227e 100644 --- a/docs/api/methods/delete_webhook.md +++ b/docs/api/methods/delete_webhook.md @@ -31,7 +31,7 @@ Imports: - `from aiogram.api.methods import DeleteWebhook` - `from aiogram.api.methods.delete_webhook import DeleteWebhook` -#### As reply into Webhook +#### In handlers with current bot ```python3 result: bool = await DeleteWebhook(...) ``` diff --git a/docs/api/methods/send_poll.md b/docs/api/methods/send_poll.md index 7583603b..74081505 100644 --- a/docs/api/methods/send_poll.md +++ b/docs/api/methods/send_poll.md @@ -2,16 +2,21 @@ ## Description -Use this method to send a native poll. A native poll can't be sent to a private chat. On success, the sent Message is returned. +Use this method to send a native poll. On success, the sent Message is returned. ## Arguments | Name | Type | Description | | - | - | - | -| `chat_id` | `#!python3 Union[int, str]` | Unique identifier for the target chat or username of the target channel (in the format @channelusername). A native poll can't be sent to a private chat. | +| `chat_id` | `#!python3 Union[int, str]` | Unique identifier for the target chat or username of the target channel (in the format @channelusername) | | `question` | `#!python3 str` | Poll question, 1-255 characters | | `options` | `#!python3 List[str]` | List of answer options, 2-10 strings 1-100 characters each | +| `is_anonymous` | `#!python3 Optional[bool]` | Optional. True, if the poll needs to be anonymous, defaults to True | +| `type` | `#!python3 Optional[str]` | Optional. Poll type, 'quiz' or 'regular', defaults to 'regular' | +| `allows_multiple_answers` | `#!python3 Optional[bool]` | Optional. True, if the poll allows multiple answers, ignored for polls in quiz mode, defaults to False | +| `correct_option_id` | `#!python3 Optional[int]` | Optional. 0-based identifier of the correct answer option, required for polls in quiz mode | +| `is_closed` | `#!python3 Optional[bool]` | Optional. Pass True, if the poll needs to be immediately closed | | `disable_notification` | `#!python3 Optional[bool]` | Optional. Sends the message silently. Users will receive a notification with no sound. | | `reply_to_message_id` | `#!python3 Optional[int]` | Optional. If the message is a reply, ID of the original message | | `reply_markup` | `#!python3 Optional[Union[InlineKeyboardMarkup, ReplyKeyboardMarkup, ReplyKeyboardRemove, ForceReply]]` | Optional. Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove reply keyboard or to force a reply from the user. | diff --git a/docs/api/types/keyboard_button.md b/docs/api/types/keyboard_button.md index b9e4fbd3..9177caa2 100644 --- a/docs/api/types/keyboard_button.md +++ b/docs/api/types/keyboard_button.md @@ -2,9 +2,11 @@ ## Description -This object represents one button of the reply keyboard. For simple text buttons String can be used instead of this object to specify text of the button. Optional fields are mutually exclusive. +This object represents one button of the reply keyboard. For simple text buttons String can be used instead of this object to specify text of the button. Optional fields request_contact, request_location, and request_poll are mutually exclusive. -Note: request_contact and request_location options will only work in Telegram versions released after 9 April, 2016. Older clients will ignore them. +Note: request_contact and request_location options will only work in Telegram versions released after 9 April, 2016. Older clients will receive unsupported message. + +Note: request_poll option will only work in Telegram versions released after 23 January, 2020. Older clients will receive unsupported message. ## Attributes @@ -14,6 +16,7 @@ Note: request_contact and request_location options will only work in Telegram ve | `text` | `#!python str` | Text of the button. If none of the optional fields are used, it will be sent as a message when the button is pressed | | `request_contact` | `#!python Optional[bool]` | Optional. If True, the user's phone number will be sent as a contact when the button is pressed. Available in private chats only | | `request_location` | `#!python Optional[bool]` | Optional. If True, the user's current location will be sent when the button is pressed. Available in private chats only | +| `request_poll` | `#!python Optional[KeyboardButtonPollType]` | Optional. If specified, the user will be asked to create a poll and send it to the bot when the button is pressed. Available in private chats only | @@ -26,3 +29,4 @@ Note: request_contact and request_location options will only work in Telegram ve ## Related pages: - [Official documentation](https://core.telegram.org/bots/api#keyboardbutton) +- [aiogram.types.KeyboardButtonPollType](../types/keyboard_button_poll_type.md) diff --git a/docs/api/types/keyboard_button_poll_type.md b/docs/api/types/keyboard_button_poll_type.md new file mode 100644 index 00000000..ed659fb8 --- /dev/null +++ b/docs/api/types/keyboard_button_poll_type.md @@ -0,0 +1,24 @@ +# KeyboardButtonPollType + +## Description + +This object represents type of a poll, which is allowed to be created and sent when the corresponding button is pressed. + + +## Attributes + +| Name | Type | Description | +| - | - | - | +| `type` | `#!python Optional[str]` | Optional. If quiz is passed, the user will be allowed to create only polls in the quiz mode. If regular is passed, only regular polls will be allowed. Otherwise, the user will be allowed to create a poll of any type. | + + + +## Location + +- `from aiogram.types import KeyboardButtonPollType` +- `from aiogram.api.types import KeyboardButtonPollType` +- `from aiogram.api.types.keyboard_button_poll_type import KeyboardButtonPollType` + +## Related pages: + +- [Official documentation](https://core.telegram.org/bots/api#keyboardbuttonpolltype) diff --git a/docs/api/types/message_entity.md b/docs/api/types/message_entity.md index 702d7701..d68d269e 100644 --- a/docs/api/types/message_entity.md +++ b/docs/api/types/message_entity.md @@ -14,6 +14,7 @@ This object represents one special entity in a text message. For example, hashta | `length` | `#!python int` | Length of the entity in UTF-16 code units | | `url` | `#!python Optional[str]` | Optional. For 'text_link' only, url that will be opened after user taps on the text | | `user` | `#!python Optional[User]` | Optional. For 'text_mention' only, the mentioned user | +| `language` | `#!python Optional[str]` | Optional. For 'pre' only, the programming language of the entity text | diff --git a/docs/api/types/poll.md b/docs/api/types/poll.md index 0a518622..421a816d 100644 --- a/docs/api/types/poll.md +++ b/docs/api/types/poll.md @@ -12,7 +12,12 @@ This object contains information about a poll. | `id` | `#!python str` | Unique poll identifier | | `question` | `#!python str` | Poll question, 1-255 characters | | `options` | `#!python List[PollOption]` | List of poll options | +| `total_voter_count` | `#!python int` | Total number of users that voted in the poll | | `is_closed` | `#!python bool` | True, if the poll is closed | +| `is_anonymous` | `#!python bool` | True, if the poll is anonymous | +| `type` | `#!python str` | Poll type, currently can be 'regular' or 'quiz' | +| `allows_multiple_answers` | `#!python bool` | True, if the poll allows multiple answers | +| `correct_option_id` | `#!python Optional[int]` | 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. | diff --git a/docs/api/types/poll_answer.md b/docs/api/types/poll_answer.md new file mode 100644 index 00000000..ff3552bf --- /dev/null +++ b/docs/api/types/poll_answer.md @@ -0,0 +1,27 @@ +# PollAnswer + +## Description + +This object represents an answer of a user in a non-anonymous poll. + + +## Attributes + +| Name | Type | Description | +| - | - | - | +| `poll_id` | `#!python str` | Unique poll identifier | +| `user` | `#!python User` | The user, who changed the answer to the poll | +| `option_ids` | `#!python List[int]` | 0-based identifiers of answer options, chosen by the user. May be empty if the user retracted their vote. | + + + +## Location + +- `from aiogram.types import PollAnswer` +- `from aiogram.api.types import PollAnswer` +- `from aiogram.api.types.poll_answer import PollAnswer` + +## Related pages: + +- [Official documentation](https://core.telegram.org/bots/api#pollanswer) +- [aiogram.types.User](../types/user.md) diff --git a/docs/api/types/update.md b/docs/api/types/update.md index 78a8d241..4994ed91 100644 --- a/docs/api/types/update.md +++ b/docs/api/types/update.md @@ -22,6 +22,7 @@ At most one of the optional parameters can be present in any given update. | `shipping_query` | `#!python Optional[ShippingQuery]` | Optional. New incoming shipping query. Only for invoices with flexible price | | `pre_checkout_query` | `#!python Optional[PreCheckoutQuery]` | Optional. New incoming pre-checkout query. Contains full information about checkout | | `poll` | `#!python Optional[Poll]` | Optional. New poll state. Bots receive only updates about stopped polls and polls, which are sent by the bot | +| `poll_answer` | `#!python Optional[PollAnswer]` | Optional. A user changed their answer in a non-anonymous poll. Bots receive new votes only in polls that were sent by the bot itself. | @@ -39,5 +40,6 @@ At most one of the optional parameters can be present in any given update. - [aiogram.types.InlineQuery](../types/inline_query.md) - [aiogram.types.Message](../types/message.md) - [aiogram.types.Poll](../types/poll.md) +- [aiogram.types.PollAnswer](../types/poll_answer.md) - [aiogram.types.PreCheckoutQuery](../types/pre_checkout_query.md) - [aiogram.types.ShippingQuery](../types/shipping_query.md) diff --git a/docs/api/types/user.md b/docs/api/types/user.md index 5925fb14..5860e1ea 100644 --- a/docs/api/types/user.md +++ b/docs/api/types/user.md @@ -15,6 +15,9 @@ This object represents a Telegram user or bot. | `last_name` | `#!python Optional[str]` | Optional. User‘s or bot’s last name | | `username` | `#!python Optional[str]` | Optional. User‘s or bot’s username | | `language_code` | `#!python Optional[str]` | Optional. IETF language tag of the user's language | +| `can_join_groups` | `#!python Optional[bool]` | Optional. True, if the bot can be invited to groups. Returned only in getMe. | +| `can_read_all_group_messages` | `#!python Optional[bool]` | Optional. True, if privacy mode is disabled for the bot. Returned only in getMe. | +| `supports_inline_queries` | `#!python Optional[bool]` | Optional. True, if the bot supports inline queries. Returned only in getMe. | diff --git a/tests/test_dispatcher/test_handler/test_callback_query.py b/tests/test_dispatcher/test_handler/test_callback_query.py index d41ffb9e..c63381de 100644 --- a/tests/test_dispatcher/test_handler/test_callback_query.py +++ b/tests/test_dispatcher/test_handler/test_callback_query.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import CallbackQuery, User from aiogram.dispatcher.handler import CallbackQueryHandler diff --git a/tests/test_dispatcher/test_handler/test_chosen_inline_result.py b/tests/test_dispatcher/test_handler/test_chosen_inline_result.py index e92f2f11..66ccde90 100644 --- a/tests/test_dispatcher/test_handler/test_chosen_inline_result.py +++ b/tests/test_dispatcher/test_handler/test_chosen_inline_result.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import CallbackQuery, ChosenInlineResult, User from aiogram.dispatcher.handler import ChosenInlineResultHandler diff --git a/tests/test_dispatcher/test_handler/test_inline_query.py b/tests/test_dispatcher/test_handler/test_inline_query.py index 045d014e..19c454da 100644 --- a/tests/test_dispatcher/test_handler/test_inline_query.py +++ b/tests/test_dispatcher/test_handler/test_inline_query.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import CallbackQuery, InlineQuery, User from aiogram.dispatcher.handler import InlineQueryHandler diff --git a/tests/test_dispatcher/test_handler/test_poll.py b/tests/test_dispatcher/test_handler/test_poll.py index 6a84dda4..84f7496a 100644 --- a/tests/test_dispatcher/test_handler/test_poll.py +++ b/tests/test_dispatcher/test_handler/test_poll.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import ( CallbackQuery, InlineQuery, diff --git a/tests/test_dispatcher/test_handler/test_pre_checkout_query.py b/tests/test_dispatcher/test_handler/test_pre_checkout_query.py index 7bab017a..159d541e 100644 --- a/tests/test_dispatcher/test_handler/test_pre_checkout_query.py +++ b/tests/test_dispatcher/test_handler/test_pre_checkout_query.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import PreCheckoutQuery, User from aiogram.dispatcher.handler import PreCheckoutQueryHandler diff --git a/tests/test_dispatcher/test_handler/test_shipping_query.py b/tests/test_dispatcher/test_handler/test_shipping_query.py index d0902fdf..0df94218 100644 --- a/tests/test_dispatcher/test_handler/test_shipping_query.py +++ b/tests/test_dispatcher/test_handler/test_shipping_query.py @@ -1,6 +1,7 @@ from typing import Any import pytest + from aiogram.api.types import CallbackQuery, InlineQuery, ShippingAddress, ShippingQuery, User from aiogram.dispatcher.handler import ShippingQueryHandler