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
This commit is contained in:
Eldinnie 2017-12-08 22:38:59 +01:00 committed by GitHub
parent 1e22d570a3
commit 042d4bb2a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 434 additions and 16 deletions

View file

@ -0,0 +1,6 @@
telegram.InputMedia
===================
.. autoclass:: telegram.InputMedia
:members:
:show-inheritance:

View file

@ -0,0 +1,6 @@
telegram.InputMediaPhoto
========================
.. autoclass:: telegram.InputMediaPhoto
:members:
:show-inheritance:

View file

@ -0,0 +1,6 @@
telegram.InputMediaVideo
========================
.. autoclass:: telegram.InputMediaVideo
:members:
:show-inheritance:

View file

@ -21,6 +21,9 @@ telegram package
telegram.inlinekeyboardbutton telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup telegram.inlinekeyboardmarkup
telegram.inputfile telegram.inputfile
telegram.inputmedia
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.keyboardbutton telegram.keyboardbutton
telegram.location telegram.location
telegram.message telegram.message

View file

@ -96,6 +96,9 @@ from .constants import (MAX_MESSAGE_LENGTH, MAX_CAPTION_LENGTH, SUPPORTED_WEBHOO
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD, MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND, MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
MAX_MESSAGES_PER_MINUTE_PER_GROUP) 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 from .version import __version__ # flake8: noqa
__author__ = 'devs@python-telegram-bot.org' __author__ = 'devs@python-telegram-bot.org'
@ -121,5 +124,6 @@ __all__ = [
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation', 'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption', 'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto', 'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto',
'StickerSet', 'MaskPosition', 'CallbackGame' 'StickerSet', 'MaskPosition', 'CallbackGame', 'InputMedia', 'InputMediaPhoto',
'InputMediaVideo'
] ]

View file

@ -21,10 +21,13 @@
"""This module contains an object that represents a Telegram Bot.""" """This module contains an object that represents a Telegram Bot."""
import functools import functools
import json
import logging import logging
import warnings import warnings
from datetime import datetime from datetime import datetime
from future.utils import string_types
from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File, from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File,
ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore, StickerSet, ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore, StickerSet,
PhotoSize, Audio, Document, Sticker, Video, Voice, VideoNote, Location, PhotoSize, Audio, Document, Sticker, Video, Voice, VideoNote, Location,
@ -335,7 +338,7 @@ class Bot(TelegramObject):
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
**kwargs): **kwargs):
"""Use this method to send photos. """Use this method to send photos.
@ -394,7 +397,7 @@ class Bot(TelegramObject):
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
**kwargs): **kwargs):
""" """
Use this method to send audio files, if you want Telegram clients to display them in the 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, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
**kwargs): **kwargs):
"""Use this method to send general files. """Use this method to send general files.
@ -576,7 +579,7 @@ class Bot(TelegramObject):
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
width=None, width=None,
height=None, height=None,
**kwargs): **kwargs):
@ -646,7 +649,7 @@ class Bot(TelegramObject):
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
**kwargs): **kwargs):
""" """
Use this method to send audio files, if you want Telegram clients to display the file 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, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
timeout=20., timeout=20,
**kwargs): **kwargs):
"""Use this method to send video messages. """Use this method to send video messages.
@ -757,6 +760,51 @@ class Bot(TelegramObject):
return url, data 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 210 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 @log
@message @message
def send_location(self, def send_location(self,
@ -2153,6 +2201,7 @@ class Bot(TelegramObject):
disable_notification=False, disable_notification=False,
reply_to_message_id=None, reply_to_message_id=None,
reply_markup=None, reply_markup=None,
provider_data=None,
timeout=None, timeout=None,
**kwargs): **kwargs):
"""Use this method to send invoices. """Use this method to send invoices.
@ -2169,6 +2218,10 @@ class Bot(TelegramObject):
currency (:obj:`str`): Three-letter ISO 4217 currency code. currency (:obj:`str`): Three-letter ISO 4217 currency code.
prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list of components prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a list of components
(e.g. product price, tax, discount, delivery cost, delivery tax, bonus, etc.). (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_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 photo of the goods or a marketing image for a service. People like it better when
they see what they are paying for. they see what they are paying for.
@ -2216,7 +2269,11 @@ class Bot(TelegramObject):
'currency': currency, 'currency': currency,
'prices': [p.to_dict() for p in prices] '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: if photo_url is not None:
data['photo_url'] = photo_url data['photo_url'] = photo_url
if photo_size is not None: if photo_size is not None:
@ -2965,6 +3022,7 @@ class Bot(TelegramObject):
sendVideo = send_video sendVideo = send_video
sendVoice = send_voice sendVoice = send_voice
sendVideoNote = send_video_note sendVideoNote = send_video_note
sendMediaGroup = send_media_group
sendLocation = send_location sendLocation = send_location
editMessageLiveLocation = edit_message_live_location editMessageLiveLocation = edit_message_live_location
stopMessageLiveLocation = stop_message_live_location stopMessageLiveLocation = stop_message_live_location

View file

@ -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 <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/].
"""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

View file

@ -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 <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 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

View file

@ -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 <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 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

View file

@ -48,6 +48,8 @@ class Message(TelegramObject):
forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent. forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent.
reply_to_message (:class:`telegram.Message`): Optional. The original message. reply_to_message (:class:`telegram.Message`): Optional. The original message.
edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited. 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. text (:obj:`str`): Optional. The actual UTF-8 text of the message.
entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like
usernames, URLs, bot commands, etc. that appear in the text. See 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. ``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 edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix
time. Converted to :class:`datetime.datetime`. 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 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`. characters. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`.
entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special
@ -232,6 +236,7 @@ class Message(TelegramObject):
successful_payment=None, successful_payment=None,
forward_signature=None, forward_signature=None,
author_signature=None, author_signature=None,
media_group_id=None,
bot=None, bot=None,
**kwargs): **kwargs):
# Required # Required
@ -277,6 +282,7 @@ class Message(TelegramObject):
self.successful_payment = successful_payment self.successful_payment = successful_payment
self.forward_signature = forward_signature self.forward_signature = forward_signature
self.author_signature = author_signature self.author_signature = author_signature
self.media_group_id = media_group_id
self.bot = bot self.bot = bot

View file

@ -104,8 +104,8 @@ class TestBot(object):
# Considering that the first message is old enough # Considering that the first message is old enough
bot.delete_message(chat_id=chat_id, message_id=1) bot.delete_message(chat_id=chat_id, message_id=1)
# send_photo, send_audio, send_document, send_sticker, send_video, send_voice # send_photo, send_audio, send_document, send_sticker, send_video, send_voice, send_video_note
# and send_video_note are tested in their respective test modules. No need to duplicate here. # and send_media_group are tested in their respective test modules. No need to duplicate here.
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)

140
tests/test_inputmedia.py Normal file
View file

@ -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 <devs@python-telegram-bot.org>
#
# 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

View file

@ -32,6 +32,7 @@ def invoice():
class TestInvoice(object): class TestInvoice(object):
payload = 'payload' payload = 'payload'
prices = [LabeledPrice('Fish', 100), LabeledPrice('Fish Tax', 1000)] prices = [LabeledPrice('Fish', 100), LabeledPrice('Fish Tax', 1000)]
provider_data = """{"test":"test"}"""
title = 'title' title = 'title'
description = 'description' description = 'description'
start_parameter = 'start_parameter' start_parameter = 'start_parameter'
@ -88,6 +89,7 @@ class TestInvoice(object):
self.start_parameter, self.start_parameter,
self.currency, self.currency,
self.prices, self.prices,
provider_data=self.provider_data,
photo_url='https://raw.githubusercontent.com/' photo_url='https://raw.githubusercontent.com/'
'python-telegram-bot/logos/master/' 'python-telegram-bot/logos/master/'
'logo/png/ptb-logo_240.png', 'logo/png/ptb-logo_240.png',
@ -105,3 +107,24 @@ class TestInvoice(object):
assert message.invoice.description == self.description assert message.invoice.description == self.description
assert message.invoice.title == self.title assert message.invoice.title == self.title
assert message.invoice.total_amount == self.total_amount 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'})

View file

@ -79,7 +79,10 @@ def message(bot):
'charge_id', 'provider_id', 'charge_id', 'provider_id',
order_info={})}, order_info={})},
{'forward_signature': 'some_forward_sign'}, {'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', ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text',
'caption_entities', 'audio', 'document', 'game', 'photo', 'sticker', 'video', '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', 'left_member', 'new_title', 'new_photo', 'delete_photo', 'group_created',
'supergroup_created', 'channel_created', 'migrated_to', 'migrated_from', 'supergroup_created', 'channel_created', 'migrated_to', 'migrated_from',
'pinned', 'invoice', 'successful_payment', 'forward_signature', 'pinned', 'invoice', 'successful_payment', 'forward_signature',
'author_signature']) 'author_signature', 'photo_from_media_group'])
def message_params(bot, request): def message_params(bot, request):
return Message(message_id=TestMessage.id, return Message(message_id=TestMessage.id,
from_user=TestMessage.from_user, from_user=TestMessage.from_user,

View file

@ -105,7 +105,8 @@ def check_object(h4):
field = parameter[0] field = parameter[0]
if field == 'from': if field == 'from':
field = 'from_user' field = 'from_user'
elif name.startswith('InlineQueryResult') and field == 'type': elif ((name.startswith('InlineQueryResult') or
name.startswith('InputMedia')) and field == 'type'):
continue continue
elif field == 'remove_keyboard': elif field == 'remove_keyboard':
continue continue

View file

@ -174,9 +174,9 @@ class TestPhoto(object):
assert isinstance(photo.file_id, str) assert isinstance(photo.file_id, str)
assert photo.file_id != '' assert photo.file_id != ''
assert isinstance(photo, PhotoSize) assert isinstance(photo, PhotoSize)
assert photo.width == 1920 assert photo.width == 1280
assert photo.height == 1080 assert photo.height == 720
assert photo.file_size == 30907 assert photo.file_size == 33372
def test_send_with_photosize(self, monkeypatch, bot, chat_id, photo): def test_send_with_photosize(self, monkeypatch, bot, chat_id, photo):
def test(_, url, data, **kwargs): def test(_, url, data, **kwargs):