Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

add support for 3.5 api #920

Merged
merged 14 commits into from Dec 8, 2017
6 changes: 6 additions & 0 deletions docs/source/telegram.inputmedia.rst
@@ -0,0 +1,6 @@
telegram.InputMedia
===================

.. autoclass:: telegram.InputMedia
:members:
:show-inheritance:
6 changes: 6 additions & 0 deletions docs/source/telegram.inputmediaphoto.rst
@@ -0,0 +1,6 @@
telegram.InputMediaPhoto
========================

.. autoclass:: telegram.InputMediaPhoto
:members:
:show-inheritance:
6 changes: 6 additions & 0 deletions docs/source/telegram.inputmediavideo.rst
@@ -0,0 +1,6 @@
telegram.InputMediaVideo
========================

.. autoclass:: telegram.InputMediaVideo
:members:
:show-inheritance:
3 changes: 3 additions & 0 deletions docs/source/telegram.rst
Expand Up @@ -21,6 +21,9 @@ telegram package
telegram.inlinekeyboardbutton
telegram.inlinekeyboardmarkup
telegram.inputfile
telegram.inputmedia
telegram.inputmediaphoto
telegram.inputmediavideo
telegram.keyboardbutton
telegram.location
telegram.message
Expand Down
6 changes: 5 additions & 1 deletion telegram/__init__.py
Expand Up @@ -96,6 +96,9 @@
MAX_FILESIZE_DOWNLOAD, MAX_FILESIZE_UPLOAD,
MAX_MESSAGES_PER_SECOND_PER_CHAT, MAX_MESSAGES_PER_SECOND,
MAX_MESSAGES_PER_MINUTE_PER_GROUP)
from .inputmedia import InputMedia
from .inputmediaphoto import InputMediaPhoto
from .inputmediavideo import InputMediaVideo
from .version import __version__ # flake8: noqa

__author__ = 'devs@python-telegram-bot.org'
Expand All @@ -121,5 +124,6 @@
'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'
]
63 changes: 56 additions & 7 deletions telegram/bot.py
Expand Up @@ -335,7 +335,7 @@ def send_photo(self,
disable_notification=False,
reply_to_message_id=None,
reply_markup=None,
timeout=20.,
timeout=20,
**kwargs):
"""Use this method to send photos.

Expand Down Expand Up @@ -394,7 +394,7 @@ def send_audio(self,
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
Expand Down Expand Up @@ -465,7 +465,7 @@ def send_document(self,
disable_notification=False,
reply_to_message_id=None,
reply_markup=None,
timeout=20.,
timeout=20,
**kwargs):
"""Use this method to send general files.

Expand Down Expand Up @@ -576,7 +576,7 @@ def send_video(self,
disable_notification=False,
reply_to_message_id=None,
reply_markup=None,
timeout=20.,
timeout=20,
width=None,
height=None,
**kwargs):
Expand Down Expand Up @@ -646,7 +646,7 @@ def send_voice(self,
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
Expand Down Expand Up @@ -708,7 +708,7 @@ def send_video_note(self,
disable_notification=False,
reply_to_message_id=None,
reply_markup=None,
timeout=20.,
timeout=20,
**kwargs):
"""Use this method to send video messages.

Expand Down Expand Up @@ -757,6 +757,49 @@ def send_video_note(self,

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`
"""
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,
Expand Down Expand Up @@ -2153,6 +2196,7 @@ def send_invoice(self,
disable_notification=False,
reply_to_message_id=None,
reply_markup=None,
provider_data=None,
timeout=None,
**kwargs):
"""Use this method to send invoices.
Expand All @@ -2169,6 +2213,9 @@ def send_invoice(self,
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`, 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.
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.
Expand Down Expand Up @@ -2216,7 +2263,8 @@ def send_invoice(self,
'currency': currency,
'prices': [p.to_dict() for p in prices]
}

if provider_data is not None:
data['provider_data'] = provider_data
if photo_url is not None:
data['photo_url'] = photo_url
if photo_size is not None:
Expand Down Expand Up @@ -2965,6 +3013,7 @@ def __reduce__(self):
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
Expand Down
31 changes: 31 additions & 0 deletions telegram/inputmedia.py
@@ -0,0 +1,31 @@
#!/usr/bin/env python
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these files maybe be in files/?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe.

#
# 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
55 changes: 55 additions & 0 deletions telegram/inputmediaphoto.py
@@ -0,0 +1,55 @@
#!/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.
"""

def __init__(self, media, caption=None):
self.type = 'photo'

if isinstance(media, PhotoSize):
self.media = media.file_id
elif hasattr(media, 'read'):
raise ValueError('We only support file_id or url as a valid media. Sending files is '
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a TODO: about this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, will do

'not supported (yet).')
else:
self.media = media

if caption:
self.caption = caption
73 changes: 73 additions & 0 deletions telegram/inputmediavideo.py
@@ -0,0 +1,73 @@
#!/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.
"""

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('We only support file_id or url as a valid media. Sending files is '
'not supported (yet).')
else:
self.media = media

if caption:
self.caption = caption
if width:
self.width = width
if height:
self.height = height
if duration:
self.duration = duration
6 changes: 6 additions & 0 deletions telegram/message.py
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -232,6 +236,7 @@ def __init__(self,
successful_payment=None,
forward_signature=None,
author_signature=None,
media_group_id=None,
bot=None,
**kwargs):
# Required
Expand Down Expand Up @@ -277,6 +282,7 @@ def __init__(self,
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

Expand Down
4 changes: 2 additions & 2 deletions tests/test_bot.py
Expand Up @@ -104,8 +104,8 @@ def test_delete_message_old_message(self, bot, chat_id):
# 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)
Expand Down