Skip to content

API 4.6 #1850

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed

API 4.6 #1850

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ jobs:
run: |
pytest -v tests/test_official.py
exit $?
continue-on-error: True
env:
TEST_OFFICIAL: "true"
shell: bash --noprofile --norc {0}
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ make the development of bots easy and straightforward. These classes are contain
Telegram API support
====================

All types and methods of the Telegram Bot API **4.5** are supported.
All types and methods of the Telegram Bot API **4.6** are supported.

==========
Installing
Expand Down
6 changes: 6 additions & 0 deletions docs/source/telegram.keyboardbuttonpolltype.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
telegram.KeyboardButtonPollType
===============================

.. autoclass:: telegram.KeyboardButtonPollType
:members:
:show-inheritance:
6 changes: 6 additions & 0 deletions docs/source/telegram.pollanswer.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
telegram.PollAnswer
===================

.. autoclass:: telegram.PollAnswer
:members:
:show-inheritance:
2 changes: 2 additions & 0 deletions docs/source/telegram.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,15 @@ telegram package
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.keyboardbutton
telegram.keyboardbuttonpolltype
telegram.location
telegram.loginurl
telegram.message
telegram.messageentity
telegram.parsemode
telegram.photosize
telegram.poll
telegram.pollanswer
telegram.polloption
telegram.replykeyboardremove
telegram.replykeyboardmarkup
Expand Down
147 changes: 147 additions & 0 deletions examples/pollbot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This program is dedicated to the public domain under the CC0 license.

"""
Basic example for a bot that works with polls. Only 3 people are allowed to interact with each
poll/quiz the bot generates. The preview command generates a closed poll/quiz, excatly like the
one the user sends the bot
"""
import logging

from telegram import (Poll, ParseMode, KeyboardButton, KeyboardButtonPollType,
ReplyKeyboardMarkup, ReplyKeyboardRemove)
from telegram.ext import (Updater, CommandHandler, PollAnswerHandler, PollHandler, MessageHandler,
Filters)
from telegram.utils.helpers import mention_html

logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO)
logger = logging.getLogger(__name__)


def start(update, context):
"""Inform user about what this bot can do"""
update.message.reply_text('Please select /poll to get a Poll, /quiz to get a Quiz or /preview'
' to generate a preview for your poll')


def poll(update, context):
"""Sends a predefined poll"""
questions = ["Good", "Really good", "Fantastic", "Great"]
message = context.bot.send_poll(update.effective_user.id, "How are you?", questions,
is_anonymous=False, allows_multiple_answers=True)
# Save some info about the poll the bot_data for later use in receive_poll_answer
payload = {message.poll.id: {"questions": questions, "message_id": message.message_id,
"chat_id": update.effective_chat.id, "answers": 0}}
context.bot_data.update(payload)


def receive_poll_answer(update, context):
"""Summarize a users poll vote"""
answer = update.poll_answer
poll_id = answer.poll_id
try:
questions = context.bot_data[poll_id]["questions"]
# this means this poll answer update is from an old poll, we can't do our answering then
except KeyError:
return
selected_options = answer.option_ids
answer_string = ""
for question_id in selected_options:
if question_id != selected_options[-1]:
answer_string += questions[question_id] + " and "
else:
answer_string += questions[question_id]
user_mention = mention_html(update.effective_user.id, update.effective_user.full_name)
context.bot.send_message(context.bot_data[poll_id]["chat_id"],
"{} feels {}!".format(user_mention, answer_string),
parse_mode=ParseMode.HTML)
context.bot_data[poll_id]["answers"] += 1
# Close poll after three participants voted
if context.bot_data[poll_id]["answers"] == 3:
context.bot.stop_poll(context.bot_data[poll_id]["chat_id"],
context.bot_data[poll_id]["message_id"])


def quiz(update, context):
"""Send a predefined poll"""
questions = ["1", "2", "4", "20"]
message = update.effective_message.reply_poll("How many eggs do you need for a cake?",
questions, type=Poll.QUIZ, correct_option_id=2)
# Save some info about the poll the bot_data for later use in receive_quiz_answer
payload = {message.poll.id: {"chat_id": update.effective_chat.id,
"message_id": message.message_id}}
context.bot_data.update(payload)


def receive_quiz_answer(update, context):
"""Close quiz after three participants took it"""
# the bot can receive closed poll updates we don't care about
if update.poll.is_closed:
return
if update.poll.total_voter_count == 3:
try:
quiz_data = context.bot_data[update.poll.id]
# this means this poll answer update is from an old poll, we can't stop it then
except KeyError:
return
context.bot.stop_poll(quiz_data["chat_id"], quiz_data["message_id"])


def preview(update, context):
"""Ask user to create a poll and display a preview of it"""
# using this without a type lets the user chooses what he wants (quiz or poll)
button = [[KeyboardButton("Press me!", request_poll=KeyboardButtonPollType())]]
message = "Press the button to let the bot generate a preview for your poll"
# using one_time_keyboard to hide the keyboard
update.effective_message.reply_text(message,
reply_markup=ReplyKeyboardMarkup(button,
one_time_keyboard=True))


def receive_poll(update, context):
"""On receiving polls, reply to it by a closed poll copying the received poll"""
actual_poll = update.effective_message.poll
# Only need to set the question and options, since all other parameters don't matter for
# a closed poll
update.effective_message.reply_poll(
question=actual_poll.question,
options=[o.text for o in actual_poll.options],
# with is_closed true, the poll/quiz is immediately closed
is_closed=True,
reply_markup=ReplyKeyboardRemove()
)


def help_handler(update, context):
"""Display a help message"""
update.message.reply_text("Use /quiz, /poll or /preview to test this "
"bot.")


def main():
# Create the Updater and pass it your bot's token.
# Make sure to set use_context=True to use the new context based callbacks
# Post version 12 this will no longer be necessary
updater = Updater("TOKEN", use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler('start', start))
dp.add_handler(CommandHandler('poll', poll))
dp.add_handler(PollAnswerHandler(receive_poll_answer))
dp.add_handler(CommandHandler('quiz', quiz))
dp.add_handler(PollHandler(receive_quiz_answer))
dp.add_handler(CommandHandler('preview', preview))
dp.add_handler(MessageHandler(Filters.poll, receive_poll))
dp.add_handler(CommandHandler('help', help_handler))

# Start the Bot
updater.start_polling()

# Run the bot until the user presses Ctrl-C or the process receives SIGINT,
# SIGTERM or SIGABRT
updater.idle()


if __name__ == '__main__':
main()
7 changes: 4 additions & 3 deletions telegram/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from .chataction import ChatAction
from .userprofilephotos import UserProfilePhotos
from .keyboardbutton import KeyboardButton
from .keyboardbuttonpolltype import KeyboardButtonPollType
from .replymarkup import ReplyMarkup
from .replykeyboardmarkup import ReplyKeyboardMarkup
from .replykeyboardremove import ReplyKeyboardRemove
Expand All @@ -48,7 +49,7 @@
from .parsemode import ParseMode
from .messageentity import MessageEntity
from .games.game import Game
from .poll import Poll, PollOption
from .poll import Poll, PollOption, PollAnswer
from .loginurl import LoginUrl
from .games.callbackgame import CallbackGame
from .payment.shippingaddress import ShippingAddress
Expand Down Expand Up @@ -138,7 +139,7 @@
'InlineQueryResultPhoto', 'InlineQueryResultVenue', 'InlineQueryResultVideo',
'InlineQueryResultVoice', 'InlineQueryResultGame', 'InputContactMessageContent', 'InputFile',
'InputLocationMessageContent', 'InputMessageContent', 'InputTextMessageContent',
'InputVenueMessageContent', 'KeyboardButton', 'Location', 'EncryptedCredentials',
'InputVenueMessageContent', 'Location', 'EncryptedCredentials',
'PassportFile', 'EncryptedPassportElement', 'PassportData', 'Message', 'MessageEntity',
'ParseMode', 'PhotoSize', 'ReplyKeyboardRemove', 'ReplyKeyboardMarkup', 'ReplyMarkup',
'Sticker', 'TelegramError', 'TelegramObject', 'Update', 'User', 'UserProfilePhotos', 'Venue',
Expand All @@ -156,5 +157,5 @@
'InputMediaAudio', 'InputMediaDocument', 'TelegramDecryptionError',
'PassportElementErrorSelfie', 'PassportElementErrorTranslationFile',
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified', 'Poll',
'PollOption', 'LoginUrl'
'PollOption', 'PollAnswer', 'LoginUrl', 'KeyboardButton', 'KeyboardButtonPollType',
]
49 changes: 48 additions & 1 deletion telegram/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,27 @@ def link(self):

return "https://t.me/{}".format(self.username)

@property
@info
def can_join_groups(self):
""":obj:`str`: Bot's can_join_groups attribute."""

return self.bot.can_join_groups

@property
@info
def can_read_all_group_messages(self):
""":obj:`str`: Bot's can_read_all_group_messages attribute."""

return self.bot.can_read_all_group_messages

@property
@info
def supports_inline_queries(self):
""":obj:`str`: Bot's supports_inline_queries attribute."""

return self.bot.supports_inline_queries

@property
def name(self):
""":obj:`str`: Bot's @username."""
Expand Down Expand Up @@ -3492,18 +3513,33 @@ def send_poll(self,
chat_id,
question,
options,
is_anonymous=True,
type=Poll.REGULAR,
allows_multiple_answers=False,
correct_option_id=None,
is_closed=None,
disable_notification=None,
reply_to_message_id=None,
reply_markup=None,
timeout=None,
**kwargs):
"""
Use this method to send a native poll. A native poll can't be sent to a private chat.
Use this method to send a native poll.

Args:
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target private chat.
question (:obj:`str`): Poll question, 1-255 characters.
options (List[:obj:`str`]): List of answer options, 2-10 strings 1-100 characters each.
is_anonymous (:obj:`bool`, optional): True, if the poll needs to be anonymous,
defaults to True.
type (:obj:`str`, optional): Poll type, :attr:`telegram.Poll.QUIZ` or
:attr:`telegram.Poll.REGULAR`, defaults to :attr:`telegram.Poll.REGULAR`.
allows_multiple_answers (:obj:`bool`, optional): True, if the poll allows multiple
answers, ignored for polls in quiz mode, defaults to False
correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer
option, required for polls in quiz mode
is_closed (:obj:`bool`, optional): Pass True, if the poll needs to be immediately
closed. This can be useful for poll preview.
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
receive a notification with no sound.
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
Expand Down Expand Up @@ -3531,6 +3567,17 @@ def send_poll(self,
'options': options
}

if not is_anonymous:
data['is_anonymous'] = is_anonymous
if type:
data['type'] = type
if allows_multiple_answers:
data['allows_multiple_answers'] = allows_multiple_answers
if correct_option_id is not None:
data['correct_option_id'] = correct_option_id
if is_closed:
data['is_closed'] = is_closed

return self._message(url, data, timeout=timeout, disable_notification=disable_notification,
reply_to_message_id=reply_to_message_id, reply_markup=reply_markup,
**kwargs)
Expand Down
5 changes: 4 additions & 1 deletion telegram/ext/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,14 @@
from .messagequeue import MessageQueue
from .messagequeue import DelayQueue
from .defaults import Defaults
from .pollanswerhandler import PollAnswerHandler
from .pollhandler import PollHandler

__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler',
'MessageHandler', 'BaseFilter', 'Filters', 'RegexHandler', 'StringCommandHandler',
'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'BasePersistence',
'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'Defaults')
'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'PollAnswerHandler',
'PollHandler', 'Defaults')
Loading