mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2025-03-16 20:29:55 +01:00
Bot api 3.1 (#698) + minor improvements
- Added all the new and shiny features from API 3.1. - Not API 3.1 changes: - Use future.utils.string_types for string isinstance checks. - Stall between retries of test_set_webhook_get_webhook_info() & test_delete_webhook().
This commit is contained in:
parent
cbafdc289f
commit
94ed4cb38d
11 changed files with 596 additions and 73 deletions
|
@ -2,6 +2,13 @@
|
|||
Changes
|
||||
=======
|
||||
|
||||
**DATE TBD**
|
||||
*WIP 6.2.0*
|
||||
- Improved filters for user_id/username/chat.
|
||||
- Internal restructure of files.
|
||||
- Improved unitests.
|
||||
- Fully support Bot API 3.1.
|
||||
|
||||
**2017-06-18**
|
||||
|
||||
*Released 6.1.0*
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
from .base import TelegramObject
|
||||
from .user import User
|
||||
from .files.chatphoto import ChatPhoto
|
||||
from .chat import Chat
|
||||
from .chatmember import ChatMember
|
||||
from .files.photosize import PhotoSize
|
||||
|
@ -119,5 +120,5 @@ __all__ = [
|
|||
'MAX_FILESIZE_DOWNLOAD', 'MAX_FILESIZE_UPLOAD', 'MAX_MESSAGES_PER_SECOND_PER_CHAT',
|
||||
'MAX_MESSAGES_PER_SECOND', 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', 'WebhookInfo', 'Animation',
|
||||
'Game', 'GameHighScore', 'VideoNote', 'LabeledPrice', 'SuccessfulPayment', 'ShippingOption',
|
||||
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery'
|
||||
'ShippingAddress', 'PreCheckoutQuery', 'OrderInfo', 'Invoice', 'ShippingQuery', 'ChatPhoto'
|
||||
]
|
||||
|
|
395
telegram/bot.py
395
telegram/bot.py
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=E0611,E0213,E1102,C0103,E1101,W0613,R0913,R0904
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
|
@ -22,10 +23,12 @@
|
|||
import functools
|
||||
import logging
|
||||
import warnings
|
||||
from datetime import datetime
|
||||
|
||||
from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos, File,
|
||||
ReplyMarkup, TelegramObject, WebhookInfo, GameHighScore)
|
||||
from telegram.error import InvalidToken, TelegramError
|
||||
from telegram.utils.helpers import to_timestamp
|
||||
from telegram.utils.request import Request
|
||||
|
||||
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
||||
|
@ -1039,12 +1042,12 @@ class Bot(TelegramObject):
|
|||
return File.de_json(result, self)
|
||||
|
||||
@log
|
||||
def kick_chat_member(self, chat_id, user_id, timeout=None, **kwargs):
|
||||
"""Use this method to kick a user from a group or a supergroup.
|
||||
def kick_chat_member(self, chat_id, user_id, timeout=None, until_date=None, **kwargs):
|
||||
"""Use this method to kick a user from a group, a supergroup or a channel.
|
||||
|
||||
In the case of supergroups, the user will not be able to return to the group on their own
|
||||
using invite links, etc., unless unbanned first. The bot must be an administrator in the
|
||||
group for this to work.
|
||||
In the case of supergroups and channels, the user will not be able to return to the group
|
||||
on their own using invite links, etc., unless unbanned first. The bot must be an
|
||||
administrator in the chat for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target group or username of the target
|
||||
|
@ -1053,8 +1056,16 @@ class Bot(TelegramObject):
|
|||
timeout (Optional[int|float]): 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).
|
||||
until_date (Optional[int|datetime]): Date when the user will be unbanned,
|
||||
unix time. If user is banned for more than 366 days or less than 30 seconds from
|
||||
the current time they are considered to be banned forever
|
||||
**kwargs (dict): Arbitrary keyword arguments.
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the
|
||||
'All Members Are Admins' setting is off in the target group. Otherwise
|
||||
members may only be removed by the group's creator or by the member that added them.
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
|
@ -1066,6 +1077,11 @@ class Bot(TelegramObject):
|
|||
|
||||
data = {'chat_id': chat_id, 'user_id': user_id}
|
||||
|
||||
if until_date is not None:
|
||||
if isinstance(until_date, datetime):
|
||||
until_date = to_timestamp(until_date)
|
||||
data['until_date'] = until_date
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
@ -1993,6 +2009,366 @@ class Bot(TelegramObject):
|
|||
|
||||
return result
|
||||
|
||||
@log
|
||||
def restrict_chat_member(self, chat_id, user_id, until_date=None, can_send_messages=None,
|
||||
can_send_media_messages=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, timeout=None, **kwargs):
|
||||
"""Use this method to restrict a user in a supergroup.
|
||||
|
||||
The bot must be an administrator in the supergroup for this to work and must have the
|
||||
appropriate admin rights. Pass True for all boolean parameters to lift restrictions
|
||||
from a user.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
supergroup (in the format @supergroupusername)
|
||||
user_id (int): Unique identifier of the target user
|
||||
until_date (Optional[int|datetime]): Date when restrictions will be lifted for the
|
||||
user, unix time. If user is restricted for more than 366 days or less than 30
|
||||
seconds from the current time, they are considered to be restricted forever
|
||||
can_send_messages (Optional[boolean]): Pass True, if the user can send text messages,
|
||||
contacts, locations and venues
|
||||
can_send_media_messages (Optional[boolean]): Pass True, if the user can send audios,
|
||||
documents, photos, videos, video notes and voice notes, implies can_send_messages
|
||||
can_send_other_messages (Optional[boolean]): Pass True, if the user can send
|
||||
animations, games, stickers and use inline bots, implies can_send_media_messages
|
||||
can_add_web_page_previews (Optional[boolean]): Pass True, if the user may add web page
|
||||
previews to their messages, implies can_send_media_messages
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/restrictChatMember'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'user_id': user_id}
|
||||
|
||||
if until_date is not None:
|
||||
if isinstance(until_date, datetime):
|
||||
until_date = to_timestamp(until_date)
|
||||
data['until_date'] = until_date
|
||||
if can_send_messages is not None:
|
||||
data['can_send_messages'] = can_send_messages
|
||||
if can_send_media_messages is not None:
|
||||
data['can_send_media_messages'] = can_send_media_messages
|
||||
if can_send_other_messages is not None:
|
||||
data['can_send_other_messages'] = can_send_other_messages
|
||||
if can_add_web_page_previews is not None:
|
||||
data['can_add_web_page_previews'] = can_add_web_page_previews
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def promote_chat_member(self, chat_id, user_id, can_change_info=None,
|
||||
can_post_messages=None, can_edit_messages=None,
|
||||
can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None,
|
||||
can_promote_members=None, timeout=None, **kwargs):
|
||||
"""Use this method to promote or demote a user in a supergroup or a channel.
|
||||
|
||||
The bot must be an administrator in the chat for this to work and must have the
|
||||
appropriate admin rights. Pass False for all boolean parameters to demote a user
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
supergroup (in the format @supergroupusername)
|
||||
user_id (int): Unique identifier of the target user
|
||||
can_change_info (Optional[boolean]): Pass True, if the administrator can change chat
|
||||
title, photo and other settings
|
||||
can_post_messages (Optional[boolean]): Pass True, if the administrator can create
|
||||
channel posts, channels only
|
||||
can_edit_messages (Optional[boolean]): Pass True, if the administrator can edit
|
||||
messages of other users, channels only
|
||||
can_delete_messages (Optional[boolean]): Pass True, if the administrator can delete
|
||||
messages of other users
|
||||
can_invite_users (Optional[boolean]): Pass True, if the administrator can invite new
|
||||
users to the chat
|
||||
can_restrict_members (Optional[boolean]): Pass True, if the administrator can restrict,
|
||||
ban or unban chat members
|
||||
can_pin_messages (Optional[boolean]): Pass True, if the administrator can pin messages,
|
||||
supergroups only
|
||||
can_promote_members (Optional[boolean]): Pass True, if the administrator can add new
|
||||
administrators with a subset of his own privileges or demote administrators that
|
||||
he has promoted, directly or indirectly (promoted by administrators that were
|
||||
appointed by him)
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/promoteChatMember'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'user_id': user_id}
|
||||
|
||||
if can_change_info is not None:
|
||||
data['can_change_info'] = can_change_info
|
||||
if can_post_messages is not None:
|
||||
data['can_post_messages'] = can_post_messages
|
||||
if can_edit_messages is not None:
|
||||
data['can_edit_messages'] = can_edit_messages
|
||||
if can_delete_messages is not None:
|
||||
data['can_delete_messages'] = can_delete_messages
|
||||
if can_invite_users is not None:
|
||||
data['can_invite_users'] = can_invite_users
|
||||
if can_restrict_members is not None:
|
||||
data['can_restrict_members'] = can_restrict_members
|
||||
if can_pin_messages is not None:
|
||||
data['can_pin_messages'] = can_pin_messages
|
||||
if can_promote_members is not None:
|
||||
data['can_promote_members'] = can_promote_members
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def export_chat_invite_link(self, chat_id, timeout=None, **kwargs):
|
||||
"""Use this method to export an invite link to a supergroup or a channel.
|
||||
|
||||
The bot must be an administrator in the chat for this to work and must have the
|
||||
appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
str: On success the exported invite link is returned
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/exportChatInviteLink'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def set_chat_photo(self, chat_id, photo, timeout=None, **kwargs):
|
||||
"""Use this method to set a new profile photo for the chat.
|
||||
|
||||
Photos can't be changed for private chats. The bot must be an administrator in the chat
|
||||
for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
photo (`telegram.InputFile`): New chat photo
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the
|
||||
'All Members Are Admins' setting is off in the target group.
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/setChatPhoto'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'photo': photo}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def delete_chat_photo(self, chat_id, timeout=None, **kwargs):
|
||||
"""Use this method to delete a chat photo.
|
||||
|
||||
Photos can't be changed for private chats. The bot must be an administrator in the chat
|
||||
for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the
|
||||
'All Members Are Admins' setting is off in the target group.
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/deleteChatPhoto'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def set_chat_title(self, chat_id, title, timeout=None, **kwargs):
|
||||
"""Use this method to change the title of a chat.
|
||||
|
||||
Titles can't be changed for private chats. The bot must be an administrator in the chat
|
||||
for this to work and must have the appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
title (str): New chat title, 1-255 characters
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Note:
|
||||
In regular groups (non-supergroups), this method will only work if the
|
||||
'All Members Are Admins' setting is off in the target group.
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/setChatTitle'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'title': title}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def set_chat_description(self, chat_id, description, timeout=None, **kwargs):
|
||||
"""Use this method to change the description of a supergroup or a channel.
|
||||
|
||||
The bot must be an administrator in the chat for this to work and must have the
|
||||
appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
description (str): New chat description, 1-255 characters
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/setChatDescription'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'description': description}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def pin_chat_message(self, chat_id, message_id, disable_notification=None, timeout=None,
|
||||
**kwargs):
|
||||
"""Use this method to pin a message in a supergroup.
|
||||
|
||||
The bot must be an administrator in the chat for this to work and must have the
|
||||
appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
message_id (int): Identifier of a message to pin
|
||||
disable_notification (boolean): Pass True, if it is not necessary to send a
|
||||
notification to all group members about the new pinned message
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/pinChatMessage'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id, 'message_id': message_id}
|
||||
|
||||
if disable_notification is not None:
|
||||
data['disable_notification'] = disable_notification
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@log
|
||||
def unpin_chat_message(self, chat_id, timeout=None, **kwargs):
|
||||
"""Use this method to unpin a message in a supergroup.
|
||||
|
||||
The bot must be an administrator in the chat for this to work and must have the
|
||||
appropriate admin rights.
|
||||
|
||||
Args:
|
||||
chat_id (int|str): Unique identifier for the target chat or username of the target
|
||||
channel (in the format @channelusername)
|
||||
timeout (Optional[int|float]): 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 (dict): Arbitrary keyword arguments
|
||||
|
||||
Returns:
|
||||
bool: On success, `True` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`telegram.TelegramError`
|
||||
|
||||
"""
|
||||
url = '{0}/unpinChatMessage'.format(self.base_url)
|
||||
|
||||
data = {'chat_id': chat_id}
|
||||
|
||||
result = self._request.post(url, data, timeout=timeout)
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def de_json(data, bot):
|
||||
data = super(Bot, Bot).de_json(data, bot)
|
||||
|
@ -2051,3 +2427,12 @@ class Bot(TelegramObject):
|
|||
sendInvoice = send_invoice
|
||||
answerShippingQuery = answer_shipping_query
|
||||
answerPreCheckoutQuery = answer_pre_checkout_query
|
||||
restrictChatMember = restrict_chat_member
|
||||
promoteChatMember = promote_chat_member
|
||||
exportChatInviteLink = export_chat_invite_link
|
||||
setChatPhoto = set_chat_photo
|
||||
deleteChatPhoto = delete_chat_photo
|
||||
setChatTitle = set_chat_title
|
||||
setChatDescription = set_chat_description
|
||||
pinChatMessage = pin_chat_message
|
||||
unpinChatMessage = unpin_chat_message
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Chat."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
from telegram import TelegramObject, ChatPhoto
|
||||
|
||||
|
||||
class Chat(TelegramObject):
|
||||
|
@ -33,14 +33,13 @@ class Chat(TelegramObject):
|
|||
first_name (str): First name of the other party in a private chat
|
||||
last_name (str): Last name of the other party in a private chat
|
||||
all_members_are_administrators (bool): True if group has 'All Members Are Administrators'
|
||||
photo (Optional[`telegram.ChatPhoto`]): Chat photo. Returned only in getChat.
|
||||
description (str): Description, for supergroups and channel chats. Returned
|
||||
only in getChat.
|
||||
invite_link (str): Chat invite link, for supergroups and channel chats. Returned
|
||||
only in getChat.
|
||||
|
||||
Args:
|
||||
id (int):
|
||||
type (str):
|
||||
title (Optional[str]):
|
||||
username(Optional[str]):
|
||||
first_name(Optional[str]):
|
||||
last_name(Optional[str]):
|
||||
bot (Optional[telegram.Bot]): The Bot to use for instance methods
|
||||
**kwargs (dict): Arbitrary keyword arguments.
|
||||
|
||||
|
@ -59,6 +58,9 @@ class Chat(TelegramObject):
|
|||
last_name=None,
|
||||
all_members_are_administrators=None,
|
||||
bot=None,
|
||||
photo=None,
|
||||
description=None,
|
||||
invite_link=None,
|
||||
**kwargs):
|
||||
# Required
|
||||
self.id = int(id)
|
||||
|
@ -69,6 +71,9 @@ class Chat(TelegramObject):
|
|||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.all_members_are_administrators = all_members_are_administrators
|
||||
self.photo = photo
|
||||
self.description = description
|
||||
self.invite_link = invite_link
|
||||
|
||||
self.bot = bot
|
||||
self._id_attrs = (self.id,)
|
||||
|
@ -86,6 +91,8 @@ class Chat(TelegramObject):
|
|||
if not data:
|
||||
return None
|
||||
|
||||
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
|
||||
|
||||
return Chat(bot=bot, **data)
|
||||
|
||||
def send_action(self, *args, **kwargs):
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
"""This module contains an object that represents a Telegram ChatMember."""
|
||||
|
||||
from telegram import User, TelegramObject
|
||||
from telegram.utils.helpers import to_timestamp, from_timestamp
|
||||
|
||||
|
||||
class ChatMember(TelegramObject):
|
||||
|
@ -28,10 +29,39 @@ class ChatMember(TelegramObject):
|
|||
user (:class:`telegram.User`): Information about the user.
|
||||
status (str): The member's status in the chat. Can be 'creator', 'administrator', 'member',
|
||||
'left' or 'kicked'.
|
||||
until_date (Optional[:class:`datetime.datetime`]): Restricted and kicked only. Date when
|
||||
restrictions will be lifted for this user.
|
||||
can_be_edited (Optional[boolean]): Administrators only. True, if the bot is allowed to
|
||||
edit administrator privileges of that user
|
||||
can_change_info (Optional[boolean]): Administrators only. True, if the administrator can
|
||||
change the chat title, photo and other settings
|
||||
can_post_messages (Optional[boolean]): Administrators only. True, if the administrator can
|
||||
post in the channel, channels only
|
||||
can_edit_messages (Optional[boolean]): Administrators only. True, if the administrator can
|
||||
edit messages of other users, channels only
|
||||
can_delete_messages (Optional[boolean]): Administrators only. True, if the administrator
|
||||
can delete messages of other user
|
||||
can_invite_users (Optional[boolean]): Administrators only. True, if the administrator can
|
||||
invite new users to the chat
|
||||
can_restrict_members (Optional[boolean]): Administrators only. True, if the administrator
|
||||
can restrict, ban or unban chat members
|
||||
can_pin_messages (Optional[boolean]): Administrators only. True, if the administrator can
|
||||
pin messages, supergroups only
|
||||
can_promote_members (Optional[boolean]): Administrators only. True, if the administrator
|
||||
can add new administrators with a subset of his own privileges or demote administrators
|
||||
that he has promoted, directly or indirectly (promoted by administrators that were
|
||||
appointed by the user)
|
||||
can_send_messages (Optional[boolean]): Restricted only. True, if the user can send text
|
||||
messages, contacts, locations and venues
|
||||
can_send_media_messages (Optional[boolean]): Restricted only. True, if the user can send
|
||||
audios, documents, photos, videos, video notes and voice notes,
|
||||
implies can_send_messages
|
||||
can_send_other_messages (Optional[boolean]): Restricted only. True, if the user can send
|
||||
animations, games, stickers and use inline bots, implies can_send_media_messages
|
||||
can_add_web_page_previews (Optional[boolean]): Restricted only. True, if user may add
|
||||
web page previews to his messages, implies can_send_media_messages
|
||||
|
||||
Args:
|
||||
user (:class:`telegram.User`):
|
||||
status (str):
|
||||
**kwargs (dict): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
@ -41,10 +71,30 @@ class ChatMember(TelegramObject):
|
|||
LEFT = 'left'
|
||||
KICKED = 'kicked'
|
||||
|
||||
def __init__(self, user, status, **kwargs):
|
||||
def __init__(self, user, status, until_date=None, can_be_edited=None,
|
||||
can_change_info=None, can_post_messages=None, can_edit_messages=None,
|
||||
can_delete_messages=None, can_invite_users=None,
|
||||
can_restrict_members=None, can_pin_messages=None,
|
||||
can_promote_members=None, can_send_messages=None,
|
||||
can_send_media_messages=None, can_send_other_messages=None,
|
||||
can_add_web_page_previews=None, **kwargs):
|
||||
# Required
|
||||
self.user = user
|
||||
self.status = status
|
||||
self.until_date = until_date
|
||||
self.can_be_edited = can_be_edited
|
||||
self.can_change_info = can_change_info
|
||||
self.can_post_messages = can_post_messages
|
||||
self.can_edit_messages = can_edit_messages
|
||||
self.can_delete_messages = can_delete_messages
|
||||
self.can_invite_users = can_invite_users
|
||||
self.can_restrict_members = can_restrict_members
|
||||
self.can_pin_messages = can_pin_messages
|
||||
self.can_promote_members = can_promote_members
|
||||
self.can_send_messages = can_send_messages
|
||||
self.can_send_media_messages = can_send_media_messages
|
||||
self.can_send_other_messages = can_send_other_messages
|
||||
self.can_add_web_page_previews = can_add_web_page_previews
|
||||
|
||||
self._id_attrs = (self.user, self.status)
|
||||
|
||||
|
@ -64,5 +114,17 @@ class ChatMember(TelegramObject):
|
|||
data = super(ChatMember, ChatMember).de_json(data, bot)
|
||||
|
||||
data['user'] = User.de_json(data.get('user'), bot)
|
||||
data['until_date'] = from_timestamp(data.get('until_date', None))
|
||||
|
||||
return ChatMember(**data)
|
||||
|
||||
def to_dict(self):
|
||||
"""
|
||||
Returns:
|
||||
dict:
|
||||
"""
|
||||
data = super(ChatMember, self).to_dict()
|
||||
|
||||
data['until_date'] = to_timestamp(self.until_date)
|
||||
|
||||
return data
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
""" This module contains the CommandHandler class """
|
||||
import warnings
|
||||
|
||||
from future.utils import string_types
|
||||
|
||||
from .handler import Handler
|
||||
from telegram import Update
|
||||
|
||||
|
@ -80,12 +82,8 @@ class CommandHandler(Handler):
|
|||
pass_job_queue=pass_job_queue,
|
||||
pass_user_data=pass_user_data,
|
||||
pass_chat_data=pass_chat_data)
|
||||
try:
|
||||
_str = basestring # Python 2
|
||||
except NameError:
|
||||
_str = str # Python 3
|
||||
|
||||
if isinstance(command, _str):
|
||||
if isinstance(command, string_types):
|
||||
self.command = [command.lower()]
|
||||
else:
|
||||
self.command = [x.lower() for x in command]
|
||||
|
|
|
@ -18,11 +18,7 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
""" This module contains the Filters for use with the MessageHandler class """
|
||||
from telegram import Chat
|
||||
|
||||
try:
|
||||
str_type = base_string
|
||||
except NameError:
|
||||
str_type = str
|
||||
from future.utils import string_types
|
||||
|
||||
|
||||
class BaseFilter(object):
|
||||
|
@ -383,7 +379,7 @@ class Filters(object):
|
|||
self.user_ids = user_id
|
||||
if username is None:
|
||||
self.usernames = username
|
||||
elif isinstance(username, str_type):
|
||||
elif isinstance(username, string_types):
|
||||
self.usernames = [username.replace('@', '')]
|
||||
else:
|
||||
self.usernames = [user.replace('@', '') for user in username]
|
||||
|
@ -420,7 +416,7 @@ class Filters(object):
|
|||
self.chat_ids = chat_id
|
||||
if username is None:
|
||||
self.usernames = username
|
||||
elif isinstance(username, str_type):
|
||||
elif isinstance(username, string_types):
|
||||
self.usernames = [username.replace('@', '')]
|
||||
else:
|
||||
self.usernames = [chat.replace('@', '') for chat in username]
|
||||
|
@ -460,7 +456,7 @@ class Filters(object):
|
|||
"""
|
||||
|
||||
def __init__(self, lang):
|
||||
if isinstance(lang, str_type):
|
||||
if isinstance(lang, string_types):
|
||||
self.lang = [lang]
|
||||
else:
|
||||
self.lang = lang
|
||||
|
|
55
telegram/files/chatphoto.py
Normal file
55
telegram/files/chatphoto.py
Normal file
|
@ -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 ChatPhoto."""
|
||||
|
||||
from telegram import TelegramObject
|
||||
|
||||
|
||||
class ChatPhoto(TelegramObject):
|
||||
""" This object represents a Telegram ChatPhoto
|
||||
|
||||
Attributes:
|
||||
small_file_id (str): Unique file identifier of small (160x160) chat photo. This file_id
|
||||
can be used only for photo download.
|
||||
big_file_id (str): Unique file identifier of big (640x640) chat photo. This file_id
|
||||
can be used only for photo download.
|
||||
|
||||
Args:
|
||||
bot (Optional[telegram.Bot]): The Bot to use for instance methods
|
||||
**kwargs (dict): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
def __init__(self, small_file_id, big_file_id, bot=None, **kwargs):
|
||||
self.small_file_id = small_file_id
|
||||
self.big_file_id = big_file_id
|
||||
|
||||
@staticmethod
|
||||
def de_json(data, bot):
|
||||
"""
|
||||
Args:
|
||||
data (dict):
|
||||
bot (telegram.Bot):
|
||||
|
||||
Returns:
|
||||
telegram.ChatPhoto:
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
return ChatPhoto(bot=bot, **data)
|
|
@ -19,14 +19,12 @@
|
|||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram Message."""
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from time import mktime
|
||||
|
||||
from telegram import (Audio, Contact, Document, Chat, Location, PhotoSize, Sticker, TelegramObject,
|
||||
User, Video, Voice, Venue, MessageEntity, Game, Invoice, SuccessfulPayment,
|
||||
VideoNote)
|
||||
from telegram.utils.deprecate import warn_deprecate_obj
|
||||
from telegram.utils.helpers import escape_html, escape_markdown
|
||||
from telegram.utils.helpers import escape_html, escape_markdown, to_timestamp, from_timestamp
|
||||
|
||||
|
||||
class Message(TelegramObject):
|
||||
|
@ -215,14 +213,14 @@ class Message(TelegramObject):
|
|||
data = super(Message, Message).de_json(data, bot)
|
||||
|
||||
data['from_user'] = User.de_json(data.get('from'), bot)
|
||||
data['date'] = Message._fromtimestamp(data['date'])
|
||||
data['date'] = from_timestamp(data['date'])
|
||||
data['chat'] = Chat.de_json(data.get('chat'), bot)
|
||||
data['entities'] = MessageEntity.de_list(data.get('entities'), 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_date'] = Message._fromtimestamp(data.get('forward_date'))
|
||||
data['forward_date'] = from_timestamp(data.get('forward_date'))
|
||||
data['reply_to_message'] = Message.de_json(data.get('reply_to_message'), bot)
|
||||
data['edit_date'] = Message._fromtimestamp(data.get('edit_date'))
|
||||
data['edit_date'] = from_timestamp(data.get('edit_date'))
|
||||
data['audio'] = Audio.de_json(data.get('audio'), bot)
|
||||
data['document'] = Document.de_json(data.get('document'), bot)
|
||||
data['game'] = Game.de_json(data.get('game'), bot)
|
||||
|
@ -259,12 +257,12 @@ class Message(TelegramObject):
|
|||
|
||||
# Required
|
||||
data['from'] = data.pop('from_user', None)
|
||||
data['date'] = self._totimestamp(self.date)
|
||||
data['date'] = to_timestamp(self.date)
|
||||
# Optionals
|
||||
if self.forward_date:
|
||||
data['forward_date'] = self._totimestamp(self.forward_date)
|
||||
data['forward_date'] = to_timestamp(self.forward_date)
|
||||
if self.edit_date:
|
||||
data['edit_date'] = self._totimestamp(self.edit_date)
|
||||
data['edit_date'] = to_timestamp(self.edit_date)
|
||||
if self.photo:
|
||||
data['photo'] = [p.to_dict() for p in self.photo]
|
||||
if self.entities:
|
||||
|
@ -277,39 +275,6 @@ class Message(TelegramObject):
|
|||
|
||||
return data
|
||||
|
||||
@staticmethod
|
||||
def _fromtimestamp(unixtime):
|
||||
"""
|
||||
Args:
|
||||
unixtime (int):
|
||||
|
||||
Returns:
|
||||
datetime.datetime:
|
||||
"""
|
||||
if not unixtime:
|
||||
return None
|
||||
|
||||
return datetime.fromtimestamp(unixtime)
|
||||
|
||||
@staticmethod
|
||||
def _totimestamp(dt_obj):
|
||||
"""
|
||||
Args:
|
||||
dt_obj (:class:`datetime.datetime`):
|
||||
|
||||
Returns:
|
||||
int:
|
||||
"""
|
||||
if not dt_obj:
|
||||
return None
|
||||
|
||||
try:
|
||||
# Python 3.3+
|
||||
return int(dt_obj.timestamp())
|
||||
except AttributeError:
|
||||
# Python 3 (< 3.3) and Python 2
|
||||
return int(mktime(dt_obj.timetuple()))
|
||||
|
||||
def _quote(self, kwargs):
|
||||
"""Modify kwargs for replying with or without quoting"""
|
||||
|
||||
|
|
|
@ -19,14 +19,56 @@
|
|||
""" This module contains helper functions """
|
||||
|
||||
import re
|
||||
from datetime import datetime
|
||||
|
||||
try:
|
||||
from html import escape as escape_html # noqa: F401
|
||||
except ImportError:
|
||||
from cgi import escape as escape_html # noqa: F401
|
||||
|
||||
# Not using future.backports.datetime here as datetime value might be an input from the user,
|
||||
# making every isinstace() call more delicate. So we just use our own compat layer.
|
||||
if hasattr(datetime, 'timestamp'):
|
||||
# Python 3.3+
|
||||
def _timestamp(dt_obj):
|
||||
return dt_obj.timestamp()
|
||||
else:
|
||||
# Python < 3.3 (incl 2.7)
|
||||
from time import mktime
|
||||
|
||||
def _timestamp(dt_obj):
|
||||
return mktime(dt_obj.timetuple())
|
||||
|
||||
|
||||
def escape_markdown(text):
|
||||
"""Helper function to escape telegram markup symbols"""
|
||||
escape_chars = '\*_`\['
|
||||
return re.sub(r'([%s])' % escape_chars, r'\\\1', text)
|
||||
|
||||
|
||||
def to_timestamp(dt_obj):
|
||||
"""
|
||||
Args:
|
||||
dt_obj (:class:`datetime.datetime`):
|
||||
|
||||
Returns:
|
||||
int:
|
||||
"""
|
||||
if not dt_obj:
|
||||
return None
|
||||
|
||||
return int(_timestamp(dt_obj))
|
||||
|
||||
|
||||
def from_timestamp(unixtime):
|
||||
"""
|
||||
Args:
|
||||
unixtime (int):
|
||||
|
||||
Returns:
|
||||
datetime.datetime:
|
||||
"""
|
||||
if not unixtime:
|
||||
return None
|
||||
|
||||
return datetime.fromtimestamp(unixtime)
|
||||
|
|
|
@ -39,6 +39,11 @@ BASE_TIME = time.time()
|
|||
HIGHSCORE_DELTA = 1450000000
|
||||
|
||||
|
||||
def _stall_retry(*_args, **_kwargs):
|
||||
time.sleep(3)
|
||||
return True
|
||||
|
||||
|
||||
class BotTest(BaseTest, unittest.TestCase):
|
||||
"""This object represents Tests for Telegram Bot."""
|
||||
|
||||
|
@ -246,7 +251,7 @@ class BotTest(BaseTest, unittest.TestCase):
|
|||
self.assertEqual(text, fwdmsg.text)
|
||||
self.assertEqual(fwdmsg.forward_from_message_id, msg.message_id)
|
||||
|
||||
@flaky(20, 1)
|
||||
@flaky(20, 1, _stall_retry)
|
||||
@timeout(10)
|
||||
def test_set_webhook_get_webhook_info(self):
|
||||
url = 'https://python-telegram-bot.org/test/webhook'
|
||||
|
@ -259,7 +264,7 @@ class BotTest(BaseTest, unittest.TestCase):
|
|||
self.assertEqual(max_connections, info.max_connections)
|
||||
self.assertListEqual(allowed_updates, info.allowed_updates)
|
||||
|
||||
@flaky(3, 1)
|
||||
@flaky(20, 1, _stall_retry)
|
||||
@timeout(10)
|
||||
def test_delete_webhook(self):
|
||||
url = 'https://python-telegram-bot.org/test/webhook'
|
||||
|
|
Loading…
Add table
Reference in a new issue