mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 22:45:09 +01:00
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:
parent
1e22d570a3
commit
042d4bb2a4
16 changed files with 434 additions and 16 deletions
6
docs/source/telegram.inputmedia.rst
Normal file
6
docs/source/telegram.inputmedia.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
telegram.InputMedia
|
||||||
|
===================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputMedia
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.inputmediaphoto.rst
Normal file
6
docs/source/telegram.inputmediaphoto.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
telegram.InputMediaPhoto
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputMediaPhoto
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
6
docs/source/telegram.inputmediavideo.rst
Normal file
6
docs/source/telegram.inputmediavideo.rst
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
telegram.InputMediaVideo
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. autoclass:: telegram.InputMediaVideo
|
||||||
|
:members:
|
||||||
|
:show-inheritance:
|
|
@ -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
|
||||||
|
|
|
@ -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'
|
||||||
]
|
]
|
||||||
|
|
|
@ -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 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
|
@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
|
||||||
|
|
31
telegram/files/inputmedia.py
Normal file
31
telegram/files/inputmedia.py
Normal 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
|
57
telegram/files/inputmediaphoto.py
Normal file
57
telegram/files/inputmediaphoto.py
Normal 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
|
74
telegram/files/inputmediavideo.py
Normal file
74
telegram/files/inputmediavideo.py
Normal 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
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
140
tests/test_inputmedia.py
Normal 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
|
|
@ -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'})
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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):
|
||||||
|
|
Loading…
Reference in a new issue