mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 22:45:09 +01:00
Merge branch '4.3' into RC1
This commit is contained in:
commit
3fc57479f3
9 changed files with 246 additions and 18 deletions
|
@ -48,6 +48,7 @@ from .parsemode import ParseMode
|
|||
from .messageentity import MessageEntity
|
||||
from .games.game import Game
|
||||
from .poll import Poll, PollOption
|
||||
from .loginurl import LoginUrl
|
||||
from .games.callbackgame import CallbackGame
|
||||
from .payment.shippingaddress import ShippingAddress
|
||||
from .payment.orderinfo import OrderInfo
|
||||
|
@ -58,11 +59,11 @@ from .passport.passportfile import PassportFile
|
|||
from .passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
|
||||
from .passport.encryptedpassportelement import EncryptedPassportElement
|
||||
from .passport.passportdata import PassportData
|
||||
from .inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from .message import Message
|
||||
from .callbackquery import CallbackQuery
|
||||
from .choseninlineresult import ChosenInlineResult
|
||||
from .inline.inlinekeyboardbutton import InlineKeyboardButton
|
||||
from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup
|
||||
from .inline.inputmessagecontent import InputMessageContent
|
||||
from .inline.inlinequery import InlineQuery
|
||||
from .inline.inlinequeryresult import InlineQueryResult
|
||||
|
@ -153,5 +154,6 @@ __all__ = [
|
|||
'PersonalDetails', 'ResidentialAddress', 'InputMediaVideo', 'InputMediaAnimation',
|
||||
'InputMediaAudio', 'InputMediaDocument', 'TelegramDecryptionError',
|
||||
'PassportElementErrorSelfie', 'PassportElementErrorTranslationFile',
|
||||
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified', 'Poll', 'PollOption'
|
||||
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified', 'Poll',
|
||||
'PollOption', 'LoginUrl'
|
||||
]
|
||||
|
|
|
@ -31,6 +31,8 @@ class InlineKeyboardButton(TelegramObject):
|
|||
Attributes:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
url (:obj:`str`): Optional. HTTP url to be opened when button is pressed.
|
||||
login_url (:class:`telegram.LoginUrl`) Optional. An HTTP URL used to automatically
|
||||
authorize the user.
|
||||
callback_data (:obj:`str`): Optional. Data to be sent in a callback query to the bot when
|
||||
button is pressed, UTF-8 1-64 bytes.
|
||||
switch_inline_query (:obj:`str`): Optional. Will prompt the user to select one of their
|
||||
|
@ -45,6 +47,8 @@ class InlineKeyboardButton(TelegramObject):
|
|||
Args:
|
||||
text (:obj:`str`): Label text on the button.
|
||||
url (:obj:`str`): HTTP url to be opened when button is pressed.
|
||||
login_url (:class:`telegram.LoginUrl`, optional) An HTTP URL used to automatically
|
||||
authorize the user.
|
||||
callback_data (:obj:`str`, optional): Data to be sent in a callback query to the bot when
|
||||
button is pressed, 1-64 UTF-8 bytes.
|
||||
switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the
|
||||
|
@ -76,14 +80,30 @@ class InlineKeyboardButton(TelegramObject):
|
|||
switch_inline_query_current_chat=None,
|
||||
callback_game=None,
|
||||
pay=None,
|
||||
login_url=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.text = text
|
||||
|
||||
# Optionals
|
||||
if url:
|
||||
self.url = url
|
||||
if login_url:
|
||||
self.login_url = login_url
|
||||
if callback_data:
|
||||
self.callback_data = callback_data
|
||||
if switch_inline_query:
|
||||
self.switch_inline_query = switch_inline_query
|
||||
if switch_inline_query_current_chat:
|
||||
self.switch_inline_query_current_chat = switch_inline_query_current_chat
|
||||
if callback_game:
|
||||
self.callback_game = callback_game
|
||||
if pay:
|
||||
self.pay = pay
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return cls(**data)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram InlineKeyboardMarkup."""
|
||||
|
||||
from telegram import ReplyMarkup
|
||||
from telegram import ReplyMarkup, InlineKeyboardButton
|
||||
|
||||
|
||||
class InlineKeyboardMarkup(ReplyMarkup):
|
||||
|
@ -49,6 +49,19 @@ class InlineKeyboardMarkup(ReplyMarkup):
|
|||
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def de_json(cls, data, bot):
|
||||
if not data:
|
||||
return None
|
||||
keyboard = []
|
||||
for row in data['inline_keyboard']:
|
||||
tmp = []
|
||||
for col in row:
|
||||
tmp.append(InlineKeyboardButton.de_json(col, bot))
|
||||
keyboard.append(tmp)
|
||||
|
||||
return cls(keyboard)
|
||||
|
||||
@classmethod
|
||||
def from_button(cls, button, **kwargs):
|
||||
"""Shortcut for::
|
||||
|
|
65
telegram/loginurl.py
Normal file
65
telegram/loginurl.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
#!/usr/bin/env python
|
||||
# pylint: disable=R0903
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2019
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram LoginUrl."""
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class LoginUrl(TelegramObject):
|
||||
"""This object represents a parameter of the inline keyboard button used to automatically
|
||||
authorize a user. Serves as a great replacement for the Telegram Login Widget when the user is
|
||||
coming from Telegram. All the user needs to do is tap/click a button and confirm that they want
|
||||
to log in. Telegram apps support these buttons as of version 5.7.
|
||||
Sample bot: @discussbot
|
||||
|
||||
Attributes:
|
||||
url (:obj:`str`): An HTTP URL to be opened with user authorization data.
|
||||
forward_text (:obj:`str`): Optional. New text of the button in forwarded messages.
|
||||
bot_username (:obj:`str`): Optional. Username of a bot, which will be used for user
|
||||
authorization.
|
||||
request_write_access (:obj:`bool`): Optional. Pass True to request the permission for your
|
||||
bot to send messages to the user.
|
||||
|
||||
Args:
|
||||
url (:obj:`str`): An HTTP URL to be opened with user authorization data added to the query
|
||||
string when the button is pressed. If the user refuses to provide authorization data,
|
||||
the original URL without information about the user will be opened. The data added is
|
||||
the same as described in Receiving authorization data.
|
||||
NOTE: You must always check the hash of the received data to verify the authentication
|
||||
and the integrity of the data as described in Checking authorization.
|
||||
forward_text (:obj:`str`, optional): New text of the button in forwarded messages.
|
||||
bot_username (:obj:`str`, optional): Username of a bot, which will be used for user
|
||||
authorization. See Setting up a bot for more details. If not specified, the current
|
||||
bot's username will be assumed. The url's domain must be the same as the domain linked
|
||||
with the bot. See Linking your domain to the bot for more details.
|
||||
request_write_access (:obj:`bool`, optional): Pass True to request the permission for your
|
||||
bot to send messages to the user.
|
||||
"""
|
||||
|
||||
def __init__(self, url, forward_text=None, bot_username=None, request_write_access=None):
|
||||
self.url = url
|
||||
|
||||
if forward_text:
|
||||
self.forward_text = forward_text
|
||||
if bot_username:
|
||||
self.bot_username = bot_username
|
||||
if request_write_access:
|
||||
self.request_write_access = request_write_access
|
||||
|
||||
self._id_attrs = (self.url,)
|
|
@ -23,7 +23,7 @@ from html import escape
|
|||
|
||||
from telegram import (Animation, Audio, Contact, Document, Chat, Location, PhotoSize, Sticker,
|
||||
TelegramObject, User, Video, Voice, Venue, MessageEntity, Game, Invoice,
|
||||
SuccessfulPayment, VideoNote, PassportData, Poll)
|
||||
SuccessfulPayment, VideoNote, PassportData, Poll, InlineKeyboardMarkup)
|
||||
from telegram import ParseMode
|
||||
from telegram.utils.helpers import escape_markdown, to_timestamp, from_timestamp
|
||||
|
||||
|
@ -106,6 +106,8 @@ class Message(TelegramObject):
|
|||
passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data.
|
||||
poll (:class:`telegram.Poll`): Optional. Message is a native poll,
|
||||
information about the poll.
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
|
||||
to the message.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
|
@ -210,6 +212,9 @@ class Message(TelegramObject):
|
|||
passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data.
|
||||
poll (:class:`telegram.Poll`, optional): Message is a native poll,
|
||||
information about the poll.
|
||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
|
||||
to the message. login_url buttons are represented as ordinary url buttons.
|
||||
|
||||
"""
|
||||
|
||||
_effective_attachment = _UNDEFINED
|
||||
|
@ -270,6 +275,7 @@ class Message(TelegramObject):
|
|||
passport_data=None,
|
||||
poll=None,
|
||||
forward_sender_name=None,
|
||||
reply_markup=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
|
@ -320,7 +326,7 @@ class Message(TelegramObject):
|
|||
self.animation = animation
|
||||
self.passport_data = passport_data
|
||||
self.poll = poll
|
||||
|
||||
self.reply_markup = reply_markup
|
||||
self.bot = bot
|
||||
|
||||
self._id_attrs = (self.message_id,)
|
||||
|
@ -375,6 +381,7 @@ class Message(TelegramObject):
|
|||
data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
|
||||
data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot)
|
||||
data['poll'] = Poll.de_json(data.get('poll'), bot)
|
||||
data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot)
|
||||
|
||||
return cls(bot=bot, **data)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import InlineKeyboardButton
|
||||
from telegram import InlineKeyboardButton, LoginUrl
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
|
@ -31,7 +31,8 @@ def inline_keyboard_button():
|
|||
switch_inline_query_current_chat=TestInlineKeyboardButton
|
||||
.switch_inline_query_current_chat,
|
||||
callback_game=TestInlineKeyboardButton.callback_game,
|
||||
pay=TestInlineKeyboardButton.pay)
|
||||
pay=TestInlineKeyboardButton.pay,
|
||||
login_url=TestInlineKeyboardButton.login_url)
|
||||
|
||||
|
||||
class TestInlineKeyboardButton(object):
|
||||
|
@ -42,6 +43,7 @@ class TestInlineKeyboardButton(object):
|
|||
switch_inline_query_current_chat = 'switch_inline_query_current_chat'
|
||||
callback_game = 'callback_game'
|
||||
pay = 'pay'
|
||||
login_url = LoginUrl("http://google.com")
|
||||
|
||||
def test_expected_values(self, inline_keyboard_button):
|
||||
assert inline_keyboard_button.text == self.text
|
||||
|
@ -52,6 +54,7 @@ class TestInlineKeyboardButton(object):
|
|||
== self.switch_inline_query_current_chat)
|
||||
assert inline_keyboard_button.callback_game == self.callback_game
|
||||
assert inline_keyboard_button.pay == self.pay
|
||||
assert inline_keyboard_button.login_url == self.login_url
|
||||
|
||||
def test_to_dict(self, inline_keyboard_button):
|
||||
inline_keyboard_button_dict = inline_keyboard_button.to_dict()
|
||||
|
@ -66,3 +69,26 @@ class TestInlineKeyboardButton(object):
|
|||
== inline_keyboard_button.switch_inline_query_current_chat)
|
||||
assert inline_keyboard_button_dict['callback_game'] == inline_keyboard_button.callback_game
|
||||
assert inline_keyboard_button_dict['pay'] == inline_keyboard_button.pay
|
||||
assert inline_keyboard_button_dict['login_url'] == \
|
||||
inline_keyboard_button.login_url.to_dict() # NOQA: E127
|
||||
|
||||
def test_de_json(self, bot):
|
||||
json_dict = {
|
||||
'text': self.text,
|
||||
'url': self.url,
|
||||
'callback_data': self.callback_data,
|
||||
'switch_inline_query': self.switch_inline_query,
|
||||
'switch_inline_query_current_chat': self.switch_inline_query_current_chat,
|
||||
'callback_game': self.callback_game,
|
||||
'pay': self.pay
|
||||
}
|
||||
|
||||
inline_keyboard_button = InlineKeyboardButton.de_json(json_dict, None)
|
||||
assert inline_keyboard_button.text == self.text
|
||||
assert inline_keyboard_button.url == self.url
|
||||
assert inline_keyboard_button.callback_data == self.callback_data
|
||||
assert inline_keyboard_button.switch_inline_query == self.switch_inline_query
|
||||
assert (inline_keyboard_button.switch_inline_query_current_chat
|
||||
== self.switch_inline_query_current_chat)
|
||||
assert inline_keyboard_button.callback_game == self.callback_game
|
||||
assert inline_keyboard_button.pay == self.pay
|
||||
|
|
|
@ -78,3 +78,34 @@ class TestInlineKeyboardMarkup(object):
|
|||
self.inline_keyboard[0][1].to_dict()
|
||||
]
|
||||
]
|
||||
|
||||
def test_de_json(self):
|
||||
json_dict = {
|
||||
'inline_keyboard': [[
|
||||
{
|
||||
'text': 'start',
|
||||
'url': 'http://google.com'
|
||||
},
|
||||
{
|
||||
'text': 'next',
|
||||
'callback_data': 'abcd'
|
||||
}],
|
||||
[{
|
||||
'text': 'Cancel',
|
||||
'callback_data': 'Cancel'
|
||||
}]
|
||||
]}
|
||||
inline_keyboard_markup = InlineKeyboardMarkup.de_json(json_dict, None)
|
||||
|
||||
assert isinstance(inline_keyboard_markup, InlineKeyboardMarkup)
|
||||
keyboard = inline_keyboard_markup.inline_keyboard
|
||||
assert len(keyboard) == 2
|
||||
assert len(keyboard[0]) == 2
|
||||
assert len(keyboard[1]) == 1
|
||||
|
||||
assert isinstance(keyboard[0][0], InlineKeyboardButton)
|
||||
assert isinstance(keyboard[0][1], InlineKeyboardButton)
|
||||
assert isinstance(keyboard[1][0], InlineKeyboardButton)
|
||||
|
||||
assert keyboard[0][0].text == 'start'
|
||||
assert keyboard[0][0].url == 'http://google.com'
|
||||
|
|
61
tests/test_loginurl.py
Normal file
61
tests/test_loginurl.py
Normal file
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2019
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import LoginUrl
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def login_url():
|
||||
return LoginUrl(url=TestLoginUrl.url, forward_text=TestLoginUrl.forward_text,
|
||||
bot_username=TestLoginUrl.bot_username,
|
||||
request_write_access=TestLoginUrl.request_write_access)
|
||||
|
||||
|
||||
class TestLoginUrl(object):
|
||||
url = "http://www.google.com"
|
||||
forward_text = "Send me forward!"
|
||||
bot_username = "botname"
|
||||
request_write_access = True
|
||||
|
||||
def test_to_dict(self, login_url):
|
||||
login_url_dict = login_url.to_dict()
|
||||
|
||||
assert isinstance(login_url_dict, dict)
|
||||
assert login_url_dict['url'] == self.url
|
||||
assert login_url_dict['forward_text'] == self.forward_text
|
||||
assert login_url_dict['bot_username'] == self.bot_username
|
||||
assert login_url_dict['request_write_access'] == self.request_write_access
|
||||
|
||||
def test_equality(self):
|
||||
a = LoginUrl(self.url, self.forward_text, self.bot_username, self.request_write_access)
|
||||
b = LoginUrl(self.url, self.forward_text, self.bot_username, self.request_write_access)
|
||||
c = LoginUrl(self.url)
|
||||
d = LoginUrl("text.com", self.forward_text, self.bot_username, self.request_write_access)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a == c
|
||||
assert hash(a) == hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
|
@ -20,10 +20,9 @@ from datetime import datetime
|
|||
|
||||
import pytest
|
||||
|
||||
from telegram import ParseMode, Poll, PollOption
|
||||
from telegram import (Update, Message, User, MessageEntity, Chat, Audio, Document, Animation,
|
||||
Game, PhotoSize, Sticker, Video, Voice, VideoNote, Contact, Location, Venue,
|
||||
Invoice, SuccessfulPayment, PassportData)
|
||||
Invoice, SuccessfulPayment, PassportData, ParseMode, Poll, PollOption)
|
||||
from tests.test_passport import RAW_PASSPORT_DATA
|
||||
|
||||
|
||||
|
@ -91,7 +90,11 @@ def message(bot):
|
|||
{'passport_data': PassportData.de_json(RAW_PASSPORT_DATA, None)},
|
||||
{'poll': Poll(id='abc', question='What is this?',
|
||||
options=[PollOption(text='a', voter_count=1),
|
||||
PollOption(text='b', voter_count=2)], is_closed=False)}
|
||||
PollOption(text='b', voter_count=2)], is_closed=False)},
|
||||
{'text': 'a text message', 'reply_markup': {'inline_keyboard': [[{
|
||||
'text': 'start', 'url': 'http://google.com'}, {
|
||||
'text': 'next', 'callback_data': 'abcd'}],
|
||||
[{'text': 'Cancel', 'callback_data': 'Cancel'}]]}}
|
||||
],
|
||||
ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text',
|
||||
'caption_entities', 'audio', 'document', 'animation', 'game', 'photo',
|
||||
|
@ -100,7 +103,7 @@ def message(bot):
|
|||
'group_created', 'supergroup_created', 'channel_created', 'migrated_to',
|
||||
'migrated_from', 'pinned', 'invoice', 'successful_payment',
|
||||
'connected_website', 'forward_signature', 'author_signature',
|
||||
'photo_from_media_group', 'passport_data', 'poll'])
|
||||
'photo_from_media_group', 'passport_data', 'poll', 'reply_markup'])
|
||||
def message_params(bot, request):
|
||||
return Message(message_id=TestMessage.id,
|
||||
from_user=TestMessage.from_user,
|
||||
|
|
Loading…
Reference in a new issue