mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-01-03 17:52:31 +01:00
support 3.4 API (#865)
This commit is contained in:
parent
8a8b1215c8
commit
bfad2fa1f3
13 changed files with 403 additions and 35 deletions
|
@ -96,7 +96,7 @@ make the development of bots easy and straightforward. These classes are contain
|
||||||
Telegram API support
|
Telegram API support
|
||||||
====================
|
====================
|
||||||
|
|
||||||
As of **23. July 2017**, all types and methods of the Telegram Bot API 3.2 are supported.
|
All types and methods of the Telegram Bot API 3.4 are supported.
|
||||||
|
|
||||||
==========
|
==========
|
||||||
Installing
|
Installing
|
||||||
|
|
178
telegram/bot.py
178
telegram/bot.py
|
@ -768,6 +768,7 @@ class Bot(TelegramObject):
|
||||||
reply_markup=None,
|
reply_markup=None,
|
||||||
timeout=None,
|
timeout=None,
|
||||||
location=None,
|
location=None,
|
||||||
|
live_period=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
"""Use this method to send point on the map.
|
"""Use this method to send point on the map.
|
||||||
|
|
||||||
|
@ -780,6 +781,8 @@ class Bot(TelegramObject):
|
||||||
latitude (:obj:`float`, optional): Latitude of location.
|
latitude (:obj:`float`, optional): Latitude of location.
|
||||||
longitude (:obj:`float`, optional): Longitude of location.
|
longitude (:obj:`float`, optional): Longitude of location.
|
||||||
location (:class:`telegram.Location`, optional): The location to send.
|
location (:class:`telegram.Location`, optional): The location to send.
|
||||||
|
live_period (:obj:`int`, optional): Period in seconds for which the location will be
|
||||||
|
updated, should be between 60 and 86400.
|
||||||
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
|
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
|
||||||
receive a notification with no sound.
|
receive a notification with no sound.
|
||||||
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
|
reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the
|
||||||
|
@ -803,7 +806,11 @@ class Bot(TelegramObject):
|
||||||
|
|
||||||
if not (all([latitude, longitude]) or location):
|
if not (all([latitude, longitude]) or location):
|
||||||
raise ValueError("Either location or latitude and longitude must be passed as"
|
raise ValueError("Either location or latitude and longitude must be passed as"
|
||||||
"argument")
|
"argument.")
|
||||||
|
|
||||||
|
if not ((latitude is not None or longitude is not None) ^ bool(location)):
|
||||||
|
raise ValueError("Either location or latitude and longitude must be passed as"
|
||||||
|
"argument. Not both.")
|
||||||
|
|
||||||
if isinstance(location, Location):
|
if isinstance(location, Location):
|
||||||
latitude = location.latitude
|
latitude = location.latitude
|
||||||
|
@ -811,6 +818,114 @@ class Bot(TelegramObject):
|
||||||
|
|
||||||
data = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
|
data = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude}
|
||||||
|
|
||||||
|
if live_period:
|
||||||
|
data['live_period'] = live_period
|
||||||
|
|
||||||
|
return url, data
|
||||||
|
|
||||||
|
@log
|
||||||
|
@message
|
||||||
|
def edit_message_live_location(self,
|
||||||
|
chat_id=None,
|
||||||
|
message_id=None,
|
||||||
|
inline_message_id=None,
|
||||||
|
latitude=None,
|
||||||
|
longitude=None,
|
||||||
|
location=None,
|
||||||
|
reply_markup=None,
|
||||||
|
**kwargs):
|
||||||
|
"""Use this method to edit live location messages sent by the bot or via the bot
|
||||||
|
(for inline bots). A location can be edited until its :attr:`live_period` expires or
|
||||||
|
editing is explicitly disabled by a call to :attr:`stop_message_live_location`.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||||
|
of the target channel (in the format @channelusername).
|
||||||
|
message_id (:obj:`int`, optional): Required if inline_message_id is not specified.
|
||||||
|
Identifier of the sent message.
|
||||||
|
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
|
||||||
|
specified. Identifier of the inline message.
|
||||||
|
latitude (:obj:`float`, optional): Latitude of location.
|
||||||
|
longitude (:obj:`float`, optional): Longitude of location.
|
||||||
|
location (:class:`telegram.Location`, optional): The location to send.
|
||||||
|
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
|
||||||
|
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
|
||||||
|
to remove reply keyboard or to force a reply from the user.
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||||
|
the read timeout from the server (instead of the one specified during creation of
|
||||||
|
the connection pool).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`telegram.Message`: On success the edited message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = '{0}/editMessageLiveLocation'.format(self.base_url)
|
||||||
|
|
||||||
|
if not (all([latitude, longitude]) or location):
|
||||||
|
raise ValueError("Either location or latitude and longitude must be passed as"
|
||||||
|
"argument.")
|
||||||
|
if not ((latitude is not None or longitude is not None) ^ bool(location)):
|
||||||
|
raise ValueError("Either location or latitude and longitude must be passed as"
|
||||||
|
"argument. Not both.")
|
||||||
|
|
||||||
|
if isinstance(location, Location):
|
||||||
|
latitude = location.latitude
|
||||||
|
longitude = location.longitude
|
||||||
|
|
||||||
|
data = {'latitude': latitude, 'longitude': longitude}
|
||||||
|
|
||||||
|
if chat_id:
|
||||||
|
data['chat_id'] = chat_id
|
||||||
|
if message_id:
|
||||||
|
data['message_id'] = message_id
|
||||||
|
if inline_message_id:
|
||||||
|
data['inline_message_id'] = inline_message_id
|
||||||
|
|
||||||
|
return url, data
|
||||||
|
|
||||||
|
@log
|
||||||
|
@message
|
||||||
|
def stop_message_live_location(self,
|
||||||
|
chat_id=None,
|
||||||
|
message_id=None,
|
||||||
|
inline_message_id=None,
|
||||||
|
reply_markup=None,
|
||||||
|
**kwargs):
|
||||||
|
"""Use this method to stop updating a live location message sent by the bot or via the bot
|
||||||
|
(for inline bots) before live_period expires.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||||
|
of the target channel (in the format @channelusername).
|
||||||
|
message_id (:obj:`int`, optional): Required if inline_message_id is not specified.
|
||||||
|
Identifier of the sent message.
|
||||||
|
inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not
|
||||||
|
specified. Identifier of the inline message.
|
||||||
|
reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A
|
||||||
|
JSON-serialized object for an inline keyboard, custom reply keyboard, instructions
|
||||||
|
to remove reply keyboard or to force a reply from the user.
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||||
|
the read timeout from the server (instead of the one specified during creation of
|
||||||
|
the connection pool).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:class:`telegram.Message`: On success the edited message.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = '{0}/stopMessageLiveLocation'.format(self.base_url)
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
if chat_id:
|
||||||
|
data['chat_id'] = chat_id
|
||||||
|
if message_id:
|
||||||
|
data['message_id'] = message_id
|
||||||
|
if inline_message_id:
|
||||||
|
data['inline_message_id'] = inline_message_id
|
||||||
|
|
||||||
return url, data
|
return url, data
|
||||||
|
|
||||||
@log
|
@log
|
||||||
|
@ -1825,6 +1940,63 @@ class Bot(TelegramObject):
|
||||||
|
|
||||||
return ChatMember.de_json(result, self)
|
return ChatMember.de_json(result, self)
|
||||||
|
|
||||||
|
@log
|
||||||
|
def set_chat_sticker_set(self, chat_id, sticker_set_name, timeout=None, **kwargs):
|
||||||
|
"""Use this method to set a new group sticker set for a supergroup.
|
||||||
|
The bot must be an administrator in the chat for this to work and must have the appropriate
|
||||||
|
admin rights. Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned
|
||||||
|
in :attr:`get_chat` requests to check if the bot can use this method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||||
|
of the target supergroup (in the format @supergroupusername).
|
||||||
|
sticker_set_name (:obj:`str`): Name of the sticker set to be set as the group
|
||||||
|
sticker set.
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||||
|
the read timeout from the server (instead of the one specified during creation of
|
||||||
|
the connection pool).
|
||||||
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: True on success.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = '{0}/setChatStickerSet'.format(self.base_url)
|
||||||
|
|
||||||
|
data = {'chat_id': chat_id, 'sticker_set_name': sticker_set_name}
|
||||||
|
|
||||||
|
result = self._request.post(url, data, timeout=timeout)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
@log
|
||||||
|
def delete_chat_sticker_set(self, chat_id, timeout=None, **kwargs):
|
||||||
|
"""Use this method to delete a group sticker set from a supergroup. The bot must be an
|
||||||
|
administrator in the chat for this to work and must have the appropriate admin rights.
|
||||||
|
Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned in
|
||||||
|
:attr:`get_chat` requests to check if the bot can use this method.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username
|
||||||
|
of the target supergroup (in the format @supergroupusername).
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as
|
||||||
|
the read timeout from the server (instead of the one specified during creation of
|
||||||
|
the connection pool).
|
||||||
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`bool`: True on success.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = '{0}/deleteChatStickerSet'.format(self.base_url)
|
||||||
|
|
||||||
|
data = {'chat_id': chat_id}
|
||||||
|
|
||||||
|
result = self._request.post(url, data, timeout=timeout)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
def get_webhook_info(self, timeout=None, **kwargs):
|
def get_webhook_info(self, timeout=None, **kwargs):
|
||||||
"""Use this method to get current webhook status. Requires no parameters.
|
"""Use this method to get current webhook status. Requires no parameters.
|
||||||
|
|
||||||
|
@ -2794,6 +2966,8 @@ class Bot(TelegramObject):
|
||||||
sendVoice = send_voice
|
sendVoice = send_voice
|
||||||
sendVideoNote = send_video_note
|
sendVideoNote = send_video_note
|
||||||
sendLocation = send_location
|
sendLocation = send_location
|
||||||
|
editMessageLiveLocation = edit_message_live_location
|
||||||
|
stopMessageLiveLocation = stop_message_live_location
|
||||||
sendVenue = send_venue
|
sendVenue = send_venue
|
||||||
sendContact = send_contact
|
sendContact = send_contact
|
||||||
sendGame = send_game
|
sendGame = send_game
|
||||||
|
@ -2814,6 +2988,8 @@ class Bot(TelegramObject):
|
||||||
getChat = get_chat
|
getChat = get_chat
|
||||||
getChatAdministrators = get_chat_administrators
|
getChatAdministrators = get_chat_administrators
|
||||||
getChatMember = get_chat_member
|
getChatMember = get_chat_member
|
||||||
|
setChatStickerSet = set_chat_sticker_set
|
||||||
|
deleteChatStickerSet = delete_chat_sticker_set
|
||||||
getChatMembersCount = get_chat_members_count
|
getChatMembersCount = get_chat_members_count
|
||||||
getWebhookInfo = get_webhook_info
|
getWebhookInfo = get_webhook_info
|
||||||
setGameScore = set_game_score
|
setGameScore = set_game_score
|
||||||
|
|
|
@ -38,6 +38,9 @@ class Chat(TelegramObject):
|
||||||
invite_link (:obj:`str`): Optional. Chat invite link, for supergroups and channel chats.
|
invite_link (:obj:`str`): Optional. Chat invite link, for supergroups and channel chats.
|
||||||
pinned_message (:class:`telegram.Message`): Optional. Pinned message, for supergroups.
|
pinned_message (:class:`telegram.Message`): Optional. Pinned message, for supergroups.
|
||||||
Returned only in get_chat.
|
Returned only in get_chat.
|
||||||
|
sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set.
|
||||||
|
can_set_sticker_set (:obj:`bool`): Optional. ``True``, if the bot can change group the
|
||||||
|
sticker set.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits
|
id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits
|
||||||
|
@ -61,6 +64,10 @@ class Chat(TelegramObject):
|
||||||
pinned_message (:class:`telegram.Message`, optional): Pinned message, for supergroups.
|
pinned_message (:class:`telegram.Message`, optional): Pinned message, for supergroups.
|
||||||
Returned only in get_chat.
|
Returned only in get_chat.
|
||||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||||
|
sticker_set_name (:obj:`str`, optional): For supergroups, name of Group sticker set.
|
||||||
|
Returned only in get_chat.
|
||||||
|
can_set_sticker_set (:obj:`bool`, optional): ``True``, if the bot can change group the
|
||||||
|
sticker set. Returned only in get_chat.
|
||||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -87,6 +94,8 @@ class Chat(TelegramObject):
|
||||||
description=None,
|
description=None,
|
||||||
invite_link=None,
|
invite_link=None,
|
||||||
pinned_message=None,
|
pinned_message=None,
|
||||||
|
sticker_set_name=None,
|
||||||
|
can_set_sticker_set=None,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
# Required
|
# Required
|
||||||
self.id = int(id)
|
self.id = int(id)
|
||||||
|
@ -101,6 +110,8 @@ class Chat(TelegramObject):
|
||||||
self.description = description
|
self.description = description
|
||||||
self.invite_link = invite_link
|
self.invite_link = invite_link
|
||||||
self.pinned_message = pinned_message
|
self.pinned_message = pinned_message
|
||||||
|
self.sticker_set_name = sticker_set_name
|
||||||
|
self.can_set_sticker_set = can_set_sticker_set
|
||||||
|
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
self._id_attrs = (self.id,)
|
self._id_attrs = (self.id,)
|
||||||
|
|
|
@ -33,6 +33,8 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||||
latitude (:obj:`float`): Location latitude in degrees.
|
latitude (:obj:`float`): Location latitude in degrees.
|
||||||
longitude (:obj:`float`): Location longitude in degrees.
|
longitude (:obj:`float`): Location longitude in degrees.
|
||||||
title (:obj:`str`): Location title.
|
title (:obj:`str`): Location title.
|
||||||
|
live_period (:obj:`int`): Optional. Period in seconds for which the location can be
|
||||||
|
updated, should be between 60 and 86400.
|
||||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
|
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
|
||||||
to the message.
|
to the message.
|
||||||
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the
|
||||||
|
@ -46,6 +48,8 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||||
latitude (:obj:`float`): Location latitude in degrees.
|
latitude (:obj:`float`): Location latitude in degrees.
|
||||||
longitude (:obj:`float`): Location longitude in degrees.
|
longitude (:obj:`float`): Location longitude in degrees.
|
||||||
title (:obj:`str`): Location title.
|
title (:obj:`str`): Location title.
|
||||||
|
live_period (:obj:`int`, optional): Period in seconds for which the location can be
|
||||||
|
updated, should be between 60 and 86400.
|
||||||
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
|
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
|
||||||
to the message.
|
to the message.
|
||||||
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the
|
||||||
|
@ -62,6 +66,7 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||||
latitude,
|
latitude,
|
||||||
longitude,
|
longitude,
|
||||||
title,
|
title,
|
||||||
|
live_period=None,
|
||||||
reply_markup=None,
|
reply_markup=None,
|
||||||
input_message_content=None,
|
input_message_content=None,
|
||||||
thumb_url=None,
|
thumb_url=None,
|
||||||
|
@ -75,6 +80,8 @@ class InlineQueryResultLocation(InlineQueryResult):
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
||||||
# Optionals
|
# Optionals
|
||||||
|
if live_period:
|
||||||
|
self.live_period = live_period
|
||||||
if reply_markup:
|
if reply_markup:
|
||||||
self.reply_markup = reply_markup
|
self.reply_markup = reply_markup
|
||||||
if input_message_content:
|
if input_message_content:
|
||||||
|
|
|
@ -32,11 +32,14 @@ class InputLocationMessageContent(InputMessageContent):
|
||||||
Args:
|
Args:
|
||||||
latitude (:obj:`float`): Latitude of the location in degrees.
|
latitude (:obj:`float`): Latitude of the location in degrees.
|
||||||
longitude (:obj:`float`): Longitude of the location in degrees.
|
longitude (:obj:`float`): Longitude of the location in degrees.
|
||||||
|
live_period (:obj:`int`, optional): Period in seconds for which the location can be
|
||||||
|
updated, should be between 60 and 86400.
|
||||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, latitude, longitude, **kwargs):
|
def __init__(self, latitude, longitude, live_period=None, **kwargs):
|
||||||
# Required
|
# Required
|
||||||
self.latitude = latitude
|
self.latitude = latitude
|
||||||
self.longitude = longitude
|
self.longitude = longitude
|
||||||
|
self.live_period = live_period
|
||||||
|
|
|
@ -26,7 +26,6 @@ from telegram import (Audio, Contact, Document, Chat, Location, PhotoSize, Stick
|
||||||
from telegram.utils.deprecate import warn_deprecate_obj
|
from telegram.utils.deprecate import warn_deprecate_obj
|
||||||
from telegram.utils.helpers import escape_html, escape_markdown, to_timestamp, from_timestamp
|
from telegram.utils.helpers import escape_html, escape_markdown, to_timestamp, from_timestamp
|
||||||
|
|
||||||
|
|
||||||
_UNDEFINED = object()
|
_UNDEFINED = object()
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,6 +53,10 @@ class Message(TelegramObject):
|
||||||
usernames, URLs, bot commands, etc. that appear in the text. See
|
usernames, URLs, bot commands, etc. that appear in the text. See
|
||||||
:attr:`Message.parse_entity` and :attr:`parse_entities` methods for how to use
|
:attr:`Message.parse_entity` and :attr:`parse_entities` methods for how to use
|
||||||
properly.
|
properly.
|
||||||
|
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like
|
||||||
|
usernames, URLs, bot commands, etc. that appear in the caption. See
|
||||||
|
:attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` methods for how
|
||||||
|
to use properly.
|
||||||
audio (:class:`telegram.Audio`): Optional. Information about the file.
|
audio (:class:`telegram.Audio`): Optional. Information about the file.
|
||||||
document (:class:`telegram.Document`): Optional. Information about the file.
|
document (:class:`telegram.Document`): Optional. Information about the file.
|
||||||
game (:class:`telegram.Game`): Optional. Information about the game.
|
game (:class:`telegram.Game`): Optional. Information about the game.
|
||||||
|
@ -119,6 +122,10 @@ class Message(TelegramObject):
|
||||||
entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special
|
entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special
|
||||||
entities like usernames, URLs, bot commands, etc. that appear in the text. See
|
entities like usernames, URLs, bot commands, etc. that appear in the text. See
|
||||||
attr:`parse_entity` and attr:`parse_entities` methods for how to use properly.
|
attr:`parse_entity` and attr:`parse_entities` methods for how to use properly.
|
||||||
|
caption_entities (List[:class:`telegram.MessageEntity`]): Optional. For Messages with a
|
||||||
|
Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the
|
||||||
|
caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities`
|
||||||
|
methods for how to use properly.
|
||||||
audio (:class:`telegram.Audio`, optional): Message is an audio file, information
|
audio (:class:`telegram.Audio`, optional): Message is an audio file, information
|
||||||
about the file.
|
about the file.
|
||||||
document (:class:`telegram.Document`, optional): Message is a general file, information
|
document (:class:`telegram.Document`, optional): Message is a general file, information
|
||||||
|
@ -196,6 +203,7 @@ class Message(TelegramObject):
|
||||||
edit_date=None,
|
edit_date=None,
|
||||||
text=None,
|
text=None,
|
||||||
entities=None,
|
entities=None,
|
||||||
|
caption_entities=None,
|
||||||
audio=None,
|
audio=None,
|
||||||
document=None,
|
document=None,
|
||||||
game=None,
|
game=None,
|
||||||
|
@ -239,6 +247,7 @@ class Message(TelegramObject):
|
||||||
self.edit_date = edit_date
|
self.edit_date = edit_date
|
||||||
self.text = text
|
self.text = text
|
||||||
self.entities = entities or list()
|
self.entities = entities or list()
|
||||||
|
self.caption_entities = caption_entities or list()
|
||||||
self.audio = audio
|
self.audio = audio
|
||||||
self.game = game
|
self.game = game
|
||||||
self.document = document
|
self.document = document
|
||||||
|
@ -289,6 +298,7 @@ class Message(TelegramObject):
|
||||||
data['date'] = from_timestamp(data['date'])
|
data['date'] = from_timestamp(data['date'])
|
||||||
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
||||||
data['entities'] = MessageEntity.de_list(data.get('entities'), bot)
|
data['entities'] = MessageEntity.de_list(data.get('entities'), bot)
|
||||||
|
data['caption_entities'] = MessageEntity.de_list(data.get('caption_entities'), bot)
|
||||||
data['forward_from'] = User.de_json(data.get('forward_from'), bot)
|
data['forward_from'] = User.de_json(data.get('forward_from'), bot)
|
||||||
data['forward_from_chat'] = Chat.de_json(data.get('forward_from_chat'), bot)
|
data['forward_from_chat'] = Chat.de_json(data.get('forward_from_chat'), bot)
|
||||||
data['forward_date'] = from_timestamp(data.get('forward_date'))
|
data['forward_date'] = from_timestamp(data.get('forward_date'))
|
||||||
|
@ -369,6 +379,8 @@ class Message(TelegramObject):
|
||||||
data['photo'] = [p.to_dict() for p in self.photo]
|
data['photo'] = [p.to_dict() for p in self.photo]
|
||||||
if self.entities:
|
if self.entities:
|
||||||
data['entities'] = [e.to_dict() for e in self.entities]
|
data['entities'] = [e.to_dict() for e in self.entities]
|
||||||
|
if self.caption_entities:
|
||||||
|
data['caption_entities'] = [e.to_dict() for e in self.caption_entities]
|
||||||
if self.new_chat_photo:
|
if self.new_chat_photo:
|
||||||
data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo]
|
data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo]
|
||||||
data['new_chat_member'] = data.pop('_new_chat_member', None)
|
data['new_chat_member'] = data.pop('_new_chat_member', None)
|
||||||
|
@ -683,7 +695,7 @@ class Message(TelegramObject):
|
||||||
be an entity that belongs to this message.
|
be an entity that belongs to this message.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The text of the given entity
|
:obj:`str`: The text of the given entity
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# Is it a narrow build, if so we don't need to convert
|
# Is it a narrow build, if so we don't need to convert
|
||||||
|
@ -695,6 +707,31 @@ class Message(TelegramObject):
|
||||||
|
|
||||||
return entity_text.decode('utf-16-le')
|
return entity_text.decode('utf-16-le')
|
||||||
|
|
||||||
|
def parse_caption_entity(self, entity):
|
||||||
|
"""Returns the text from a given :class:`telegram.MessageEntity`.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
This method is present because Telegram calculates the offset and length in
|
||||||
|
UTF-16 codepoint pairs, which some versions of Python don't handle automatically.
|
||||||
|
(That is, you can't just slice ``Message.caption`` with the offset and length.)
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must
|
||||||
|
be an entity that belongs to this message.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`str`: The text of the given entity
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Is it a narrow build, if so we don't need to convert
|
||||||
|
if sys.maxunicode == 0xffff:
|
||||||
|
return self.caption[entity.offset:entity.offset + entity.length]
|
||||||
|
else:
|
||||||
|
entity_text = self.caption.encode('utf-16-le')
|
||||||
|
entity_text = entity_text[entity.offset * 2:(entity.offset + entity.length) * 2]
|
||||||
|
|
||||||
|
return entity_text.decode('utf-16-le')
|
||||||
|
|
||||||
def parse_entities(self, types=None):
|
def parse_entities(self, types=None):
|
||||||
"""
|
"""
|
||||||
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||||
|
@ -726,6 +763,37 @@ class Message(TelegramObject):
|
||||||
for entity in self.entities if entity.type in types
|
for entity in self.entities if entity.type in types
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def parse_caption_entities(self, types=None):
|
||||||
|
"""
|
||||||
|
Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`.
|
||||||
|
It contains entities from this message's caption filtered by their
|
||||||
|
:attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity
|
||||||
|
belongs to as the value of the :obj:`dict`.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
This method should always be used instead of the :attr:`caption_entities` attribute,
|
||||||
|
since it calculates the correct substring from the message text based on UTF-16
|
||||||
|
codepoints. See :attr:`parse_entity` for more info.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
types (List[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as
|
||||||
|
strings. If the ``type`` attribute of an entity is contained in this list, it will
|
||||||
|
be returned. Defaults to a list of all types. All types can be found as constants
|
||||||
|
in :class:`telegram.MessageEntity`.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to
|
||||||
|
the text that belongs to them, calculated based on UTF-16 codepoints.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if types is None:
|
||||||
|
types = MessageEntity.ALL_TYPES
|
||||||
|
|
||||||
|
return {
|
||||||
|
entity: self.parse_caption_entity(entity)
|
||||||
|
for entity in self.caption_entities if entity.type in types
|
||||||
|
}
|
||||||
|
|
||||||
def _text_html(self, urled=False):
|
def _text_html(self, urled=False):
|
||||||
entities = self.parse_entities()
|
entities = self.parse_entities()
|
||||||
message_text = self.text
|
message_text = self.text
|
||||||
|
|
|
@ -107,15 +107,6 @@ class TestBot(object):
|
||||||
# send_photo, send_audio, send_document, send_sticker, send_video, send_voice
|
# 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.
|
# and send_video_note are tested in their respective test modules. No need to duplicate here.
|
||||||
|
|
||||||
@flaky(3, 1)
|
|
||||||
@pytest.mark.timeout(10)
|
|
||||||
def test_send_location(self, bot, chat_id):
|
|
||||||
message = bot.send_location(chat_id=chat_id, latitude=-23.691288, longitude=-46.788279)
|
|
||||||
|
|
||||||
assert message.location
|
|
||||||
assert message.location.longitude == -46.788279
|
|
||||||
assert message.location.latitude == -23.691288
|
|
||||||
|
|
||||||
@flaky(3, 1)
|
@flaky(3, 1)
|
||||||
@pytest.mark.timeout(10)
|
@pytest.mark.timeout(10)
|
||||||
def test_send_venue(self, bot, chat_id):
|
def test_send_venue(self, bot, chat_id):
|
||||||
|
@ -368,6 +359,14 @@ class TestBot(object):
|
||||||
assert chat_member.status == 'administrator'
|
assert chat_member.status == 'administrator'
|
||||||
assert chat_member.user.username == 'EchteEldin'
|
assert chat_member.user.username == 'EchteEldin'
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="Not implemented yet.")
|
||||||
|
def test_set_chat_sticker_set(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="Not implemented yet.")
|
||||||
|
def test_delete_chat_sticker_set(self):
|
||||||
|
pass
|
||||||
|
|
||||||
@pytest.mark.skipif(os.getenv('APPVEYOR'), reason='No game made for Appveyor bot (yet)')
|
@pytest.mark.skipif(os.getenv('APPVEYOR'), reason='No game made for Appveyor bot (yet)')
|
||||||
@flaky(3, 1)
|
@flaky(3, 1)
|
||||||
@pytest.mark.timeout(10)
|
@pytest.mark.timeout(10)
|
||||||
|
|
|
@ -27,7 +27,8 @@ from telegram import User
|
||||||
def chat(bot):
|
def chat(bot):
|
||||||
return Chat(TestChat.id, TestChat.title, TestChat.type,
|
return Chat(TestChat.id, TestChat.title, TestChat.type,
|
||||||
all_members_are_administrators=TestChat.all_members_are_administrators,
|
all_members_are_administrators=TestChat.all_members_are_administrators,
|
||||||
bot=bot)
|
bot=bot, sticker_set_name=TestChat.sticker_set_name,
|
||||||
|
can_set_sticker_set=TestChat.can_set_sticker_set)
|
||||||
|
|
||||||
|
|
||||||
class TestChat(object):
|
class TestChat(object):
|
||||||
|
@ -35,13 +36,17 @@ class TestChat(object):
|
||||||
title = 'ToledosPalaceBot - Group'
|
title = 'ToledosPalaceBot - Group'
|
||||||
type = 'group'
|
type = 'group'
|
||||||
all_members_are_administrators = False
|
all_members_are_administrators = False
|
||||||
|
sticker_set_name = 'stickers'
|
||||||
|
can_set_sticker_set = False
|
||||||
|
|
||||||
def test_de_json(self, bot):
|
def test_de_json(self, bot):
|
||||||
json_dict = {
|
json_dict = {
|
||||||
'id': TestChat.id,
|
'id': self.id,
|
||||||
'title': TestChat.title,
|
'title': self.title,
|
||||||
'type': TestChat.type,
|
'type': self.type,
|
||||||
'all_members_are_administrators': TestChat.all_members_are_administrators
|
'all_members_are_administrators': self.all_members_are_administrators,
|
||||||
|
'sticker_set_name': self.sticker_set_name,
|
||||||
|
'can_set_sticker_set': self.can_set_sticker_set
|
||||||
}
|
}
|
||||||
chat = Chat.de_json(json_dict, bot)
|
chat = Chat.de_json(json_dict, bot)
|
||||||
|
|
||||||
|
@ -49,6 +54,8 @@ class TestChat(object):
|
||||||
assert chat.title == self.title
|
assert chat.title == self.title
|
||||||
assert chat.type == self.type
|
assert chat.type == self.type
|
||||||
assert chat.all_members_are_administrators == self.all_members_are_administrators
|
assert chat.all_members_are_administrators == self.all_members_are_administrators
|
||||||
|
assert chat.sticker_set_name == self.sticker_set_name
|
||||||
|
assert chat.can_set_sticker_set == self.can_set_sticker_set
|
||||||
|
|
||||||
def test_to_dict(self, chat):
|
def test_to_dict(self, chat):
|
||||||
chat_dict = chat.to_dict()
|
chat_dict = chat.to_dict()
|
||||||
|
|
|
@ -29,6 +29,7 @@ def inline_query_result_location():
|
||||||
TestInlineQueryResultLocation.latitude,
|
TestInlineQueryResultLocation.latitude,
|
||||||
TestInlineQueryResultLocation.longitude,
|
TestInlineQueryResultLocation.longitude,
|
||||||
TestInlineQueryResultLocation.title,
|
TestInlineQueryResultLocation.title,
|
||||||
|
live_period=TestInlineQueryResultLocation.live_period,
|
||||||
thumb_url=TestInlineQueryResultLocation.thumb_url,
|
thumb_url=TestInlineQueryResultLocation.thumb_url,
|
||||||
thumb_width=TestInlineQueryResultLocation.thumb_width,
|
thumb_width=TestInlineQueryResultLocation.thumb_width,
|
||||||
thumb_height=TestInlineQueryResultLocation.thumb_height,
|
thumb_height=TestInlineQueryResultLocation.thumb_height,
|
||||||
|
@ -42,6 +43,7 @@ class TestInlineQueryResultLocation(object):
|
||||||
latitude = 0.0
|
latitude = 0.0
|
||||||
longitude = 1.0
|
longitude = 1.0
|
||||||
title = 'title'
|
title = 'title'
|
||||||
|
live_period = 70
|
||||||
thumb_url = 'thumb url'
|
thumb_url = 'thumb url'
|
||||||
thumb_width = 10
|
thumb_width = 10
|
||||||
thumb_height = 15
|
thumb_height = 15
|
||||||
|
@ -54,6 +56,7 @@ class TestInlineQueryResultLocation(object):
|
||||||
assert inline_query_result_location.latitude == self.latitude
|
assert inline_query_result_location.latitude == self.latitude
|
||||||
assert inline_query_result_location.longitude == self.longitude
|
assert inline_query_result_location.longitude == self.longitude
|
||||||
assert inline_query_result_location.title == self.title
|
assert inline_query_result_location.title == self.title
|
||||||
|
assert inline_query_result_location.live_period == self.live_period
|
||||||
assert inline_query_result_location.thumb_url == self.thumb_url
|
assert inline_query_result_location.thumb_url == self.thumb_url
|
||||||
assert inline_query_result_location.thumb_width == self.thumb_width
|
assert inline_query_result_location.thumb_width == self.thumb_width
|
||||||
assert inline_query_result_location.thumb_height == self.thumb_height
|
assert inline_query_result_location.thumb_height == self.thumb_height
|
||||||
|
@ -72,6 +75,8 @@ class TestInlineQueryResultLocation(object):
|
||||||
assert inline_query_result_location_dict['longitude'] == \
|
assert inline_query_result_location_dict['longitude'] == \
|
||||||
inline_query_result_location.longitude
|
inline_query_result_location.longitude
|
||||||
assert inline_query_result_location_dict['title'] == inline_query_result_location.title
|
assert inline_query_result_location_dict['title'] == inline_query_result_location.title
|
||||||
|
assert inline_query_result_location_dict[
|
||||||
|
'live_period'] == inline_query_result_location.live_period
|
||||||
assert inline_query_result_location_dict['thumb_url'] == \
|
assert inline_query_result_location_dict['thumb_url'] == \
|
||||||
inline_query_result_location.thumb_url
|
inline_query_result_location.thumb_url
|
||||||
assert inline_query_result_location_dict['thumb_width'] == \
|
assert inline_query_result_location_dict['thumb_width'] == \
|
||||||
|
|
|
@ -25,16 +25,19 @@ from telegram import InputLocationMessageContent
|
||||||
@pytest.fixture(scope='class')
|
@pytest.fixture(scope='class')
|
||||||
def input_location_message_content():
|
def input_location_message_content():
|
||||||
return InputLocationMessageContent(TestInputLocationMessageContent.latitude,
|
return InputLocationMessageContent(TestInputLocationMessageContent.latitude,
|
||||||
TestInputLocationMessageContent.longitude)
|
TestInputLocationMessageContent.longitude,
|
||||||
|
live_period=TestInputLocationMessageContent.live_period)
|
||||||
|
|
||||||
|
|
||||||
class TestInputLocationMessageContent(object):
|
class TestInputLocationMessageContent(object):
|
||||||
latitude = -23.691288
|
latitude = -23.691288
|
||||||
longitude = -46.788279
|
longitude = -46.788279
|
||||||
|
live_period = 80
|
||||||
|
|
||||||
def test_expected_values(self, input_location_message_content):
|
def test_expected_values(self, input_location_message_content):
|
||||||
assert input_location_message_content.longitude == self.longitude
|
assert input_location_message_content.longitude == self.longitude
|
||||||
assert input_location_message_content.latitude == self.latitude
|
assert input_location_message_content.latitude == self.latitude
|
||||||
|
assert input_location_message_content.live_period == self.live_period
|
||||||
|
|
||||||
def test_to_dict(self, input_location_message_content):
|
def test_to_dict(self, input_location_message_content):
|
||||||
input_location_message_content_dict = input_location_message_content.to_dict()
|
input_location_message_content_dict = input_location_message_content.to_dict()
|
||||||
|
@ -44,3 +47,5 @@ class TestInputLocationMessageContent(object):
|
||||||
input_location_message_content.latitude
|
input_location_message_content.latitude
|
||||||
assert input_location_message_content_dict['longitude'] == \
|
assert input_location_message_content_dict['longitude'] == \
|
||||||
input_location_message_content.longitude
|
input_location_message_content.longitude
|
||||||
|
assert input_location_message_content_dict[
|
||||||
|
'live_period'] == input_location_message_content.live_period
|
||||||
|
|
|
@ -18,8 +18,10 @@
|
||||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from flaky import flaky
|
||||||
|
|
||||||
from telegram import Location
|
from telegram import Location
|
||||||
|
from telegram.error import BadRequest
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='class')
|
@pytest.fixture(scope='class')
|
||||||
|
@ -39,6 +41,46 @@ class TestLocation(object):
|
||||||
assert location.latitude == self.latitude
|
assert location.latitude == self.latitude
|
||||||
assert location.longitude == self.longitude
|
assert location.longitude == self.longitude
|
||||||
|
|
||||||
|
@flaky(3, 1)
|
||||||
|
@pytest.mark.timeout(10)
|
||||||
|
def test_send_live_location(self, bot, chat_id):
|
||||||
|
message = bot.send_location(chat_id=chat_id, latitude=52.223880, longitude=5.166146,
|
||||||
|
live_period=80)
|
||||||
|
assert message.location
|
||||||
|
assert message.location.latitude == 52.223880
|
||||||
|
assert message.location.longitude == 5.166146
|
||||||
|
|
||||||
|
message2 = bot.edit_message_live_location(message.chat_id, message.message_id,
|
||||||
|
latitude=52.223098, longitude=5.164306)
|
||||||
|
|
||||||
|
assert message2.location.latitude == 52.223098
|
||||||
|
assert message2.location.longitude == 5.164306
|
||||||
|
|
||||||
|
bot.stop_message_live_location(message.chat_id, message.message_id)
|
||||||
|
with pytest.raises(BadRequest, match="Message can't be edited"):
|
||||||
|
bot.edit_message_live_location(message.chat_id, message.message_id, latitude=52.223880,
|
||||||
|
longitude=5.164306)
|
||||||
|
|
||||||
|
# TODO: Needs improvement with in inline sent live location.
|
||||||
|
def test_edit_live_inline_message(self, monkeypatch, bot, location):
|
||||||
|
def test(_, url, data, **kwargs):
|
||||||
|
lat = data['latitude'] == location.latitude
|
||||||
|
lon = data['longitude'] == location.longitude
|
||||||
|
id = data['inline_message_id'] == 1234
|
||||||
|
return lat and lon and id
|
||||||
|
|
||||||
|
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||||
|
assert bot.edit_message_live_location(inline_message_id=1234, location=location)
|
||||||
|
|
||||||
|
# TODO: Needs improvement with in inline sent live location.
|
||||||
|
def test_stop_live_inline_message(self, monkeypatch, bot):
|
||||||
|
def test(_, url, data, **kwargs):
|
||||||
|
id = data['inline_message_id'] == 1234
|
||||||
|
return id
|
||||||
|
|
||||||
|
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||||
|
assert bot.stop_message_live_location(inline_message_id=1234)
|
||||||
|
|
||||||
def test_send_with_location(self, monkeypatch, bot, chat_id, location):
|
def test_send_with_location(self, monkeypatch, bot, chat_id, location):
|
||||||
def test(_, url, data, **kwargs):
|
def test(_, url, data, **kwargs):
|
||||||
lat = data['latitude'] == location.latitude
|
lat = data['latitude'] == location.latitude
|
||||||
|
@ -48,10 +90,32 @@ class TestLocation(object):
|
||||||
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||||
assert bot.send_location(location=location, chat_id=chat_id)
|
assert bot.send_location(location=location, chat_id=chat_id)
|
||||||
|
|
||||||
|
def test_edit_live_location_with_location(self, monkeypatch, bot, location):
|
||||||
|
def test(_, url, data, **kwargs):
|
||||||
|
lat = data['latitude'] == location.latitude
|
||||||
|
lon = data['longitude'] == location.longitude
|
||||||
|
return lat and lon
|
||||||
|
|
||||||
|
monkeypatch.setattr('telegram.utils.request.Request.post', test)
|
||||||
|
assert bot.edit_message_live_location(None, None, location=location)
|
||||||
|
|
||||||
def test_send_location_without_required(self, bot, chat_id):
|
def test_send_location_without_required(self, bot, chat_id):
|
||||||
with pytest.raises(ValueError, match='Either location or latitude and longitude'):
|
with pytest.raises(ValueError, match='Either location or latitude and longitude'):
|
||||||
bot.send_location(chat_id=chat_id)
|
bot.send_location(chat_id=chat_id)
|
||||||
|
|
||||||
|
def test_edit_location_without_required(self, bot):
|
||||||
|
with pytest.raises(ValueError, match='Either location or latitude and longitude'):
|
||||||
|
bot.edit_message_live_location(chat_id=2, message_id=3)
|
||||||
|
|
||||||
|
def test_send_location_with_all_args(self, bot, location):
|
||||||
|
with pytest.raises(ValueError, match='Not both'):
|
||||||
|
bot.send_location(chat_id=1, latitude=2.5, longitude=4.6, location=location)
|
||||||
|
|
||||||
|
def test_edit_location_with_all_args(self, bot, location):
|
||||||
|
with pytest.raises(ValueError, match='Not both'):
|
||||||
|
bot.edit_message_live_location(chat_id=1, message_id=7, latitude=2.5, longitude=4.6,
|
||||||
|
location=location)
|
||||||
|
|
||||||
def test_to_dict(self, location):
|
def test_to_dict(self, location):
|
||||||
location_dict = location.to_dict()
|
location_dict = location.to_dict()
|
||||||
|
|
||||||
|
|
|
@ -40,9 +40,12 @@ def message(bot):
|
||||||
'forward_date': datetime.now()},
|
'forward_date': datetime.now()},
|
||||||
{'reply_to_message': Message(50, None, None, None)},
|
{'reply_to_message': Message(50, None, None, None)},
|
||||||
{'edit_date': datetime.now()},
|
{'edit_date': datetime.now()},
|
||||||
{'test': 'a text message',
|
{'text': 'a text message',
|
||||||
'enitites': [MessageEntity('bold', 10, 4),
|
'enitites': [MessageEntity('bold', 10, 4),
|
||||||
MessageEntity('italic', 16, 7)]},
|
MessageEntity('italic', 16, 7)]},
|
||||||
|
{'caption': 'A message caption',
|
||||||
|
'caption_entities': [MessageEntity('bold', 1, 1),
|
||||||
|
MessageEntity('text_link', 4, 3)]},
|
||||||
{'audio': Audio('audio_id', 12),
|
{'audio': Audio('audio_id', 12),
|
||||||
'caption': 'audio_file'},
|
'caption': 'audio_file'},
|
||||||
{'document': Document('document_id'),
|
{'document': Document('document_id'),
|
||||||
|
@ -78,12 +81,13 @@ def message(bot):
|
||||||
{'forward_signature': 'some_forward_sign'},
|
{'forward_signature': 'some_forward_sign'},
|
||||||
{'author_signature': 'some_author_sign'}
|
{'author_signature': 'some_author_sign'}
|
||||||
],
|
],
|
||||||
ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text', 'audio',
|
ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text',
|
||||||
'document', 'game', 'photo', 'sticker', 'video', 'voice', 'video_note',
|
'caption_entities', 'audio', 'document', 'game', 'photo', 'sticker', 'video',
|
||||||
'new_members', 'contact', 'location', 'venue', 'left_member', 'new_title',
|
'voice', 'video_note', 'new_members', 'contact', 'location', 'venue',
|
||||||
'new_photo', 'delete_photo', 'group_created', 'supergroup_created',
|
'left_member', 'new_title', 'new_photo', 'delete_photo', 'group_created',
|
||||||
'channel_created', 'migrated_to', 'migrated_from', 'pinned', 'invoice',
|
'supergroup_created', 'channel_created', 'migrated_to', 'migrated_from',
|
||||||
'successful_payment', 'forward_signature', 'author_signature'])
|
'pinned', 'invoice', 'successful_payment', 'forward_signature',
|
||||||
|
'author_signature'])
|
||||||
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,
|
||||||
|
@ -127,6 +131,14 @@ class TestMessage(object):
|
||||||
message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[entity])
|
message = Message(1, self.from_user, self.date, self.chat, text=text, entities=[entity])
|
||||||
assert message.parse_entity(entity) == 'http://google.com'
|
assert message.parse_entity(entity) == 'http://google.com'
|
||||||
|
|
||||||
|
def test_parse_caption_entity(self):
|
||||||
|
caption = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
|
||||||
|
b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
|
||||||
|
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||||
|
message = Message(1, self.from_user, self.date, self.chat, caption=caption,
|
||||||
|
caption_entities=[entity])
|
||||||
|
assert message.parse_caption_entity(entity) == 'http://google.com'
|
||||||
|
|
||||||
def test_parse_entities(self):
|
def test_parse_entities(self):
|
||||||
text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
|
text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
|
||||||
b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
|
b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
|
||||||
|
@ -137,6 +149,16 @@ class TestMessage(object):
|
||||||
assert message.parse_entities(MessageEntity.URL) == {entity: 'http://google.com'}
|
assert message.parse_entities(MessageEntity.URL) == {entity: 'http://google.com'}
|
||||||
assert message.parse_entities() == {entity: 'http://google.com', entity_2: 'h'}
|
assert message.parse_entities() == {entity: 'http://google.com', entity_2: 'h'}
|
||||||
|
|
||||||
|
def test_parse_caption_entities(self):
|
||||||
|
text = (b'\\U0001f469\\u200d\\U0001f469\\u200d\\U0001f467'
|
||||||
|
b'\\u200d\\U0001f467\\U0001f431http://google.com').decode('unicode-escape')
|
||||||
|
entity = MessageEntity(type=MessageEntity.URL, offset=13, length=17)
|
||||||
|
entity_2 = MessageEntity(type=MessageEntity.BOLD, offset=13, length=1)
|
||||||
|
message = Message(1, self.from_user, self.date, self.chat,
|
||||||
|
caption=text, caption_entities=[entity_2, entity])
|
||||||
|
assert message.parse_caption_entities(MessageEntity.URL) == {entity: 'http://google.com'}
|
||||||
|
assert message.parse_caption_entities() == {entity: 'http://google.com', entity_2: 'h'}
|
||||||
|
|
||||||
def test_text_html_simple(self):
|
def test_text_html_simple(self):
|
||||||
test_html_string = ('Test for <<b>bold</b>, <i>ita_lic</i>, <code>code</code>, '
|
test_html_string = ('Test for <<b>bold</b>, <i>ita_lic</i>, <code>code</code>, '
|
||||||
'<a href="http://github.com/">links</a> and <pre>pre</pre>. '
|
'<a href="http://github.com/">links</a> and <pre>pre</pre>. '
|
||||||
|
@ -201,7 +223,6 @@ class TestMessage(object):
|
||||||
item = None
|
item = None
|
||||||
assert message_params.effective_attachment == item
|
assert message_params.effective_attachment == item
|
||||||
|
|
||||||
|
|
||||||
def test_reply_text(self, monkeypatch, message):
|
def test_reply_text(self, monkeypatch, message):
|
||||||
def test(*args, **kwargs):
|
def test(*args, **kwargs):
|
||||||
id = args[1] == message.chat_id
|
id = args[1] == message.chat_id
|
||||||
|
|
|
@ -33,6 +33,8 @@ import telegram
|
||||||
IGNORED_OBJECTS = ('ResponseParameters', 'CallbackGame')
|
IGNORED_OBJECTS = ('ResponseParameters', 'CallbackGame')
|
||||||
IGNORED_PARAMETERS = {'self', 'args', 'kwargs', 'read_latency', 'network_delay', 'timeout', 'bot',
|
IGNORED_PARAMETERS = {'self', 'args', 'kwargs', 'read_latency', 'network_delay', 'timeout', 'bot',
|
||||||
'new_chat_member'}
|
'new_chat_member'}
|
||||||
|
|
||||||
|
|
||||||
# TODO: New_chat_member is still in our lib but already removed from TG's docs.
|
# TODO: New_chat_member is still in our lib but already removed from TG's docs.
|
||||||
|
|
||||||
|
|
||||||
|
@ -49,10 +51,10 @@ def parse_table(h4):
|
||||||
if not table:
|
if not table:
|
||||||
return []
|
return []
|
||||||
head = [td.text for td in table.tr.find_all('td')]
|
head = [td.text for td in table.tr.find_all('td')]
|
||||||
row = namedtuple('{}TableRow'.format(h4.text), ','.join(head))
|
# row = namedtuple('{}TableRow'.format(h4.text), ','.join(head))
|
||||||
t = []
|
t = []
|
||||||
for tr in table.find_all('tr')[1:]:
|
for tr in table.find_all('tr')[1:]:
|
||||||
t.append(row(*[td.text for td in tr.find_all('td')]))
|
t.append([td.text for td in tr.find_all('td')])
|
||||||
return t
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
@ -66,12 +68,12 @@ def check_method(h4):
|
||||||
|
|
||||||
checked = []
|
checked = []
|
||||||
for parameter in table:
|
for parameter in table:
|
||||||
param = sig.parameters.get(parameter.Parameters)
|
param = sig.parameters.get(parameter[0])
|
||||||
assert param is not None, "Parameter {} not found in {}".format(parameter.Parameters,
|
assert param is not None, "Parameter {} not found in {}".format(parameter[0],
|
||||||
method.__name__)
|
method.__name__)
|
||||||
# TODO: Check type via docstring
|
# TODO: Check type via docstring
|
||||||
# TODO: Check if optional or required
|
# TODO: Check if optional or required
|
||||||
checked.append(parameter.Parameters)
|
checked.append(parameter[0])
|
||||||
|
|
||||||
ignored = IGNORED_PARAMETERS.copy()
|
ignored = IGNORED_PARAMETERS.copy()
|
||||||
if name == 'getUpdates':
|
if name == 'getUpdates':
|
||||||
|
@ -82,7 +84,7 @@ def check_method(h4):
|
||||||
ignored |= {'edit_message'} # TODO: Now deprecated, so no longer in telegrams docs
|
ignored |= {'edit_message'} # TODO: Now deprecated, so no longer in telegrams docs
|
||||||
elif name == 'sendContact':
|
elif name == 'sendContact':
|
||||||
ignored |= {'contact'} # Added for ease of use
|
ignored |= {'contact'} # Added for ease of use
|
||||||
elif name == 'sendLocation':
|
elif name in ['sendLocation', 'editMessageLiveLocation']:
|
||||||
ignored |= {'location'} # Added for ease of use
|
ignored |= {'location'} # Added for ease of use
|
||||||
elif name == 'sendVenue':
|
elif name == 'sendVenue':
|
||||||
ignored |= {'venue'} # Added for ease of use
|
ignored |= {'venue'} # Added for ease of use
|
||||||
|
@ -100,7 +102,7 @@ def check_object(h4):
|
||||||
|
|
||||||
checked = []
|
checked = []
|
||||||
for parameter in table:
|
for parameter in table:
|
||||||
field = parameter.Field
|
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') and field == 'type':
|
||||||
|
|
Loading…
Reference in a new issue