From 042d4bb2a4853c5a668063c7b06d493b980be01f Mon Sep 17 00:00:00 2001 From: Eldinnie Date: Fri, 8 Dec 2017 22:38:59 +0100 Subject: [PATCH] add support for 3.5 api (#920) * add support for 3.5 api * removed "unused" import by accident * Hardcoded values Appearantly TG decided to change the size of a send image (again) * test_official * Improve coverage * Finishing up * spelling error * pytest fixed tot < than 3.3 for python 3.3 support * flake8 * rollback requirements * as per CR * object for provider_data Make it possible to send an object that will be json-serialized for send_invoice + tests * shorten error message * using string_types --- docs/source/telegram.inputmedia.rst | 6 + docs/source/telegram.inputmediaphoto.rst | 6 + docs/source/telegram.inputmediavideo.rst | 6 + docs/source/telegram.rst | 3 + telegram/__init__.py | 6 +- telegram/bot.py | 72 ++++++++++-- telegram/files/inputmedia.py | 31 +++++ telegram/files/inputmediaphoto.py | 57 +++++++++ telegram/files/inputmediavideo.py | 74 ++++++++++++ telegram/message.py | 6 + tests/test_bot.py | 4 +- tests/test_inputmedia.py | 140 +++++++++++++++++++++++ tests/test_invoice.py | 23 ++++ tests/test_message.py | 7 +- tests/test_official.py | 3 +- tests/test_photo.py | 6 +- 16 files changed, 434 insertions(+), 16 deletions(-) create mode 100644 docs/source/telegram.inputmedia.rst create mode 100644 docs/source/telegram.inputmediaphoto.rst create mode 100644 docs/source/telegram.inputmediavideo.rst create mode 100644 telegram/files/inputmedia.py create mode 100644 telegram/files/inputmediaphoto.py create mode 100644 telegram/files/inputmediavideo.py create mode 100644 tests/test_inputmedia.py diff --git a/docs/source/telegram.inputmedia.rst b/docs/source/telegram.inputmedia.rst new file mode 100644 index 000000000..26b9d76eb --- /dev/null +++ b/docs/source/telegram.inputmedia.rst @@ -0,0 +1,6 @@ +telegram.InputMedia +=================== + +.. autoclass:: telegram.InputMedia + :members: + :show-inheritance: diff --git a/docs/source/telegram.inputmediaphoto.rst b/docs/source/telegram.inputmediaphoto.rst new file mode 100644 index 000000000..07bfe307f --- /dev/null +++ b/docs/source/telegram.inputmediaphoto.rst @@ -0,0 +1,6 @@ +telegram.InputMediaPhoto +======================== + +.. autoclass:: telegram.InputMediaPhoto + :members: + :show-inheritance: diff --git a/docs/source/telegram.inputmediavideo.rst b/docs/source/telegram.inputmediavideo.rst new file mode 100644 index 000000000..af28e4667 --- /dev/null +++ b/docs/source/telegram.inputmediavideo.rst @@ -0,0 +1,6 @@ +telegram.InputMediaVideo +======================== + +.. autoclass:: telegram.InputMediaVideo + :members: + :show-inheritance: diff --git a/docs/source/telegram.rst b/docs/source/telegram.rst index b28bb5cf2..59441f2e5 100644 --- a/docs/source/telegram.rst +++ b/docs/source/telegram.rst @@ -21,6 +21,9 @@ telegram package telegram.inlinekeyboardbutton telegram.inlinekeyboardmarkup telegram.inputfile + telegram.inputmedia + telegram.inputmediaphoto + telegram.inputmediavideo telegram.keyboardbutton telegram.location telegram.message diff --git a/telegram/__init__.py b/telegram/__init__.py index fcc4b3add..be2cf5d54 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -96,6 +96,9 @@ from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOO MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD, MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND, MAX_MESSAGES_PER_MINUTE_PER_GROUP) +from .files.inputmedia import InputMedia +from .files.inputmediavideo import InputMediaVideo +from .files.inputmediaphoto import InputMediaPhoto from .version import __version__ # flake8: noqa __author__ = 'devs@python-telegram-bot.org' @@ -121,5 +124,6 @@ __all__ = [ 'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation', 'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption', 'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto', - 'StickerSet', 'MaskPosition', 'CallbackGame' + 'StickerSet', 'MaskPosition', 'CallbackGame', 'InputMedia', 'InputMediaPhoto', + 'InputMediaVideo' ] diff --git a/telegram/bot.py b/telegram/bot.py index 3c976d31d..ef66cf7df 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -21,10 +21,13 @@ """This module contains an object that represents a Telegram Bot.""" import functools +import json import logging import warnings from datetime import datetime +from future.utils import string_types + from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File, ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore, StickerSet, PhotoSize, Audio, Document, Sticker, Video, Voice, VideoNote, Location, @@ -335,7 +338,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, **kwargs): """Use this method to send photos. @@ -394,7 +397,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, **kwargs): """ Use this method to send audio files, if you want Telegram clients to display them in the @@ -465,7 +468,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, **kwargs): """Use this method to send general files. @@ -576,7 +579,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, width=None, height=None, **kwargs): @@ -646,7 +649,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, **kwargs): """ Use this method to send audio files, if you want Telegram clients to display the file @@ -708,7 +711,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, - timeout=20., + timeout=20, **kwargs): """Use this method to send video messages. @@ -757,6 +760,51 @@ class Bot(TelegramObject): return url, data + @log + def send_media_group(self, + chat_id, + media, + disable_notification=None, + reply_to_message_id=None, + timeout=20, + **kwargs): + """Use this method to send a group of photos or videos as an album. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format @channelusername). + media (List[:class:`telegram.InputMedia`]): An array describing photos and videos to be + sent, must include 2–10 items. + 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 + original message. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Returns: + List[:class:`telegram.Message`]: An array of the sent Messages. + + Raises: + :class:`telegram.TelegramError` + """ + # TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files + + url = '{0}/sendMediaGroup'.format(self.base_url) + + media = [med.to_dict() for med in media] + + data = {'chat_id': chat_id, 'media': media} + + if reply_to_message_id: + data['reply_to_message_id'] = reply_to_message_id + if disable_notification: + data['disable_notification'] = disable_notification + + result = self._request.post(url, data, timeout=timeout) + + return [Message.de_json(res, self) for res in result] + @log @message def send_location(self, @@ -2153,6 +2201,7 @@ class Bot(TelegramObject): disable_notification=False, reply_to_message_id=None, reply_markup=None, + provider_data=None, timeout=None, **kwargs): """Use this method to send invoices. @@ -2169,6 +2218,10 @@ class Bot(TelegramObject): currency (:obj:`str`): Three-letter ISO 4217 currency code. prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list of components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). + provider_data (:obj:`str` | :obj:`object`, optional): JSON-encoded data about the + invoice, which will be shared with the payment provider. A detailed description of + required fields should be provided by the payment provider. When an object is + passed, it will be encoded as JSON. photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a photo of the goods or a marketing image for a service. People like it better when they see what they are paying for. @@ -2216,7 +2269,11 @@ class Bot(TelegramObject): 'currency': currency, 'prices': [p.to_dict() for p in prices] } - + if provider_data is not None: + if isinstance(provider_data, string_types): + data['provider_data'] = provider_data + else: + data['provider_data'] = json.dumps(provider_data) if photo_url is not None: data['photo_url'] = photo_url if photo_size is not None: @@ -2965,6 +3022,7 @@ class Bot(TelegramObject): sendVideo = send_video sendVoice = send_voice sendVideoNote = send_video_note + sendMediaGroup = send_media_group sendLocation = send_location editMessageLiveLocation = edit_message_live_location stopMessageLiveLocation = stop_message_live_location diff --git a/telegram/files/inputmedia.py b/telegram/files/inputmedia.py new file mode 100644 index 000000000..2943a6693 --- /dev/null +++ b/telegram/files/inputmedia.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2017 +# Leandro Toledo de Souza +# +# 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/]. +"""Base class for Telegram InputMedia Objects.""" + +from telegram import TelegramObject + + +class InputMedia(TelegramObject): + """Base class for Telegram InputMedia Objects. + + See :class:`telegram.InputMediaPhoto` and :class:`telegram.InputMediaVideo` for + detailed use. + + """ + pass diff --git a/telegram/files/inputmediaphoto.py b/telegram/files/inputmediaphoto.py new file mode 100644 index 000000000..1acd32e1e --- /dev/null +++ b/telegram/files/inputmediaphoto.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2017 +# Leandro Toledo de Souza +# +# 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 InputMediaPhoto.""" +from telegram import InputMedia, PhotoSize + + +class InputMediaPhoto(InputMedia): + """Represents a photo to be sent. + + Attributes: + type (:obj:`str`): ``photo``. + media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the + Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the + Internet. Lastly you can pass an existing :class:`telegram.PhotoSize` object to send. + caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-200 characters. + + Args: + media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the + Telegram servers (recommended), pass an HTTP URL for Telegram to get a file from the + Internet. Lastly you can pass an existing :class:`telegram.PhotoSize` object to send. + caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-200 characters. + + Note: + At the moment using a new file is not yet supported. + """ + + # TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files + + def __init__(self, media, caption=None): + self.type = 'photo' + + if isinstance(media, PhotoSize): + self.media = media.file_id + elif hasattr(media, 'read'): + raise ValueError( + 'Sending files is not supported (yet). Use file_id, url or PhotoSize') + else: + self.media = media + + if caption: + self.caption = caption diff --git a/telegram/files/inputmediavideo.py b/telegram/files/inputmediavideo.py new file mode 100644 index 000000000..ff9c3a562 --- /dev/null +++ b/telegram/files/inputmediavideo.py @@ -0,0 +1,74 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2017 +# Leandro Toledo de Souza +# +# 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 InputMediaPhoto.""" +from telegram import InputMedia, Video + + +class InputMediaVideo(InputMedia): + """Represents a video to be sent. + + Attributes: + type (:obj:`str`): ``video``. + media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram + servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet. + Lastly you can pass an existing :class:`telegram.Video` object to send. + caption (:obj:`str`): Optional. Caption of the video to be sent, 0-200 characters. + width (:obj:`int`): Optional. Video width. + height (:obj:`int`): Optional. Video height. + duration (:obj:`int`): Optional. Video duration. + + Args: + media (:obj:`str`): File to send. Pass a file_id to send a file that exists on the Telegram + servers (recommended), pass an HTTP URL for Telegram to get a file from the Internet. + Lastly you can pass an existing :class:`telegram.Video` object to send. + caption (:obj:`str`, optional): Caption of the video to be sent, 0-200 characters. + width (:obj:`int`, optional): Video width. + height (:obj:`int`, optional): Video height. + duration (:obj:`int`, optional): Video duration. + + Note: + When using a :class:`telegram.Video` for the :attr:`media` attribute. It will take the + width, height and duration from that video, unless otherwise specified with the optional + arguments. + At the moment using a new file is not yet supported. + """ + + # TODO: Make InputMediaPhoto, InputMediaVideo and send_media_group work with new files + + def __init__(self, media, caption=None, width=None, height=None, duration=None): + self.type = 'video' + + if isinstance(media, Video): + self.media = media.file_id + self.width = media.width + self.height = media.height + self.duration = media.duration + elif hasattr(media, 'read'): + raise ValueError('Sending files is not supported (yet). Use file_id, url or Video') + else: + self.media = media + + if caption: + self.caption = caption + if width: + self.width = width + if height: + self.height = height + if duration: + self.duration = duration diff --git a/telegram/message.py b/telegram/message.py index d912a8812..8d1e27b4f 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -48,6 +48,8 @@ class Message(TelegramObject): forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent. reply_to_message (:class:`telegram.Message`): Optional. The original message. edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited. + media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this + message belongs to. text (:obj:`str`): Optional. The actual UTF-8 text of the message. entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like usernames, URLs, bot commands, etc. that appear in the text. See @@ -117,6 +119,8 @@ class Message(TelegramObject): ``reply_to_message`` fields even if it itself is a reply. edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix time. Converted to :class:`datetime.datetime`. + media_group_id (:obj:`str`, optional): The unique identifier of a media message group this + message belongs to. text (str, optional): For text messages, the actual UTF-8 text of the message, 0-4096 characters. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special @@ -232,6 +236,7 @@ class Message(TelegramObject): successful_payment=None, forward_signature=None, author_signature=None, + media_group_id=None, bot=None, **kwargs): # Required @@ -277,6 +282,7 @@ class Message(TelegramObject): self.successful_payment = successful_payment self.forward_signature = forward_signature self.author_signature = author_signature + self.media_group_id = media_group_id self.bot = bot diff --git a/tests/test_bot.py b/tests/test_bot.py index 6d547ba16..634130241 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -104,8 +104,8 @@ class TestBot(object): # Considering that the first message is old enough bot.delete_message(chat_id=chat_id, message_id=1) - # send_photo, send_audio, send_document, send_sticker, send_video, send_voice - # and send_video_note are tested in their respective test modules. No need to duplicate here. + # send_photo, send_audio, send_document, send_sticker, send_video, send_voice, send_video_note + # and send_media_group are tested in their respective test modules. No need to duplicate here. @flaky(3, 1) @pytest.mark.timeout(10) diff --git a/tests/test_inputmedia.py b/tests/test_inputmedia.py new file mode 100644 index 000000000..e0e9901a1 --- /dev/null +++ b/tests/test_inputmedia.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2017 +# Leandro Toledo de Souza +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +import pytest +from flaky import flaky + +from telegram import InputMediaVideo, InputMediaPhoto, Message +from .test_video import video, video_file +from .test_photo import _photo, photo_file, photo, thumb + + +@pytest.fixture(scope='class') +def input_media_video(): + return InputMediaVideo(media=TestInputMediaVideo.media, + caption=TestInputMediaVideo.caption, + width=TestInputMediaVideo.width, + height=TestInputMediaVideo.height, + duration=TestInputMediaVideo.duration) + + +@pytest.fixture(scope='class') +def input_media_photo(): + return InputMediaPhoto(media=TestInputMediaPhoto.media, + caption=TestInputMediaPhoto.caption) + + +class TestInputMediaVideo(object): + type = "video" + media = "NOTAREALFILEID" + caption = "My Caption" + width = 3 + height = 4 + duration = 5 + + def test_expected_values(self, input_media_video): + assert input_media_video.type == self.type + assert input_media_video.media == self.media + assert input_media_video.caption == self.caption + assert input_media_video.width == self.width + assert input_media_video.height == self.height + assert input_media_video.duration == self.duration + + def test_to_dict(self, input_media_video): + input_media_video_dict = input_media_video.to_dict() + assert input_media_video_dict['type'] == input_media_video.type + assert input_media_video_dict['media'] == input_media_video.media + assert input_media_video_dict['caption'] == input_media_video.caption + assert input_media_video_dict['width'] == input_media_video.width + assert input_media_video_dict['height'] == input_media_video.height + assert input_media_video_dict['duration'] == input_media_video.duration + + def test_with_video(self, video): + # fixture found in test_video + input_media_video = InputMediaVideo(video, caption="test 3") + assert input_media_video.type == self.type + assert input_media_video.media == video.file_id + assert input_media_video.width == video.width + assert input_media_video.height == video.height + assert input_media_video.duration == video.duration + assert input_media_video.caption == "test 3" + + def test_error_with_file(self, video_file): + # fixture found in test_video + with pytest.raises(ValueError, match="file_id, url or Video"): + InputMediaVideo(video_file) + + +class TestInputMediaPhoto(object): + type = "photo" + media = "NOTAREALFILEID" + caption = "My Caption" + + def test_expected_values(self, input_media_photo): + assert input_media_photo.type == self.type + assert input_media_photo.media == self.media + assert input_media_photo.caption == self.caption + + def test_to_dict(self, input_media_photo): + input_media_photo_dict = input_media_photo.to_dict() + assert input_media_photo_dict['type'] == input_media_photo.type + assert input_media_photo_dict['media'] == input_media_photo.media + assert input_media_photo_dict['caption'] == input_media_photo.caption + + def test_with_photo(self, photo): + # fixture found in test_photo + imp = InputMediaPhoto(photo, caption="test 2") + assert imp.type == self.type + assert imp.media == photo.file_id + assert imp.caption == "test 2" + + def test_error_with_file(self, photo_file): + # fixture found in test_photo + with pytest.raises(ValueError, match="file_id, url or PhotoSize"): + InputMediaPhoto(photo_file) + + +@pytest.fixture(scope='function') +def media_group(photo, thumb): + return [InputMediaPhoto(photo), InputMediaPhoto(thumb)] + + +class TestSendMediaGroup(object): + @flaky(3, 1) + @pytest.mark.timeout(10) + def test_send_media_group_photo(self, bot, chat_id, media_group): + messages = bot.send_media_group(chat_id, media_group) + assert isinstance(messages, list) + assert len(messages) == 2 + assert all([isinstance(mes, Message) for mes in messages]) + assert all([mes.media_group_id == messages[0].media_group_id for mes in messages]) + + @flaky(3, 1) + @pytest.mark.timeout(10) + def test_send_media_group_all_args(self, bot, chat_id, media_group): + m1 = bot.send_message(chat_id, text="test") + messages = bot.send_media_group(chat_id, media_group, disable_notification=True, + reply_to_message_id=m1.message_id) + assert isinstance(messages, list) + assert len(messages) == 2 + assert all([isinstance(mes, Message) for mes in messages]) + assert all([mes.media_group_id == messages[0].media_group_id for mes in messages]) + + @pytest.mark.skip(reason="Needs a rework to send new files") + def test_send_media_group_new_files(self): + pass diff --git a/tests/test_invoice.py b/tests/test_invoice.py index c6b6ffc5a..5811a70f2 100644 --- a/tests/test_invoice.py +++ b/tests/test_invoice.py @@ -32,6 +32,7 @@ def invoice(): class TestInvoice(object): payload = 'payload' prices = [LabeledPrice('Fish', 100), LabeledPrice('Fish Tax', 1000)] + provider_data = """{"test":"test"}""" title = 'title' description = 'description' start_parameter = 'start_parameter' @@ -88,6 +89,7 @@ class TestInvoice(object): self.start_parameter, self.currency, self.prices, + provider_data=self.provider_data, photo_url='https://raw.githubusercontent.com/' 'python-telegram-bot/logos/master/' 'logo/png/ptb-logo_240.png', @@ -105,3 +107,24 @@ class TestInvoice(object): assert message.invoice.description == self.description assert message.invoice.title == self.title assert message.invoice.total_amount == self.total_amount + + def test_send_object_as_provider_data(self, monkeypatch, bot, chat_id, provider_token): + def test(_, url, data, **kwargs): + return data['provider_data'] == '{"test_data": 123456789}' + + monkeypatch.setattr('telegram.utils.request.Request.post', test) + + assert bot.send_invoice(chat_id, self.title, self.description, self.payload, + provider_token, self.start_parameter, self.currency, + self.prices, provider_data={'test_data': 123456789}) + + def test_send_nonesense_as_provider_data(self, monkeypatch, bot, chat_id, provider_token): + def test(_, url, data, **kwargs): + return True + + monkeypatch.setattr('telegram.utils.request.Request.post', test) + + with pytest.raises(TypeError): + assert bot.send_invoice(chat_id, self.title, self.description, self.payload, + provider_token, self.start_parameter, self.currency, + self.prices, provider_data={'a', 'b', 'c'}) diff --git a/tests/test_message.py b/tests/test_message.py index fb9c1c74c..42c85a6e1 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -79,7 +79,10 @@ def message(bot): 'charge_id', 'provider_id', order_info={})}, {'forward_signature': 'some_forward_sign'}, - {'author_signature': 'some_author_sign'} + {'author_signature': 'some_author_sign'}, + {'photo': [PhotoSize('photo_id', 50, 50)], + 'caption': 'photo_file', + 'media_group_id': 1234443322222} ], ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text', 'caption_entities', 'audio', 'document', 'game', 'photo', 'sticker', 'video', @@ -87,7 +90,7 @@ def message(bot): 'left_member', 'new_title', 'new_photo', 'delete_photo', 'group_created', 'supergroup_created', 'channel_created', 'migrated_to', 'migrated_from', 'pinned', 'invoice', 'successful_payment', 'forward_signature', - 'author_signature']) + 'author_signature', 'photo_from_media_group']) def message_params(bot, request): return Message(message_id=TestMessage.id, from_user=TestMessage.from_user, diff --git a/tests/test_official.py b/tests/test_official.py index 8a5f7c1f5..bfb0da3cf 100644 --- a/tests/test_official.py +++ b/tests/test_official.py @@ -105,7 +105,8 @@ def check_object(h4): field = parameter[0] if field == 'from': field = 'from_user' - elif name.startswith('InlineQueryResult') and field == 'type': + elif ((name.startswith('InlineQueryResult') or + name.startswith('InputMedia')) and field == 'type'): continue elif field == 'remove_keyboard': continue diff --git a/tests/test_photo.py b/tests/test_photo.py index 7bfcd4b62..0563c485b 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -174,9 +174,9 @@ class TestPhoto(object): assert isinstance(photo.file_id, str) assert photo.file_id != '' assert isinstance(photo, PhotoSize) - assert photo.width == 1920 - assert photo.height == 1080 - assert photo.file_size == 30907 + assert photo.width == 1280 + assert photo.height == 720 + assert photo.file_size == 33372 def test_send_with_photosize(self, monkeypatch, bot, chat_id, photo): def test(_, url, data, **kwargs):