Add default values (#1490)

* added parse_mode parameter in Updater and in Bot class to set a default parse mode for bot

* DefaultValue

* Add default parse_mode everywhere

* Renome to default_parse_mode

* Test def parse_mode for send_*, edit_message_*

* Remove duplicate code in Input* classes

* Improve handling of def_p_m for Bot methods

* Remove unneeded deletion of kwargs

* Make @log preserve signature, add bots with defaults to tests

* Fix Codacy

* Fix Travis Error

* Add default_disable_notification

* Add default_disable_web_page_preview

* Add default_disable_timeout

* add default_disable_web_page_preview for InputTextMessageContent

* add default_quote

* Try fixing test_pin_and_unpin

* Just run 3.5 tests for paranoia

* add tests for Defaults

* Revert "Just run 3.5 tests for paranoia"

This reverts commit 1baa91a3a1.

* Tidy up parameters, move Defaults to ext

* Stage new files, because im an idiot

* remove debug prints

* change equality checks for DEFAULT_NONE

* Some last changes

* fix S&R error so that tests actually run

Co-authored-by: Ak4zh <agwl.akash@gmail.com>
Co-authored-by: Eldinnie <Eldinnie@users.noreply.github.com>
This commit is contained in:
Bibo-Joshi 2020-02-06 11:22:56 +01:00 committed by GitHub
parent bacabbe767
commit 960c7a0c70
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
51 changed files with 1015 additions and 195 deletions

View file

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

View file

@ -12,6 +12,7 @@ telegram.ext package
telegram.ext.messagequeue telegram.ext.messagequeue
telegram.ext.delayqueue telegram.ext.delayqueue
telegram.ext.callbackcontext telegram.ext.callbackcontext
telegram.ext.defaults
Handlers Handlers
-------- --------

View file

@ -2,3 +2,4 @@ future>=0.16.0
certifi certifi
tornado>=5.1 tornado>=5.1
cryptography cryptography
decorator>=4.4.0

View file

@ -21,6 +21,8 @@
"""This module contains an object that represents a Telegram Bot.""" """This module contains an object that represents a Telegram Bot."""
import functools import functools
import inspect
from decorator import decorate
try: try:
import ujson as json import ujson as json
@ -39,7 +41,7 @@ from telegram import (User, Message, Update, Chat, ChatMember, UserProfilePhotos
PhotoSize, Audio, Document, Sticker, Video, Animation, Voice, VideoNote, PhotoSize, Audio, Document, Sticker, Video, Animation, Voice, VideoNote,
Location, Venue, Contact, InputFile, Poll) Location, Venue, Contact, InputFile, Poll)
from telegram.error import InvalidToken, TelegramError from telegram.error import InvalidToken, TelegramError
from telegram.utils.helpers import to_timestamp from telegram.utils.helpers import to_timestamp, DEFAULT_NONE
from telegram.utils.request import Request from telegram.utils.request import Request
logging.getLogger(__name__).addHandler(logging.NullHandler()) logging.getLogger(__name__).addHandler(logging.NullHandler())
@ -57,18 +59,17 @@ def info(func):
return decorator return decorator
def log(func): def log(func, *args, **kwargs):
logger = logging.getLogger(func.__module__) logger = logging.getLogger(func.__module__)
@functools.wraps(func)
def decorator(self, *args, **kwargs): def decorator(self, *args, **kwargs):
logger.debug('Entering: %s', func.__name__) logger.debug('Entering: %s', func.__name__)
result = func(self, *args, **kwargs) result = func(*args, **kwargs)
logger.debug(result) logger.debug(result)
logger.debug('Exiting: %s', func.__name__) logger.debug('Exiting: %s', func.__name__)
return result return result
return decorator return decorate(func, decorator)
class Bot(TelegramObject): class Bot(TelegramObject):
@ -82,13 +83,55 @@ class Bot(TelegramObject):
:obj:`telegram.utils.request.Request`. :obj:`telegram.utils.request.Request`.
private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data.
private_key_password (:obj:`bytes`, optional): Password for above private key. private_key_password (:obj:`bytes`, optional): Password for above private key.
defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to
be used if not set explicitly in the bot methods.
""" """
def __init__(self, token, base_url=None, base_file_url=None, request=None, private_key=None, def __new__(cls, *args, **kwargs):
private_key_password=None): # Get default values from kwargs
defaults = kwargs.get('defaults')
# Make an instance of the class
instance = super(Bot, cls).__new__(cls)
if not defaults:
return instance
# For each method ...
for method_name, method in inspect.getmembers(instance, predicate=inspect.ismethod):
# ... get kwargs
argspec = inspect.getargspec(method)
kwarg_names = argspec.args[-len(argspec.defaults or []):]
# ... check if Defaults has a attribute that matches the kwarg name
needs_default = [
kwarg_name for kwarg_name in kwarg_names if hasattr(defaults, kwarg_name)
]
# ... make a dict of kwarg name and the default value
default_kwargs = {
kwarg_name: getattr(defaults, kwarg_name) for kwarg_name in needs_default if (
getattr(defaults, kwarg_name) is not DEFAULT_NONE
)
}
# ... apply the defaults using a partial
if default_kwargs:
setattr(instance, method_name, functools.partial(method, **default_kwargs))
return instance
def __init__(self,
token,
base_url=None,
base_file_url=None,
request=None,
private_key=None,
private_key_password=None,
defaults=None):
self.token = self._validate_token(token) self.token = self._validate_token(token)
# Gather default
self.defaults = defaults
if base_url is None: if base_url is None:
base_url = 'https://api.telegram.org/bot' base_url = 'https://api.telegram.org/bot'
@ -120,11 +163,20 @@ class Bot(TelegramObject):
else: else:
data['reply_markup'] = reply_markup data['reply_markup'] = reply_markup
if data.get('media') and (data['media'].parse_mode == DEFAULT_NONE):
if self.defaults:
data['media'].parse_mode = self.defaults.parse_mode
else:
data['media'].parse_mode = None
result = self._request.post(url, data, timeout=timeout) result = self._request.post(url, data, timeout=timeout)
if result is True: if result is True:
return result return result
if self.defaults:
result['default_quote'] = self.defaults.quote
return Message.de_json(result, self) return Message.de_json(result, self)
@property @property
@ -978,6 +1030,13 @@ class Bot(TelegramObject):
data = {'chat_id': chat_id, 'media': media} data = {'chat_id': chat_id, 'media': media}
for m in data['media']:
if m.parse_mode == DEFAULT_NONE:
if self.defaults:
m.parse_mode = self.defaults.parse_mode
else:
m.parse_mode = None
if reply_to_message_id: if reply_to_message_id:
data['reply_to_message_id'] = reply_to_message_id data['reply_to_message_id'] = reply_to_message_id
if disable_notification: if disable_notification:
@ -985,6 +1044,10 @@ class Bot(TelegramObject):
result = self._request.post(url, data, timeout=timeout) result = self._request.post(url, data, timeout=timeout)
if self.defaults:
for res in result:
res['default_quote'] = self.defaults.quote
return [Message.de_json(res, self) for res in result] return [Message.de_json(res, self) for res in result]
@log @log
@ -1447,6 +1510,24 @@ class Bot(TelegramObject):
""" """
url = '{0}/answerInlineQuery'.format(self.base_url) url = '{0}/answerInlineQuery'.format(self.base_url)
for res in results:
if res._has_parse_mode and res.parse_mode == DEFAULT_NONE:
res.parse_mode = self.defaults.parse_mode
if res._has_input_message_content and res.input_message_content:
if (res.input_message_content._has_parse_mode
and res.input_message_content.parse_mode == DEFAULT_NONE):
if self.defaults:
res.input_message_content.parse_mode = self.defaults.parse_mode
else:
res.input_message_content.parse_mode = None
if (res.input_message_content._has_disable_web_page_preview
and res.input_message_content.disable_web_page_preview == DEFAULT_NONE):
if self.defaults:
res.input_message_content.disable_web_page_preview = \
self.defaults.disable_web_page_preview
else:
res.input_message_content.disable_web_page_preview = None
results = [res.to_dict() for res in results] results = [res.to_dict() for res in results]
data = {'inline_query_id': inline_query_id, 'results': results} data = {'inline_query_id': inline_query_id, 'results': results}
@ -1987,6 +2068,10 @@ class Bot(TelegramObject):
else: else:
self.logger.debug('No new updates found.') self.logger.debug('No new updates found.')
if self.defaults:
for u in result:
u['default_quote'] = self.defaults.quote
return [Update.de_json(u, self) for u in result] return [Update.de_json(u, self) for u in result]
@log @log
@ -2167,6 +2252,9 @@ class Bot(TelegramObject):
result = self._request.post(url, data, timeout=timeout) result = self._request.post(url, data, timeout=timeout)
if self.defaults:
result['default_quote'] = self.defaults.quote
return Chat.de_json(result, self) return Chat.de_json(result, self)
@log @log

View file

@ -101,7 +101,10 @@ class CallbackQuery(TelegramObject):
data = super(CallbackQuery, cls).de_json(data, bot) data = super(CallbackQuery, cls).de_json(data, bot)
data['from_user'] = User.de_json(data.get('from'), bot) data['from_user'] = User.de_json(data.get('from'), bot)
data['message'] = Message.de_json(data.get('message'), bot) message = data.get('message')
if message:
message['default_quote'] = data.get('default_quote')
data['message'] = Message.de_json(message, bot)
return cls(bot=bot, **data) return cls(bot=bot, **data)

View file

@ -135,7 +135,10 @@ class Chat(TelegramObject):
data['photo'] = ChatPhoto.de_json(data.get('photo'), bot) data['photo'] = ChatPhoto.de_json(data.get('photo'), bot)
from telegram import Message from telegram import Message
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) pinned_message = data.get('pinned_message')
if pinned_message:
pinned_message['default_quote'] = data.get('default_quote')
data['pinned_message'] = Message.de_json(pinned_message, bot)
data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot) data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot)
return cls(bot=bot, **data) return cls(bot=bot, **data)

View file

@ -41,6 +41,7 @@ from .precheckoutqueryhandler import PreCheckoutQueryHandler
from .shippingqueryhandler import ShippingQueryHandler from .shippingqueryhandler import ShippingQueryHandler
from .messagequeue import MessageQueue from .messagequeue import MessageQueue
from .messagequeue import DelayQueue from .messagequeue import DelayQueue
from .defaults import Defaults
__all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler', __all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler', 'ChosenInlineResultHandler', 'CommandHandler', 'Handler', 'InlineQueryHandler',
@ -48,4 +49,4 @@ __all__ = ('Dispatcher', 'JobQueue', 'Job', 'Updater', 'CallbackQueryHandler',
'StringRegexHandler', 'TypeHandler', 'ConversationHandler', 'StringRegexHandler', 'TypeHandler', 'ConversationHandler',
'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue', 'PreCheckoutQueryHandler', 'ShippingQueryHandler', 'MessageQueue', 'DelayQueue',
'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'BasePersistence', 'DispatcherHandlerStop', 'run_async', 'CallbackContext', 'BasePersistence',
'PicklePersistence', 'DictPersistence', 'PrefixHandler') 'PicklePersistence', 'DictPersistence', 'PrefixHandler', 'Defaults')

127
telegram/ext/defaults.py Normal file
View file

@ -0,0 +1,127 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2020
# 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 the class Defaults, which allows to pass default values to Updater."""
from telegram.utils.helpers import DEFAULT_NONE
class Defaults:
"""Convenience Class to gather all parameters with a (user defined) default value
Attributes:
parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width toxt or URLs in your bot's message.
disable_notification (:obj:`bool`): Optional. Sends the message silently. Users will
receive a notification with no sound.
disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in this
message.
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).
quote (:obj:`bool`): Optional. If set to ``True``, the reply is sent as an actual reply to
the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will
be ignored. Default: ``True`` in group chats and ``False`` in private chats.
Parameters:
parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show
bold, italic, fixed-width toxt or URLs in your bot's message.
disable_notification (:obj:`bool`, optional): Sends the message silently. Users will
receive a notification with no sound.
disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this
message.
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).
quote (:obj:`bool`, opitonal): If set to ``True``, the reply is sent as an actual reply to
the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will
be ignored. Default: ``True`` in group chats and ``False`` in private chats.
"""
def __init__(self,
parse_mode=None,
disable_notification=None,
disable_web_page_preview=None,
# Timeout needs special treatment, since the bot methods have two different
# default values for timeout (None and 20s)
timeout=DEFAULT_NONE,
quote=None):
self._parse_mode = parse_mode
self._disable_notification = disable_notification
self._disable_web_page_preview = disable_web_page_preview
self._timeout = timeout
self._quote = quote
@property
def parse_mode(self):
return self._parse_mode
@parse_mode.setter
def parse_mode(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def disable_notification(self):
return self._disable_notification
@disable_notification.setter
def disable_notification(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def disable_web_page_preview(self):
return self._disable_web_page_preview
@disable_web_page_preview.setter
def disable_web_page_preview(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def timeout(self):
return self._timeout
@timeout.setter
def timeout(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
@property
def quote(self):
return self._quote
@quote.setter
def quote(self, value):
raise AttributeError("You can not assign a new value to defaults after because it would "
"not have any effect.")
def __hash__(self):
return hash((self._parse_mode,
self._disable_notification,
self._disable_web_page_preview,
self._timeout,
self._quote))
def __eq__(self, other):
if isinstance(other, Defaults):
return self.__dict__ == other.__dict__
return False
def __ne__(self, other):
return not self == other

View file

@ -87,6 +87,8 @@ class Updater(object):
persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to
store data that should be persistent over restarts (ignored if `dispatcher` argument is store data that should be persistent over restarts (ignored if `dispatcher` argument is
used). used).
defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to
be used if not set explicitly in the bot methods.
Note: Note:
You must supply either a :attr:`bot` or a :attr:`token` argument. You must supply either a :attr:`bot` or a :attr:`token` argument.
@ -108,6 +110,7 @@ class Updater(object):
user_sig_handler=None, user_sig_handler=None,
request_kwargs=None, request_kwargs=None,
persistence=None, persistence=None,
defaults=None,
use_context=False, use_context=False,
dispatcher=None, dispatcher=None,
base_file_url=None): base_file_url=None):
@ -157,7 +160,8 @@ class Updater(object):
base_file_url=base_file_url, base_file_url=base_file_url,
request=self._request, request=self._request,
private_key=private_key, private_key=private_key,
private_key_password=private_key_password) private_key_password=private_key_password,
defaults=defaults)
self.update_queue = Queue() self.update_queue = Queue()
self.job_queue = JobQueue() self.job_queue = JobQueue()
self.__exception_event = Event() self.__exception_event = Event()
@ -192,6 +196,9 @@ class Updater(object):
self.__lock = Lock() self.__lock = Lock()
self.__threads = [] self.__threads = []
# Just for passing to WebhookAppClass
self._default_quote = defaults.quote if defaults else None
def _init_thread(self, target, name, *args, **kwargs): def _init_thread(self, target, name, *args, **kwargs):
thr = Thread(target=self._thread_wrapper, thr = Thread(target=self._thread_wrapper,
name="Bot:{}:{}".format(self.bot.id, name), name="Bot:{}:{}".format(self.bot.id, name),
@ -409,7 +416,8 @@ class Updater(object):
url_path = '/{0}'.format(url_path) url_path = '/{0}'.format(url_path)
# Create Tornado app instance # Create Tornado app instance
app = WebhookAppClass(url_path, self.bot, self.update_queue) app = WebhookAppClass(url_path, self.bot, self.update_queue,
default_quote=self._default_quote)
# Form SSL Context # Form SSL Context
# An SSLError is raised if the private key does not match with the certificate # An SSLError is raised if the private key does not match with the certificate

View file

@ -19,6 +19,7 @@
"""Base class for Telegram InputMedia Objects.""" """Base class for Telegram InputMedia Objects."""
from telegram import TelegramObject, InputFile, PhotoSize, Animation, Video, Audio, Document from telegram import TelegramObject, InputFile, PhotoSize, Animation, Video, Audio, Document
from telegram.utils.helpers import DEFAULT_NONE
class InputMedia(TelegramObject): class InputMedia(TelegramObject):
@ -77,7 +78,13 @@ class InputMediaAnimation(InputMedia):
arguments. arguments.
""" """
def __init__(self, media, thumb=None, caption=None, parse_mode=None, width=None, height=None, def __init__(self,
media,
thumb=None,
caption=None,
parse_mode=DEFAULT_NONE,
width=None,
height=None,
duration=None): duration=None):
self.type = 'animation' self.type = 'animation'
@ -98,8 +105,7 @@ class InputMediaAnimation(InputMedia):
if caption: if caption:
self.caption = caption self.caption = caption
if parse_mode: self.parse_mode = parse_mode
self.parse_mode = parse_mode
if width: if width:
self.width = width self.width = width
if height: if height:
@ -133,7 +139,7 @@ class InputMediaPhoto(InputMedia):
in :class:`telegram.ParseMode` for the available modes. in :class:`telegram.ParseMode` for the available modes.
""" """
def __init__(self, media, caption=None, parse_mode=None): def __init__(self, media, caption=None, parse_mode=DEFAULT_NONE):
self.type = 'photo' self.type = 'photo'
if isinstance(media, PhotoSize): if isinstance(media, PhotoSize):
@ -145,8 +151,7 @@ class InputMediaPhoto(InputMedia):
if caption: if caption:
self.caption = caption self.caption = caption
if parse_mode: self.parse_mode = parse_mode
self.parse_mode = parse_mode
class InputMediaVideo(InputMedia): class InputMediaVideo(InputMedia):
@ -198,7 +203,7 @@ class InputMediaVideo(InputMedia):
""" """
def __init__(self, media, caption=None, width=None, height=None, duration=None, def __init__(self, media, caption=None, width=None, height=None, duration=None,
supports_streaming=None, parse_mode=None, thumb=None): supports_streaming=None, parse_mode=DEFAULT_NONE, thumb=None):
self.type = 'video' self.type = 'video'
if isinstance(media, Video): if isinstance(media, Video):
@ -218,8 +223,7 @@ class InputMediaVideo(InputMedia):
if caption: if caption:
self.caption = caption self.caption = caption
if parse_mode: self.parse_mode = parse_mode
self.parse_mode = parse_mode
if width: if width:
self.width = width self.width = width
if height: if height:
@ -276,7 +280,7 @@ class InputMediaAudio(InputMedia):
optional arguments. optional arguments.
""" """
def __init__(self, media, thumb=None, caption=None, parse_mode=None, def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE,
duration=None, performer=None, title=None): duration=None, performer=None, title=None):
self.type = 'audio' self.type = 'audio'
@ -297,8 +301,7 @@ class InputMediaAudio(InputMedia):
if caption: if caption:
self.caption = caption self.caption = caption
if parse_mode: self.parse_mode = parse_mode
self.parse_mode = parse_mode
if duration: if duration:
self.duration = duration self.duration = duration
if performer: if performer:
@ -340,7 +343,7 @@ class InputMediaDocument(InputMedia):
is passed as a string or file_id. is passed as a string or file_id.
""" """
def __init__(self, media, thumb=None, caption=None, parse_mode=None): def __init__(self, media, thumb=None, caption=None, parse_mode=DEFAULT_NONE):
self.type = 'document' self.type = 'document'
if isinstance(media, Document): if isinstance(media, Document):
@ -357,5 +360,4 @@ class InputMediaDocument(InputMedia):
if caption: if caption:
self.caption = caption self.caption = caption
if parse_mode: self.parse_mode = parse_mode
self.parse_mode = parse_mode

View file

@ -41,3 +41,11 @@ class InlineQueryResult(TelegramObject):
self.id = str(id) self.id = str(id)
self._id_attrs = (self.id,) self._id_attrs = (self.id,)
@property
def _has_parse_mode(self):
return hasattr(self, 'parse_mode')
@property
def _has_input_message_content(self):
return hasattr(self, 'input_message_content')

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultAudio.""" """This module contains the classes that represent Telegram InlineQueryResultAudio."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultAudio(InlineQueryResult): class InlineQueryResultAudio(InlineQueryResult):
@ -70,7 +71,7 @@ class InlineQueryResultAudio(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio.""" """This module contains the classes that represent Telegram InlineQueryResultCachedAudio."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedAudio(InlineQueryResult): class InlineQueryResultCachedAudio(InlineQueryResult):
@ -61,7 +62,7 @@ class InlineQueryResultCachedAudio(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedAudio, self).__init__('audio', id) super(InlineQueryResultCachedAudio, self).__init__('audio', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument.""" """This module contains the classes that represent Telegram InlineQueryResultCachedDocument."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedDocument(InlineQueryResult): class InlineQueryResultCachedDocument(InlineQueryResult):
@ -67,7 +68,7 @@ class InlineQueryResultCachedDocument(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedDocument, self).__init__('document', id) super(InlineQueryResultCachedDocument, self).__init__('document', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedGif.""" """This module contains the classes that represent Telegram InlineQueryResultCachedGif."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedGif(InlineQueryResult): class InlineQueryResultCachedGif(InlineQueryResult):
@ -65,7 +66,7 @@ class InlineQueryResultCachedGif(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedGif, self).__init__('gif', id) super(InlineQueryResultCachedGif, self).__init__('gif', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" """This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
@ -65,7 +66,7 @@ class InlineQueryResultCachedMpeg4Gif(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedMpeg4Gif, self).__init__('mpeg4_gif', id) super(InlineQueryResultCachedMpeg4Gif, self).__init__('mpeg4_gif', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultPhoto""" """This module contains the classes that represent Telegram InlineQueryResultPhoto"""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedPhoto(InlineQueryResult): class InlineQueryResultCachedPhoto(InlineQueryResult):
@ -68,7 +69,7 @@ class InlineQueryResultCachedPhoto(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedPhoto, self).__init__('photo', id) super(InlineQueryResultCachedPhoto, self).__init__('photo', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo.""" """This module contains the classes that represent Telegram InlineQueryResultCachedVideo."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedVideo(InlineQueryResult): class InlineQueryResultCachedVideo(InlineQueryResult):
@ -68,7 +69,7 @@ class InlineQueryResultCachedVideo(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedVideo, self).__init__('video', id) super(InlineQueryResultCachedVideo, self).__init__('video', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice.""" """This module contains the classes that represent Telegram InlineQueryResultCachedVoice."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultCachedVoice(InlineQueryResult): class InlineQueryResultCachedVoice(InlineQueryResult):
@ -64,7 +65,7 @@ class InlineQueryResultCachedVoice(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultCachedVoice, self).__init__('voice', id) super(InlineQueryResultCachedVoice, self).__init__('voice', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultDocument""" """This module contains the classes that represent Telegram InlineQueryResultDocument"""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultDocument(InlineQueryResult): class InlineQueryResultDocument(InlineQueryResult):
@ -82,7 +83,7 @@ class InlineQueryResultDocument(InlineQueryResult):
thumb_url=None, thumb_url=None,
thumb_width=None, thumb_width=None,
thumb_height=None, thumb_height=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultDocument, self).__init__('document', id) super(InlineQueryResultDocument, self).__init__('document', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultGif.""" """This module contains the classes that represent Telegram InlineQueryResultGif."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultGif(InlineQueryResult): class InlineQueryResultGif(InlineQueryResult):
@ -76,7 +77,7 @@ class InlineQueryResultGif(InlineQueryResult):
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
gif_duration=None, gif_duration=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" """This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultMpeg4Gif(InlineQueryResult): class InlineQueryResultMpeg4Gif(InlineQueryResult):
@ -77,7 +78,7 @@ class InlineQueryResultMpeg4Gif(InlineQueryResult):
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
mpeg4_duration=None, mpeg4_duration=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultPhoto.""" """This module contains the classes that represent Telegram InlineQueryResultPhoto."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultPhoto(InlineQueryResult): class InlineQueryResultPhoto(InlineQueryResult):
@ -78,7 +79,7 @@ class InlineQueryResultPhoto(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required
super(InlineQueryResultPhoto, self).__init__('photo', id) super(InlineQueryResultPhoto, self).__init__('photo', id)

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultVideo.""" """This module contains the classes that represent Telegram InlineQueryResultVideo."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultVideo(InlineQueryResult): class InlineQueryResultVideo(InlineQueryResult):
@ -83,7 +84,7 @@ class InlineQueryResultVideo(InlineQueryResult):
description=None, description=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InlineQueryResultVoice.""" """This module contains the classes that represent Telegram InlineQueryResultVoice."""
from telegram import InlineQueryResult from telegram import InlineQueryResult
from telegram.utils.helpers import DEFAULT_NONE
class InlineQueryResultVoice(InlineQueryResult): class InlineQueryResultVoice(InlineQueryResult):
@ -68,7 +69,7 @@ class InlineQueryResultVoice(InlineQueryResult):
caption=None, caption=None,
reply_markup=None, reply_markup=None,
input_message_content=None, input_message_content=None,
parse_mode=None, parse_mode=DEFAULT_NONE,
**kwargs): **kwargs):
# Required # Required

View file

@ -29,4 +29,10 @@ class InputMessageContent(TelegramObject):
:class:`telegram.InputVenueMessageContent` for more details. :class:`telegram.InputVenueMessageContent` for more details.
""" """
pass @property
def _has_parse_mode(self):
return hasattr(self, 'parse_mode')
@property
def _has_disable_web_page_preview(self):
return hasattr(self, 'disable_web_page_preview')

View file

@ -19,6 +19,7 @@
"""This module contains the classes that represent Telegram InputTextMessageContent.""" """This module contains the classes that represent Telegram InputTextMessageContent."""
from telegram import InputMessageContent from telegram import InputMessageContent
from telegram.utils.helpers import DEFAULT_NONE
class InputTextMessageContent(InputMessageContent): class InputTextMessageContent(InputMessageContent):
@ -43,7 +44,11 @@ class InputTextMessageContent(InputMessageContent):
""" """
def __init__(self, message_text, parse_mode=None, disable_web_page_preview=None, **kwargs): def __init__(self,
message_text,
parse_mode=DEFAULT_NONE,
disable_web_page_preview=DEFAULT_NONE,
**kwargs):
# Required # Required
self.message_text = message_text self.message_text = message_text
# Optionals # Optionals

View file

@ -109,6 +109,8 @@ class Message(TelegramObject):
reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached
to the message. to the message.
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
default_quote (:obj:`bool`): Optional. Default setting for the `quote` parameter of the
:attr:`reply_text` and friends.
Args: Args:
message_id (:obj:`int`): Unique message identifier inside this chat. message_id (:obj:`int`): Unique message identifier inside this chat.
@ -214,6 +216,8 @@ class Message(TelegramObject):
information about the poll. information about the poll.
reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached
to the message. login_url buttons are represented as ordinary url buttons. to the message. login_url buttons are represented as ordinary url buttons.
default_quote (:obj:`bool`, optional): Default setting for the `quote` parameter of the
:attr:`reply_text` and friends.
""" """
@ -277,6 +281,7 @@ class Message(TelegramObject):
forward_sender_name=None, forward_sender_name=None,
reply_markup=None, reply_markup=None,
bot=None, bot=None,
default_quote=None,
**kwargs): **kwargs):
# Required # Required
self.message_id = int(message_id) self.message_id = int(message_id)
@ -328,6 +333,7 @@ class Message(TelegramObject):
self.poll = poll self.poll = poll
self.reply_markup = reply_markup self.reply_markup = reply_markup
self.bot = bot self.bot = bot
self.default_quote = default_quote
self._id_attrs = (self.message_id,) self._id_attrs = (self.message_id,)
@ -358,13 +364,22 @@ class Message(TelegramObject):
data['from_user'] = User.de_json(data.get('from'), bot) data['from_user'] = User.de_json(data.get('from'), bot)
data['date'] = from_timestamp(data['date']) data['date'] = from_timestamp(data['date'])
data['chat'] = Chat.de_json(data.get('chat'), bot) chat = data.get('chat')
if chat:
chat['default_quote'] = data.get('default_quote')
data['chat'] = Chat.de_json(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['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) forward_from_chat = data.get('forward_from_chat')
if forward_from_chat:
forward_from_chat['default_quote'] = data.get('default_quote')
data['forward_from_chat'] = Chat.de_json(forward_from_chat, bot)
data['forward_date'] = from_timestamp(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) reply_to_message = data.get('reply_to_message')
if reply_to_message:
reply_to_message['default_quote'] = data.get('default_quote')
data['reply_to_message'] = Message.de_json(reply_to_message, bot)
data['edit_date'] = from_timestamp(data.get('edit_date')) data['edit_date'] = from_timestamp(data.get('edit_date'))
data['audio'] = Audio.de_json(data.get('audio'), bot) data['audio'] = Audio.de_json(data.get('audio'), bot)
data['document'] = Document.de_json(data.get('document'), bot) data['document'] = Document.de_json(data.get('document'), bot)
@ -381,7 +396,10 @@ class Message(TelegramObject):
data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot) data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot)
data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot) data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot)
data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot) data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot)
data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) pinned_message = data.get('pinned_message')
if pinned_message:
pinned_message['default_quote'] = data.get('default_quote')
data['pinned_message'] = Message.de_json(pinned_message, bot)
data['invoice'] = Invoice.de_json(data.get('invoice'), bot) data['invoice'] = Invoice.de_json(data.get('invoice'), bot)
data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot) data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot)
data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot) data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot)
@ -464,7 +482,8 @@ class Message(TelegramObject):
del kwargs['quote'] del kwargs['quote']
else: else:
if self.chat.type != Chat.PRIVATE: if ((self.default_quote is None and self.chat.type != Chat.PRIVATE)
or self.default_quote):
kwargs['reply_to_message_id'] = self.message_id kwargs['reply_to_message_id'] = self.message_id
def reply_text(self, *args, **kwargs): def reply_text(self, *args, **kwargs):

View file

@ -211,16 +211,31 @@ class Update(TelegramObject):
data = super(Update, cls).de_json(data, bot) data = super(Update, cls).de_json(data, bot)
data['message'] = Message.de_json(data.get('message'), bot) message = data.get('message')
data['edited_message'] = Message.de_json(data.get('edited_message'), bot) if message:
message['default_quote'] = data.get('default_quote')
data['message'] = Message.de_json(message, bot)
edited_message = data.get('edited_message')
if edited_message:
edited_message['default_quote'] = data.get('default_quote')
data['edited_message'] = Message.de_json(edited_message, bot)
data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot) data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot)
data['chosen_inline_result'] = ChosenInlineResult.de_json( data['chosen_inline_result'] = ChosenInlineResult.de_json(
data.get('chosen_inline_result'), bot) data.get('chosen_inline_result'), bot)
data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot) callback_query = data.get('callback_query')
if callback_query:
callback_query['default_quote'] = data.get('default_quote')
data['callback_query'] = CallbackQuery.de_json(callback_query, bot)
data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot) data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot)
data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot) data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot)
data['channel_post'] = Message.de_json(data.get('channel_post'), bot) channel_post = data.get('channel_post')
data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot) if channel_post:
channel_post['default_quote'] = data.get('default_quote')
data['channel_post'] = Message.de_json(channel_post, bot)
edited_channel_post = data.get('edited_channel_post')
if edited_channel_post:
edited_channel_post['default_quote'] = data.get('default_quote')
data['edited_channel_post'] = Message.de_json(edited_channel_post, bot)
data['poll'] = Poll.de_json(data.get('poll'), bot) data['poll'] = Poll.de_json(data.get('poll'), bot)
return cls(**data) return cls(**data)

View file

@ -360,3 +360,57 @@ def decode_user_chat_data_from_json(data):
pass pass
tmp[user][key] = value tmp[user][key] = value
return tmp return tmp
class DefaultValue:
"""Wrapper for immutable default arguments that allows to check, if the default value was set
explicitly. Usage::
DefaultOne = DefaultValue(1)
def f(arg=DefaultOne):
if arg is DefaultOne:
print('`arg` is the default')
arg = arg.value
else:
print('`arg` was set explicitly')
print('`arg` = ' + str(arg))
This yields::
>>> f()
`arg` is the default
`arg` = 1
>>> f(1)
`arg` was set explicitly
`arg` = 1
>>> f(2)
`arg` was set explicitly
`arg` = 2
Also allows to evaluate truthiness::
default = DefaultValue(value)
if default:
...
is equivalent to::
default = DefaultValue(value)
if value:
...
Attributes:
value (:obj:`obj`): The value of the default argument
Args:
value (:obj:`obj`): The value of the default argument
"""
def __init__(self, value=None):
self.value = value
def __bool__(self):
return bool(self.value)
DEFAULT_NONE = DefaultValue(None)
""":class:`DefaultValue`: Default `None`"""

View file

@ -71,8 +71,9 @@ class WebhookServer(object):
class WebhookAppClass(tornado.web.Application): class WebhookAppClass(tornado.web.Application):
def __init__(self, webhook_path, bot, update_queue): def __init__(self, webhook_path, bot, update_queue, default_quote=None):
self.shared_objects = {"bot": bot, "update_queue": update_queue} self.shared_objects = {"bot": bot, "update_queue": update_queue,
"default_quote": default_quote}
handlers = [ handlers = [
(r"{0}/?".format(webhook_path), WebhookHandler, (r"{0}/?".format(webhook_path), WebhookHandler,
self.shared_objects) self.shared_objects)
@ -91,9 +92,10 @@ class WebhookHandler(tornado.web.RequestHandler):
super(WebhookHandler, self).__init__(application, request, **kwargs) super(WebhookHandler, self).__init__(application, request, **kwargs)
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
def initialize(self, bot, update_queue): def initialize(self, bot, update_queue, default_quote=None):
self.bot = bot self.bot = bot
self.update_queue = update_queue self.update_queue = update_queue
self._default_quote = default_quote
def set_default_headers(self): def set_default_headers(self):
self.set_header("Content-Type", 'application/json; charset="utf-8"') self.set_header("Content-Type", 'application/json; charset="utf-8"')
@ -105,6 +107,7 @@ class WebhookHandler(tornado.web.RequestHandler):
data = json.loads(json_string) data = json.loads(json_string)
self.set_status(200) self.set_status(200)
self.logger.debug('Webhook received data: ' + json_string) self.logger.debug('Webhook received data: ' + json_string)
data['default_quote'] = self._default_quote
update = Update.de_json(data, self.bot) update = Update.de_json(data, self.bot)
self.logger.debug('Received Update with ID %d on Webhook' % update.update_id) self.logger.debug('Received Update with ID %d on Webhook' % update.update_id)
self.update_queue.put(update) self.update_queue.put(update)

View file

@ -30,7 +30,7 @@ import pytest
from telegram import (Bot, Message, User, Chat, MessageEntity, Update, from telegram import (Bot, Message, User, Chat, MessageEntity, Update,
InlineQuery, CallbackQuery, ShippingQuery, PreCheckoutQuery, InlineQuery, CallbackQuery, ShippingQuery, PreCheckoutQuery,
ChosenInlineResult) ChosenInlineResult)
from telegram.ext import Dispatcher, JobQueue, Updater, BaseFilter from telegram.ext import Dispatcher, JobQueue, Updater, BaseFilter, Defaults
from telegram.utils.helpers import _UtcOffsetTimezone from telegram.utils.helpers import _UtcOffsetTimezone
from tests.bots import get_bot from tests.bots import get_bot
@ -59,6 +59,21 @@ def bot(bot_info):
return make_bot(bot_info) return make_bot(bot_info)
DEFAULT_BOTS = {}
@pytest.fixture(scope='function')
def default_bot(request, bot_info):
param = request.param if hasattr(request, 'param') else {}
defaults = Defaults(**param)
default_bot = DEFAULT_BOTS.get(defaults)
if default_bot:
return default_bot
else:
default_bot = make_bot(bot_info, **{'defaults': defaults})
DEFAULT_BOTS[defaults] = default_bot
return default_bot
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def chat_id(bot_info): def chat_id(bot_info):
return bot_info['chat_id'] return bot_info['chat_id']
@ -159,8 +174,8 @@ def pytest_configure(config):
# TODO: Write so good code that we don't need to ignore ResourceWarnings anymore # TODO: Write so good code that we don't need to ignore ResourceWarnings anymore
def make_bot(bot_info): def make_bot(bot_info, **kwargs):
return Bot(bot_info['token'], private_key=PRIVATE_KEY) return Bot(bot_info['token'], private_key=PRIVATE_KEY, **kwargs)
CMD_PATTERN = re.compile(r'/[\da-z_]{1,32}(?:@\w{1,32})?') CMD_PATTERN = re.compile(r'/[\da-z_]{1,32}(?:@\w{1,32})?')

View file

@ -22,6 +22,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import PhotoSize, Animation, Voice, TelegramError from telegram import PhotoSize, Animation, Voice, TelegramError
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -107,6 +108,39 @@ class TestAnimation(object):
assert message.animation.mime_type == animation.mime_type assert message.animation.mime_type == animation.mime_type
assert message.animation.file_size == animation.file_size assert message.animation.file_size == animation.file_size
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_animation_default_parse_mode_1(self, default_bot, chat_id, animation_file):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_animation(chat_id, animation_file, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_animation_default_parse_mode_2(self, default_bot, chat_id, animation_file):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_animation(chat_id, animation_file, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_animation_default_parse_mode_3(self, default_bot, chat_id, animation_file):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_animation(chat_id, animation_file, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)
@pytest.mark.skip(reason='Doesnt work without API 4.5') @pytest.mark.skip(reason='Doesnt work without API 4.5')

View file

@ -22,6 +22,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import Audio, TelegramError, Voice from telegram import Audio, TelegramError, Voice
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -133,6 +134,39 @@ class TestAudio(object):
message = bot.send_audio(audio=audio, chat_id=chat_id) message = bot.send_audio(audio=audio, chat_id=chat_id)
assert message assert message
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_audio_default_parse_mode_1(self, default_bot, chat_id, audio_file, thumb_file):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_audio(chat_id, audio_file, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_audio_default_parse_mode_2(self, default_bot, chat_id, audio_file, thumb_file):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_audio(chat_id, audio_file, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_audio_default_parse_mode_3(self, default_bot, chat_id, audio_file, thumb_file):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_audio(chat_id, audio_file, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
def test_de_json(self, bot, audio): def test_de_json(self, bot, audio):
json_dict = {'file_id': 'not a file id', json_dict = {'file_id': 'not a file id',
'duration': self.duration, 'duration': self.duration,

View file

@ -30,7 +30,7 @@ from telegram import (Bot, Update, ChatAction, TelegramError, User, InlineKeyboa
InlineKeyboardButton, InlineQueryResultArticle, InputTextMessageContent, InlineKeyboardButton, InlineQueryResultArticle, InputTextMessageContent,
ShippingOption, LabeledPrice, ChatPermissions, Poll) ShippingOption, LabeledPrice, ChatPermissions, Poll)
from telegram.error import BadRequest, InvalidToken, NetworkError, RetryAfter from telegram.error import BadRequest, InvalidToken, NetworkError, RetryAfter
from telegram.utils.helpers import from_timestamp from telegram.utils.helpers import from_timestamp, escape_markdown
BASE_TIME = time.time() BASE_TIME = time.time()
HIGHSCORE_DELTA = 1450000000 HIGHSCORE_DELTA = 1450000000
@ -309,6 +309,34 @@ class TestBot(object):
assert message.text == 'new_text' assert message.text == 'new_text'
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_edit_message_text_default_parse_mode(self, default_bot, message):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.edit_message_text(text=test_markdown_string, chat_id=message.chat_id,
message_id=message.message_id,
disable_web_page_preview=True)
assert message.text_markdown == test_markdown_string
assert message.text == test_string
message = default_bot.edit_message_text(text=test_markdown_string, chat_id=message.chat_id,
message_id=message.message_id, parse_mode=None,
disable_web_page_preview=True)
assert message.text == test_markdown_string
assert message.text_markdown == escape_markdown(test_markdown_string)
message = default_bot.edit_message_text(text=test_markdown_string, chat_id=message.chat_id,
message_id=message.message_id,
disable_web_page_preview=True)
message = default_bot.edit_message_text(text=test_markdown_string, chat_id=message.chat_id,
message_id=message.message_id, parse_mode='HTML',
disable_web_page_preview=True)
assert message.text == test_markdown_string
assert message.text_markdown == escape_markdown(test_markdown_string)
@pytest.mark.skip(reason='need reference to an inline message') @pytest.mark.skip(reason='need reference to an inline message')
def test_edit_message_text_inline(self): def test_edit_message_text_inline(self):
pass pass
@ -323,6 +351,36 @@ class TestBot(object):
# edit_message_media is tested in test_inputmedia # edit_message_media is tested in test_inputmedia
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_edit_message_caption_default_parse_mode(self, default_bot, media_message):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.edit_message_caption(caption=test_markdown_string,
chat_id=media_message.chat_id,
message_id=media_message.message_id)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
message = default_bot.edit_message_caption(caption=test_markdown_string,
chat_id=media_message.chat_id,
message_id=media_message.message_id,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
message = default_bot.edit_message_caption(caption=test_markdown_string,
chat_id=media_message.chat_id,
message_id=media_message.message_id)
message = default_bot.edit_message_caption(caption=test_markdown_string,
chat_id=media_message.chat_id,
message_id=media_message.message_id,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)
def test_edit_message_caption_with_parse_mode(self, bot, media_message): def test_edit_message_caption_with_parse_mode(self, bot, media_message):
@ -409,6 +467,20 @@ class TestBot(object):
assert chat.title == '>>> telegram.Bot(test)' assert chat.title == '>>> telegram.Bot(test)'
assert chat.id == int(super_group_id) assert chat.id == int(super_group_id)
# TODO: Add bot to group to test there too
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'quote': True}], indirect=True)
def test_get_chat_default_quote(self, default_bot, super_group_id):
message = default_bot.send_message(super_group_id, text="test_get_chat_default_quote")
assert default_bot.pin_chat_message(chat_id=super_group_id, message_id=message.message_id,
disable_notification=True)
chat = default_bot.get_chat(super_group_id)
assert chat.pinned_message.default_quote is True
assert default_bot.unpinChatMessage(super_group_id)
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)
def test_get_chat_administrators(self, bot, channel_id): def test_get_chat_administrators(self, bot, channel_id):
@ -724,3 +796,29 @@ class TestBot(object):
# Test file uploading # Test file uploading
with pytest.raises(OkException): with pytest.raises(OkException):
bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb')) bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb'))
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_message_default_parse_mode(self, default_bot, chat_id):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_message(chat_id, test_markdown_string)
assert message.text_markdown == test_markdown_string
assert message.text == test_string
message = default_bot.send_message(chat_id, test_markdown_string, parse_mode=None)
assert message.text == test_markdown_string
assert message.text_markdown == escape_markdown(test_markdown_string)
message = default_bot.send_message(chat_id, test_markdown_string, parse_mode='HTML')
assert message.text == test_markdown_string
assert message.text_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'quote': True}], indirect=True)
def test_send_message_default_quote(self, default_bot, chat_id):
message = default_bot.send_message(chat_id, 'test')
assert message.default_quote is True

View file

@ -53,13 +53,15 @@ class TestCallbackQuery(object):
'message': self.message.to_dict(), 'message': self.message.to_dict(),
'data': self.data, 'data': self.data,
'inline_message_id': self.inline_message_id, 'inline_message_id': self.inline_message_id,
'game_short_name': self.game_short_name} 'game_short_name': self.game_short_name,
'default_quote': True}
callback_query = CallbackQuery.de_json(json_dict, bot) callback_query = CallbackQuery.de_json(json_dict, bot)
assert callback_query.id == self.id assert callback_query.id == self.id
assert callback_query.from_user == self.from_user assert callback_query.from_user == self.from_user
assert callback_query.chat_instance == self.chat_instance assert callback_query.chat_instance == self.chat_instance
assert callback_query.message == self.message assert callback_query.message == self.message
assert callback_query.message.default_quote is True
assert callback_query.data == self.data assert callback_query.data == self.data
assert callback_query.inline_message_id == self.inline_message_id assert callback_query.inline_message_id == self.inline_message_id
assert callback_query.game_short_name == self.game_short_name assert callback_query.game_short_name == self.game_short_name
@ -80,15 +82,15 @@ class TestCallbackQuery(object):
def test_answer(self, monkeypatch, callback_query): def test_answer(self, monkeypatch, callback_query):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == callback_query.id return args[0] == callback_query.id
monkeypatch.setattr('telegram.Bot.answerCallbackQuery', test) monkeypatch.setattr(callback_query.bot, 'answerCallbackQuery', test)
# TODO: PEP8 # TODO: PEP8
assert callback_query.answer() assert callback_query.answer()
def test_edit_message_text(self, monkeypatch, callback_query): def test_edit_message_text(self, monkeypatch, callback_query):
def test(*args, **kwargs): def test(*args, **kwargs):
text = args[1] == 'test' text = args[0] == 'test'
try: try:
id = kwargs['inline_message_id'] == callback_query.inline_message_id id = kwargs['inline_message_id'] == callback_query.inline_message_id
return id and text return id and text
@ -97,7 +99,7 @@ class TestCallbackQuery(object):
message_id = kwargs['message_id'] == callback_query.message.message_id message_id = kwargs['message_id'] == callback_query.message.message_id
return chat_id and message_id and text return chat_id and message_id and text
monkeypatch.setattr('telegram.Bot.edit_message_text', test) monkeypatch.setattr(callback_query.bot, 'edit_message_text', test)
assert callback_query.edit_message_text(text='test') assert callback_query.edit_message_text(text='test')
assert callback_query.edit_message_text('test') assert callback_query.edit_message_text('test')
@ -112,7 +114,7 @@ class TestCallbackQuery(object):
message = kwargs['message_id'] == callback_query.message.message_id message = kwargs['message_id'] == callback_query.message.message_id
return id and message and caption return id and message and caption
monkeypatch.setattr('telegram.Bot.edit_message_caption', test) monkeypatch.setattr(callback_query.bot, 'edit_message_caption', test)
assert callback_query.edit_message_caption(caption='new caption') assert callback_query.edit_message_caption(caption='new caption')
assert callback_query.edit_message_caption('new caption') assert callback_query.edit_message_caption('new caption')
@ -127,7 +129,7 @@ class TestCallbackQuery(object):
message = kwargs['message_id'] == callback_query.message.message_id message = kwargs['message_id'] == callback_query.message.message_id
return id and message and reply_markup return id and message and reply_markup
monkeypatch.setattr('telegram.Bot.edit_message_reply_markup', test) monkeypatch.setattr(callback_query.bot, 'edit_message_reply_markup', test)
assert callback_query.edit_message_reply_markup(reply_markup=[['1', '2']]) assert callback_query.edit_message_reply_markup(reply_markup=[['1', '2']])
assert callback_query.edit_message_reply_markup([['1', '2']]) assert callback_query.edit_message_reply_markup([['1', '2']])

View file

@ -20,7 +20,7 @@
import pytest import pytest
from telegram import Chat, ChatAction, ChatPermissions from telegram import Chat, ChatAction, ChatPermissions
from telegram import User from telegram import User, Message
@pytest.fixture(scope='class') @pytest.fixture(scope='class')
@ -68,6 +68,22 @@ class TestChat(object):
assert chat.can_set_sticker_set == self.can_set_sticker_set assert chat.can_set_sticker_set == self.can_set_sticker_set
assert chat.permissions == self.permissions assert chat.permissions == self.permissions
def test_de_json_default_quote(self, bot):
json_dict = {
'id': self.id,
'type': self.type,
'pinned_message': Message(
message_id=123,
from_user=None,
date=None,
chat=None
).to_dict(),
'default_quote': True
}
chat = Chat.de_json(json_dict, bot)
assert chat.pinned_message.default_quote is True
def test_to_dict(self, chat): def test_to_dict(self, chat):
chat_dict = chat.to_dict() chat_dict = chat.to_dict()
@ -86,139 +102,139 @@ class TestChat(object):
def test_send_action(self, monkeypatch, chat): def test_send_action(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == chat.id id = args[0] == chat.id
action = kwargs['action'] == ChatAction.TYPING action = kwargs['action'] == ChatAction.TYPING
return id and action return id and action
monkeypatch.setattr('telegram.Bot.send_chat_action', test) monkeypatch.setattr(chat.bot, 'send_chat_action', test)
assert chat.send_action(action=ChatAction.TYPING) assert chat.send_action(action=ChatAction.TYPING)
def test_leave(self, monkeypatch, chat): def test_leave(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id return args[0] == chat.id
monkeypatch.setattr('telegram.Bot.leave_chat', test) monkeypatch.setattr(chat.bot, 'leave_chat', test)
assert chat.leave() assert chat.leave()
def test_get_administrators(self, monkeypatch, chat): def test_get_administrators(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id return args[0] == chat.id
monkeypatch.setattr('telegram.Bot.get_chat_administrators', test) monkeypatch.setattr(chat.bot, 'get_chat_administrators', test)
assert chat.get_administrators() assert chat.get_administrators()
def test_get_members_count(self, monkeypatch, chat): def test_get_members_count(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id return args[0] == chat.id
monkeypatch.setattr('telegram.Bot.get_chat_members_count', test) monkeypatch.setattr(chat.bot, 'get_chat_members_count', test)
assert chat.get_members_count() assert chat.get_members_count()
def test_get_member(self, monkeypatch, chat): def test_get_member(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
chat_id = args[1] == chat.id chat_id = args[0] == chat.id
user_id = args[2] == 42 user_id = args[1] == 42
return chat_id and user_id return chat_id and user_id
monkeypatch.setattr('telegram.Bot.get_chat_member', test) monkeypatch.setattr(chat.bot, 'get_chat_member', test)
assert chat.get_member(42) assert chat.get_member(42)
def test_kick_member(self, monkeypatch, chat): def test_kick_member(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
chat_id = args[1] == chat.id chat_id = args[0] == chat.id
user_id = args[2] == 42 user_id = args[1] == 42
until = kwargs['until_date'] == 43 until = kwargs['until_date'] == 43
return chat_id and user_id and until return chat_id and user_id and until
monkeypatch.setattr('telegram.Bot.kick_chat_member', test) monkeypatch.setattr(chat.bot, 'kick_chat_member', test)
assert chat.kick_member(42, until_date=43) assert chat.kick_member(42, until_date=43)
def test_unban_member(self, monkeypatch, chat): def test_unban_member(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
chat_id = args[1] == chat.id chat_id = args[0] == chat.id
user_id = args[2] == 42 user_id = args[1] == 42
return chat_id and user_id return chat_id and user_id
monkeypatch.setattr('telegram.Bot.unban_chat_member', test) monkeypatch.setattr(chat.bot, 'unban_chat_member', test)
assert chat.unban_member(42) assert chat.unban_member(42)
def test_set_permissions(self, monkeypatch, chat): def test_set_permissions(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
chat_id = args[1] == chat.id chat_id = args[0] == chat.id
permissions = args[2] == self.permissions permissions = args[1] == self.permissions
return chat_id and permissions return chat_id and permissions
monkeypatch.setattr('telegram.Bot.set_chat_permissions', test) monkeypatch.setattr(chat.bot, 'set_chat_permissions', test)
assert chat.set_permissions(self.permissions) assert chat.set_permissions(self.permissions)
def test_instance_method_send_message(self, monkeypatch, chat): def test_instance_method_send_message(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test' return args[0] == chat.id and args[1] == 'test'
monkeypatch.setattr('telegram.Bot.send_message', test) monkeypatch.setattr(chat.bot, 'send_message', test)
assert chat.send_message('test') assert chat.send_message('test')
def test_instance_method_send_photo(self, monkeypatch, chat): def test_instance_method_send_photo(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_photo' return args[0] == chat.id and args[1] == 'test_photo'
monkeypatch.setattr('telegram.Bot.send_photo', test) monkeypatch.setattr(chat.bot, 'send_photo', test)
assert chat.send_photo('test_photo') assert chat.send_photo('test_photo')
def test_instance_method_send_audio(self, monkeypatch, chat): def test_instance_method_send_audio(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_audio' return args[0] == chat.id and args[1] == 'test_audio'
monkeypatch.setattr('telegram.Bot.send_audio', test) monkeypatch.setattr(chat.bot, 'send_audio', test)
assert chat.send_audio('test_audio') assert chat.send_audio('test_audio')
def test_instance_method_send_document(self, monkeypatch, chat): def test_instance_method_send_document(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_document' return args[0] == chat.id and args[1] == 'test_document'
monkeypatch.setattr('telegram.Bot.send_document', test) monkeypatch.setattr(chat.bot, 'send_document', test)
assert chat.send_document('test_document') assert chat.send_document('test_document')
def test_instance_method_send_sticker(self, monkeypatch, chat): def test_instance_method_send_sticker(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_sticker' return args[0] == chat.id and args[1] == 'test_sticker'
monkeypatch.setattr('telegram.Bot.send_sticker', test) monkeypatch.setattr(chat.bot, 'send_sticker', test)
assert chat.send_sticker('test_sticker') assert chat.send_sticker('test_sticker')
def test_instance_method_send_video(self, monkeypatch, chat): def test_instance_method_send_video(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_video' return args[0] == chat.id and args[1] == 'test_video'
monkeypatch.setattr('telegram.Bot.send_video', test) monkeypatch.setattr(chat.bot, 'send_video', test)
assert chat.send_video('test_video') assert chat.send_video('test_video')
def test_instance_method_send_video_note(self, monkeypatch, chat): def test_instance_method_send_video_note(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_video_note' return args[0] == chat.id and args[1] == 'test_video_note'
monkeypatch.setattr('telegram.Bot.send_video_note', test) monkeypatch.setattr(chat.bot, 'send_video_note', test)
assert chat.send_video_note('test_video_note') assert chat.send_video_note('test_video_note')
def test_instance_method_send_voice(self, monkeypatch, chat): def test_instance_method_send_voice(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_voice' return args[0] == chat.id and args[1] == 'test_voice'
monkeypatch.setattr('telegram.Bot.send_voice', test) monkeypatch.setattr(chat.bot, 'send_voice', test)
assert chat.send_voice('test_voice') assert chat.send_voice('test_voice')
def test_instance_method_send_animation(self, monkeypatch, chat): def test_instance_method_send_animation(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_animation' return args[0] == chat.id and args[1] == 'test_animation'
monkeypatch.setattr('telegram.Bot.send_animation', test) monkeypatch.setattr(chat.bot, 'send_animation', test)
assert chat.send_animation('test_animation') assert chat.send_animation('test_animation')
def test_instance_method_send_poll(self, monkeypatch, chat): def test_instance_method_send_poll(self, monkeypatch, chat):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == chat.id and args[2] == 'test_poll' return args[0] == chat.id and args[1] == 'test_poll'
monkeypatch.setattr('telegram.Bot.send_poll', test) monkeypatch.setattr(chat.bot, 'send_poll', test)
assert chat.send_poll('test_poll') assert chat.send_poll('test_poll')
def test_equality(self): def test_equality(self):

59
tests/test_defaults.py Normal file
View file

@ -0,0 +1,59 @@
#!/usr/bin/env python
#
# A library that provides a Python interface to the Telegram Bot API
# Copyright (C) 2020
# 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/].
import pytest
from telegram.ext import Defaults
from telegram import User
class TestDefault(object):
def test_data_assignment(self, cdp):
defaults = Defaults()
with pytest.raises(AttributeError):
defaults.parse_mode = True
with pytest.raises(AttributeError):
defaults.disable_notification = True
with pytest.raises(AttributeError):
defaults.disable_web_page_preview = True
with pytest.raises(AttributeError):
defaults.timeout = True
with pytest.raises(AttributeError):
defaults.quote = True
def test_equality(self):
a = Defaults(parse_mode='HTML', quote=True)
b = Defaults(parse_mode='HTML', quote=True)
c = Defaults(parse_mode='HTML', quote=False)
d = Defaults(parse_mode='HTML', timeout=50)
e = User(123, 'test_user', False)
assert a == b
assert hash(a) == hash(b)
assert a is not b
assert a != c
assert hash(a) != hash(c)
assert a != d
assert hash(a) != hash(d)
assert a != e
assert hash(a) != hash(e)

View file

@ -22,6 +22,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import Document, PhotoSize, TelegramError, Voice from telegram import Document, PhotoSize, TelegramError, Voice
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -124,6 +125,39 @@ class TestDocument(object):
assert message assert message
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_document_default_parse_mode_1(self, default_bot, chat_id, document):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_document(chat_id, document, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_document_default_parse_mode_2(self, default_bot, chat_id, document):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_document(chat_id, document, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_document_default_parse_mode_3(self, default_bot, chat_id, document):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_document(chat_id, document, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
def test_de_json(self, bot, document): def test_de_json(self, bot, document):
json_dict = {'file_id': 'not a file id', json_dict = {'file_id': 'not a file id',
'thumb': document.thumb.to_dict(), 'thumb': document.thumb.to_dict(),

View file

@ -63,9 +63,9 @@ class TestInlineQuery(object):
def test_answer(self, monkeypatch, inline_query): def test_answer(self, monkeypatch, inline_query):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == inline_query.id return args[0] == inline_query.id
monkeypatch.setattr('telegram.Bot.answer_inline_query', test) monkeypatch.setattr(inline_query.bot, 'answer_inline_query', test)
assert inline_query.answer() assert inline_query.answer()
def test_equality(self): def test_equality(self):

View file

@ -329,6 +329,13 @@ class TestSendMediaGroup(object):
assert all([isinstance(mes, Message) for mes in messages]) assert all([isinstance(mes, Message) for mes in messages])
assert all([mes.media_group_id == messages[0].media_group_id for mes in messages]) assert all([mes.media_group_id == messages[0].media_group_id for mes in messages])
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'quote': True}], indirect=True)
def test_send_media_group_default_quote(self, default_bot, chat_id, media_group):
messages = default_bot.send_media_group(chat_id, media_group)
assert all([mes.default_quote is True for mes in messages])
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)
def test_edit_message_media(self, bot, chat_id, media_group): def test_edit_message_media(self, bot, chat_id, media_group):

View file

@ -94,7 +94,8 @@ def message(bot):
{'text': 'a text message', 'reply_markup': {'inline_keyboard': [[{ {'text': 'a text message', 'reply_markup': {'inline_keyboard': [[{
'text': 'start', 'url': 'http://google.com'}, { 'text': 'start', 'url': 'http://google.com'}, {
'text': 'next', 'callback_data': 'abcd'}], 'text': 'next', 'callback_data': 'abcd'}],
[{'text': 'Cancel', 'callback_data': 'Cancel'}]]}} [{'text': 'Cancel', 'callback_data': 'Cancel'}]]}},
{'quote': True}
], ],
ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text', ids=['forwarded_user', 'forwarded_channel', 'reply', 'edited', 'text',
'caption_entities', 'audio', 'document', 'animation', 'game', 'photo', 'caption_entities', 'audio', 'document', 'animation', 'game', 'photo',
@ -103,7 +104,8 @@ def message(bot):
'group_created', 'supergroup_created', 'channel_created', 'migrated_to', 'group_created', 'supergroup_created', 'channel_created', 'migrated_to',
'migrated_from', 'pinned', 'invoice', 'successful_payment', 'migrated_from', 'pinned', 'invoice', 'successful_payment',
'connected_website', 'forward_signature', 'author_signature', 'connected_website', 'forward_signature', 'author_signature',
'photo_from_media_group', 'passport_data', 'poll', 'reply_markup']) 'photo_from_media_group', 'passport_data', 'poll', 'reply_markup',
'default_quote'])
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,
@ -343,15 +345,15 @@ class TestMessage(object):
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[0] == message.chat_id
text = args[2] == 'test' text = args[1] == 'test'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
else: else:
reply = True reply = True
return id and text and reply return id and text and reply
monkeypatch.setattr('telegram.Bot.send_message', test) monkeypatch.setattr(message.bot, 'send_message', test)
assert message.reply_text('test') assert message.reply_text('test')
assert message.reply_text('test', quote=True) assert message.reply_text('test', quote=True)
assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True) assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True)
@ -362,8 +364,8 @@ class TestMessage(object):
'http://google.com') 'http://google.com')
def test(*args, **kwargs): def test(*args, **kwargs):
cid = args[1] == message.chat_id cid = args[0] == message.chat_id
markdown_text = args[2] == test_md_string markdown_text = args[1] == test_md_string
markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -374,7 +376,7 @@ class TestMessage(object):
text_markdown = self.test_message.text_markdown text_markdown = self.test_message.text_markdown
assert text_markdown == test_md_string assert text_markdown == test_md_string
monkeypatch.setattr('telegram.Bot.send_message', test) monkeypatch.setattr(message.bot, 'send_message', test)
assert message.reply_markdown(self.test_message.text_markdown) assert message.reply_markdown(self.test_message.text_markdown)
assert message.reply_markdown(self.test_message.text_markdown, quote=True) assert message.reply_markdown(self.test_message.text_markdown, quote=True)
assert message.reply_markdown(self.test_message.text_markdown, assert message.reply_markdown(self.test_message.text_markdown,
@ -388,8 +390,8 @@ class TestMessage(object):
'<pre>pre</pre>. http://google.com') '<pre>pre</pre>. http://google.com')
def test(*args, **kwargs): def test(*args, **kwargs):
cid = args[1] == message.chat_id cid = args[0] == message.chat_id
html_text = args[2] == test_html_string html_text = args[1] == test_html_string
html_enabled = kwargs['parse_mode'] == ParseMode.HTML html_enabled = kwargs['parse_mode'] == ParseMode.HTML
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -400,7 +402,7 @@ class TestMessage(object):
text_html = self.test_message.text_html text_html = self.test_message.text_html
assert text_html == test_html_string assert text_html == test_html_string
monkeypatch.setattr('telegram.Bot.send_message', test) monkeypatch.setattr(message.bot, 'send_message', test)
assert message.reply_html(self.test_message.text_html) assert message.reply_html(self.test_message.text_html)
assert message.reply_html(self.test_message.text_html, quote=True) assert message.reply_html(self.test_message.text_html, quote=True)
assert message.reply_html(self.test_message.text_html, assert message.reply_html(self.test_message.text_html,
@ -409,7 +411,7 @@ class TestMessage(object):
def test_reply_media_group(self, monkeypatch, message): def test_reply_media_group(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
media = kwargs['media'] == 'reply_media_group' media = kwargs['media'] == 'reply_media_group'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -417,13 +419,13 @@ class TestMessage(object):
reply = True reply = True
return id and media and reply return id and media and reply
monkeypatch.setattr('telegram.Bot.send_media_group', test) monkeypatch.setattr(message.bot, 'send_media_group', test)
assert message.reply_media_group(media='reply_media_group') assert message.reply_media_group(media='reply_media_group')
assert message.reply_media_group(media='reply_media_group', quote=True) assert message.reply_media_group(media='reply_media_group', quote=True)
def test_reply_photo(self, monkeypatch, message): def test_reply_photo(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
photo = kwargs['photo'] == 'test_photo' photo = kwargs['photo'] == 'test_photo'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -431,13 +433,13 @@ class TestMessage(object):
reply = True reply = True
return id and photo and reply return id and photo and reply
monkeypatch.setattr('telegram.Bot.send_photo', test) monkeypatch.setattr(message.bot, 'send_photo', test)
assert message.reply_photo(photo='test_photo') assert message.reply_photo(photo='test_photo')
assert message.reply_photo(photo='test_photo', quote=True) assert message.reply_photo(photo='test_photo', quote=True)
def test_reply_audio(self, monkeypatch, message): def test_reply_audio(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
audio = kwargs['audio'] == 'test_audio' audio = kwargs['audio'] == 'test_audio'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -445,13 +447,13 @@ class TestMessage(object):
reply = True reply = True
return id and audio and reply return id and audio and reply
monkeypatch.setattr('telegram.Bot.send_audio', test) monkeypatch.setattr(message.bot, 'send_audio', test)
assert message.reply_audio(audio='test_audio') assert message.reply_audio(audio='test_audio')
assert message.reply_audio(audio='test_audio', quote=True) assert message.reply_audio(audio='test_audio', quote=True)
def test_reply_document(self, monkeypatch, message): def test_reply_document(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
document = kwargs['document'] == 'test_document' document = kwargs['document'] == 'test_document'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -459,13 +461,13 @@ class TestMessage(object):
reply = True reply = True
return id and document and reply return id and document and reply
monkeypatch.setattr('telegram.Bot.send_document', test) monkeypatch.setattr(message.bot, 'send_document', test)
assert message.reply_document(document='test_document') assert message.reply_document(document='test_document')
assert message.reply_document(document='test_document', quote=True) assert message.reply_document(document='test_document', quote=True)
def test_reply_animation(self, monkeypatch, message): def test_reply_animation(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
animation = kwargs['animation'] == 'test_animation' animation = kwargs['animation'] == 'test_animation'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -473,13 +475,13 @@ class TestMessage(object):
reply = True reply = True
return id and animation and reply return id and animation and reply
monkeypatch.setattr('telegram.Bot.send_animation', test) monkeypatch.setattr(message.bot, 'send_animation', test)
assert message.reply_animation(animation='test_animation') assert message.reply_animation(animation='test_animation')
assert message.reply_animation(animation='test_animation', quote=True) assert message.reply_animation(animation='test_animation', quote=True)
def test_reply_sticker(self, monkeypatch, message): def test_reply_sticker(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
sticker = kwargs['sticker'] == 'test_sticker' sticker = kwargs['sticker'] == 'test_sticker'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -487,13 +489,13 @@ class TestMessage(object):
reply = True reply = True
return id and sticker and reply return id and sticker and reply
monkeypatch.setattr('telegram.Bot.send_sticker', test) monkeypatch.setattr(message.bot, 'send_sticker', test)
assert message.reply_sticker(sticker='test_sticker') assert message.reply_sticker(sticker='test_sticker')
assert message.reply_sticker(sticker='test_sticker', quote=True) assert message.reply_sticker(sticker='test_sticker', quote=True)
def test_reply_video(self, monkeypatch, message): def test_reply_video(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
video = kwargs['video'] == 'test_video' video = kwargs['video'] == 'test_video'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -501,13 +503,13 @@ class TestMessage(object):
reply = True reply = True
return id and video and reply return id and video and reply
monkeypatch.setattr('telegram.Bot.send_video', test) monkeypatch.setattr(message.bot, 'send_video', test)
assert message.reply_video(video='test_video') assert message.reply_video(video='test_video')
assert message.reply_video(video='test_video', quote=True) assert message.reply_video(video='test_video', quote=True)
def test_reply_video_note(self, monkeypatch, message): def test_reply_video_note(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
video_note = kwargs['video_note'] == 'test_video_note' video_note = kwargs['video_note'] == 'test_video_note'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -515,13 +517,13 @@ class TestMessage(object):
reply = True reply = True
return id and video_note and reply return id and video_note and reply
monkeypatch.setattr('telegram.Bot.send_video_note', test) monkeypatch.setattr(message.bot, 'send_video_note', test)
assert message.reply_video_note(video_note='test_video_note') assert message.reply_video_note(video_note='test_video_note')
assert message.reply_video_note(video_note='test_video_note', quote=True) assert message.reply_video_note(video_note='test_video_note', quote=True)
def test_reply_voice(self, monkeypatch, message): def test_reply_voice(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
voice = kwargs['voice'] == 'test_voice' voice = kwargs['voice'] == 'test_voice'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -529,13 +531,13 @@ class TestMessage(object):
reply = True reply = True
return id and voice and reply return id and voice and reply
monkeypatch.setattr('telegram.Bot.send_voice', test) monkeypatch.setattr(message.bot, 'send_voice', test)
assert message.reply_voice(voice='test_voice') assert message.reply_voice(voice='test_voice')
assert message.reply_voice(voice='test_voice', quote=True) assert message.reply_voice(voice='test_voice', quote=True)
def test_reply_location(self, monkeypatch, message): def test_reply_location(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
location = kwargs['location'] == 'test_location' location = kwargs['location'] == 'test_location'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -543,13 +545,13 @@ class TestMessage(object):
reply = True reply = True
return id and location and reply return id and location and reply
monkeypatch.setattr('telegram.Bot.send_location', test) monkeypatch.setattr(message.bot, 'send_location', test)
assert message.reply_location(location='test_location') assert message.reply_location(location='test_location')
assert message.reply_location(location='test_location', quote=True) assert message.reply_location(location='test_location', quote=True)
def test_reply_venue(self, monkeypatch, message): def test_reply_venue(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
venue = kwargs['venue'] == 'test_venue' venue = kwargs['venue'] == 'test_venue'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -557,13 +559,13 @@ class TestMessage(object):
reply = True reply = True
return id and venue and reply return id and venue and reply
monkeypatch.setattr('telegram.Bot.send_venue', test) monkeypatch.setattr(message.bot, 'send_venue', test)
assert message.reply_venue(venue='test_venue') assert message.reply_venue(venue='test_venue')
assert message.reply_venue(venue='test_venue', quote=True) assert message.reply_venue(venue='test_venue', quote=True)
def test_reply_contact(self, monkeypatch, message): def test_reply_contact(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
contact = kwargs['contact'] == 'test_contact' contact = kwargs['contact'] == 'test_contact'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -571,13 +573,13 @@ class TestMessage(object):
reply = True reply = True
return id and contact and reply return id and contact and reply
monkeypatch.setattr('telegram.Bot.send_contact', test) monkeypatch.setattr(message.bot, 'send_contact', test)
assert message.reply_contact(contact='test_contact') assert message.reply_contact(contact='test_contact')
assert message.reply_contact(contact='test_contact', quote=True) assert message.reply_contact(contact='test_contact', quote=True)
def test_reply_poll(self, monkeypatch, message): def test_reply_poll(self, monkeypatch, message):
def test(*args, **kwargs): def test(*args, **kwargs):
id = args[1] == message.chat_id id = args[0] == message.chat_id
contact = kwargs['contact'] == 'test_poll' contact = kwargs['contact'] == 'test_poll'
if kwargs.get('reply_to_message_id'): if kwargs.get('reply_to_message_id'):
reply = kwargs['reply_to_message_id'] == message.message_id reply = kwargs['reply_to_message_id'] == message.message_id
@ -585,7 +587,7 @@ class TestMessage(object):
reply = True reply = True
return id and contact and reply return id and contact and reply
monkeypatch.setattr('telegram.Bot.send_poll', test) monkeypatch.setattr(message.bot, 'send_poll', test)
assert message.reply_poll(contact='test_poll') assert message.reply_poll(contact='test_poll')
assert message.reply_poll(contact='test_poll', quote=True) assert message.reply_poll(contact='test_poll', quote=True)
@ -600,7 +602,7 @@ class TestMessage(object):
notification = True notification = True
return chat_id and from_chat and message_id and notification return chat_id and from_chat and message_id and notification
monkeypatch.setattr('telegram.Bot.forward_message', test) monkeypatch.setattr(message.bot, 'forward_message', test)
assert message.forward(123456) assert message.forward(123456)
assert message.forward(123456, disable_notification=True) assert message.forward(123456, disable_notification=True)
assert not message.forward(635241) assert not message.forward(635241)
@ -612,7 +614,7 @@ class TestMessage(object):
text = kwargs['text'] == 'test' text = kwargs['text'] == 'test'
return chat_id and message_id and text return chat_id and message_id and text
monkeypatch.setattr('telegram.Bot.edit_message_text', test) monkeypatch.setattr(message.bot, 'edit_message_text', test)
assert message.edit_text(text='test') assert message.edit_text(text='test')
def test_edit_caption(self, monkeypatch, message): def test_edit_caption(self, monkeypatch, message):
@ -622,7 +624,7 @@ class TestMessage(object):
caption = kwargs['caption'] == 'new caption' caption = kwargs['caption'] == 'new caption'
return chat_id and message_id and caption return chat_id and message_id and caption
monkeypatch.setattr('telegram.Bot.edit_message_caption', test) monkeypatch.setattr(message.bot, 'edit_message_caption', test)
assert message.edit_caption(caption='new caption') assert message.edit_caption(caption='new caption')
def test_edit_media(self, monkeypatch, message): def test_edit_media(self, monkeypatch, message):
@ -632,7 +634,7 @@ class TestMessage(object):
media = kwargs['media'] == 'my_media' media = kwargs['media'] == 'my_media'
return chat_id and message_id and media return chat_id and message_id and media
monkeypatch.setattr('telegram.Bot.edit_message_media', test) monkeypatch.setattr(message.bot, 'edit_message_media', test)
assert message.edit_media('my_media') assert message.edit_media('my_media')
def test_edit_reply_markup(self, monkeypatch, message): def test_edit_reply_markup(self, monkeypatch, message):
@ -642,7 +644,7 @@ class TestMessage(object):
reply_markup = kwargs['reply_markup'] == [['1', '2']] reply_markup = kwargs['reply_markup'] == [['1', '2']]
return chat_id and message_id and reply_markup return chat_id and message_id and reply_markup
monkeypatch.setattr('telegram.Bot.edit_message_reply_markup', test) monkeypatch.setattr(message.bot, 'edit_message_reply_markup', test)
assert message.edit_reply_markup(reply_markup=[['1', '2']]) assert message.edit_reply_markup(reply_markup=[['1', '2']])
def test_delete(self, monkeypatch, message): def test_delete(self, monkeypatch, message):
@ -651,9 +653,30 @@ class TestMessage(object):
message_id = kwargs['message_id'] == message.message_id message_id = kwargs['message_id'] == message.message_id
return chat_id and message_id return chat_id and message_id
monkeypatch.setattr('telegram.Bot.delete_message', test) monkeypatch.setattr(message.bot, 'delete_message', test)
assert message.delete() assert message.delete()
def test_default_quote(self, message):
kwargs = {}
message.default_quote = False
message._quote(kwargs)
assert 'reply_to_message_id' not in kwargs
message.default_quote = True
message._quote(kwargs)
assert 'reply_to_message_id' in kwargs
kwargs = {}
message.default_quote = None
message.chat.type = Chat.PRIVATE
message._quote(kwargs)
assert 'reply_to_message_id' not in kwargs
message.chat.type = Chat.GROUP
message._quote(kwargs)
assert 'reply_to_message_id' in kwargs
def test_equality(self): def test_equality(self):
id = 1 id = 1
a = Message(id, self.from_user, self.date, self.chat) a = Message(id, self.from_user, self.date, self.chat)

View file

@ -296,9 +296,9 @@ class TestPassport(object):
selfie = passport_data.decrypted_data[1].selfie selfie = passport_data.decrypted_data[1].selfie
def get_file(*args, **kwargs): def get_file(*args, **kwargs):
return File(args[1]) return File(args[0])
monkeypatch.setattr('telegram.Bot.get_file', get_file) monkeypatch.setattr(passport_data.bot, 'get_file', get_file)
file = selfie.get_file() file = selfie.get_file()
assert file.file_id == selfie.file_id assert file.file_id == selfie.file_id
assert file._credentials.file_hash == self.driver_license_selfie_credentials_file_hash assert file._credentials.file_hash == self.driver_license_selfie_credentials_file_hash

View file

@ -23,6 +23,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import Sticker, TelegramError, PhotoSize, InputFile from telegram import Sticker, TelegramError, PhotoSize, InputFile
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -139,6 +140,39 @@ class TestPhoto(object):
assert message.caption == TestPhoto.caption.replace('<b>', '').replace('</b>', '') assert message.caption == TestPhoto.caption.replace('<b>', '').replace('</b>', '')
assert len(message.caption_entities) == 1 assert len(message.caption_entities) == 1
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_photo_default_parse_mode_1(self, default_bot, chat_id, photo_file, thumb, photo):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_photo(chat_id, photo_file, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_photo_default_parse_mode_2(self, default_bot, chat_id, photo_file, thumb, photo):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_photo(chat_id, photo_file, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_photo_default_parse_mode_3(self, default_bot, chat_id, photo_file, thumb, photo):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_photo(chat_id, photo_file, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1) @flaky(3, 1)
@pytest.mark.timeout(10) @pytest.mark.timeout(10)
@pytest.mark.skip(reason='Doesnt work without API 4.5') @pytest.mark.skip(reason='Doesnt work without API 4.5')

View file

@ -77,9 +77,9 @@ class TestPreCheckoutQuery(object):
def test_answer(self, monkeypatch, pre_checkout_query): def test_answer(self, monkeypatch, pre_checkout_query):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == pre_checkout_query.id return args[0] == pre_checkout_query.id
monkeypatch.setattr('telegram.Bot.answer_pre_checkout_query', test) monkeypatch.setattr(pre_checkout_query.bot, 'answer_pre_checkout_query', test)
assert pre_checkout_query.answer() assert pre_checkout_query.answer()
def test_equality(self): def test_equality(self):

View file

@ -63,9 +63,9 @@ class TestShippingQuery(object):
def test_answer(self, monkeypatch, shipping_query): def test_answer(self, monkeypatch, shipping_query):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == shipping_query.id return args[0] == shipping_query.id
monkeypatch.setattr('telegram.Bot.answer_shipping_query', test) monkeypatch.setattr(shipping_query.bot, 'answer_shipping_query', test)
assert shipping_query.answer() assert shipping_query.answer()
def test_equality(self): def test_equality(self):

View file

@ -75,6 +75,14 @@ class TestUpdate(object):
assert update is None assert update is None
def test_de_json_default_quote(self, bot):
json_dict = {'update_id': TestUpdate.update_id}
json_dict['message'] = message.to_dict()
json_dict['default_quote'] = True
update = Update.de_json(json_dict, bot)
assert update.message.default_quote is True
def test_to_dict(self, update): def test_to_dict(self, update):
update_dict = update.to_dict() update_dict = update.to_dict()

View file

@ -79,8 +79,8 @@ class TestUpdater(object):
def test(*args, **kwargs): def test(*args, **kwargs):
raise error raise error
monkeypatch.setattr('telegram.Bot.get_updates', test) monkeypatch.setattr(updater.bot, 'get_updates', test)
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
updater.dispatcher.add_error_handler(self.error_handler) updater.dispatcher.add_error_handler(self.error_handler)
updater.start_polling(0.01) updater.start_polling(0.01)
@ -99,8 +99,8 @@ class TestUpdater(object):
raise error raise error
with caplog.at_level(logging.DEBUG): with caplog.at_level(logging.DEBUG):
monkeypatch.setattr('telegram.Bot.get_updates', test) monkeypatch.setattr(updater.bot, 'get_updates', test)
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
updater.dispatcher.add_error_handler(self.error_handler) updater.dispatcher.add_error_handler(self.error_handler)
updater.start_polling(0.01) updater.start_polling(0.01)
assert self.err_handler_called.wait(1) is not True assert self.err_handler_called.wait(1) is not True
@ -127,8 +127,8 @@ class TestUpdater(object):
event.set() event.set()
raise error raise error
monkeypatch.setattr('telegram.Bot.get_updates', test) monkeypatch.setattr(updater.bot, 'get_updates', test)
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
updater.dispatcher.add_error_handler(self.error_handler) updater.dispatcher.add_error_handler(self.error_handler)
updater.start_polling(0.01) updater.start_polling(0.01)
@ -144,8 +144,8 @@ class TestUpdater(object):
def test_webhook(self, monkeypatch, updater): def test_webhook(self, monkeypatch, updater):
q = Queue() q = Queue()
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u)) monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u))
ip = '127.0.0.1' ip = '127.0.0.1'
@ -182,8 +182,8 @@ class TestUpdater(object):
updater.stop() updater.stop()
def test_webhook_ssl(self, monkeypatch, updater): def test_webhook_ssl(self, monkeypatch, updater):
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True)
ip = '127.0.0.1' ip = '127.0.0.1'
port = randrange(1024, 49152) # Select random port for travis port = randrange(1024, 49152) # Select random port for travis
tg_err = False tg_err = False
@ -204,8 +204,8 @@ class TestUpdater(object):
def test_webhook_no_ssl(self, monkeypatch, updater): def test_webhook_no_ssl(self, monkeypatch, updater):
q = Queue() q = Queue()
monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u)) monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u))
ip = '127.0.0.1' ip = '127.0.0.1'
@ -221,18 +221,42 @@ class TestUpdater(object):
assert q.get(False) == update assert q.get(False) == update
updater.stop() updater.stop()
def test_webhook_default_quote(self, monkeypatch, updater):
updater._default_quote = True
q = Queue()
monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True)
monkeypatch.setattr('telegram.ext.Dispatcher.process_update', lambda _, u: q.put(u))
ip = '127.0.0.1'
port = randrange(1024, 49152) # Select random port for travis
updater.start_webhook(
ip,
port,
url_path='TOKEN')
sleep(.2)
# Now, we send an update to the server via urlopen
update = Update(1, message=Message(1, User(1, '', False), None, Chat(1, ''),
text='Webhook'))
self._send_webhook_msg(ip, port, update.to_json(), 'TOKEN')
sleep(.2)
# assert q.get(False) == update
assert q.get(False).message.default_quote is True
updater.stop()
@pytest.mark.parametrize(('error',), @pytest.mark.parametrize(('error',),
argvalues=[(TelegramError(''),)], argvalues=[(TelegramError(''),)],
ids=('TelegramError',)) ids=('TelegramError',))
def test_bootstrap_retries_success(self, monkeypatch, updater, error): def test_bootstrap_retries_success(self, monkeypatch, updater, error):
retries = 2 retries = 2
def attempt(_, *args, **kwargs): def attempt(*args, **kwargs):
if self.attempts < retries: if self.attempts < retries:
self.attempts += 1 self.attempts += 1
raise error raise error
monkeypatch.setattr('telegram.Bot.set_webhook', attempt) monkeypatch.setattr(updater.bot, 'set_webhook', attempt)
updater.running = True updater.running = True
updater._bootstrap(retries, False, 'path', None, bootstrap_interval=0) updater._bootstrap(retries, False, 'path', None, bootstrap_interval=0)
@ -246,11 +270,11 @@ class TestUpdater(object):
def test_bootstrap_retries_error(self, monkeypatch, updater, error, attempts): def test_bootstrap_retries_error(self, monkeypatch, updater, error, attempts):
retries = 1 retries = 1
def attempt(_, *args, **kwargs): def attempt(*args, **kwargs):
self.attempts += 1 self.attempts += 1
raise error raise error
monkeypatch.setattr('telegram.Bot.set_webhook', attempt) monkeypatch.setattr(updater.bot, 'set_webhook', attempt)
updater.running = True updater.running = True
with pytest.raises(type(error)): with pytest.raises(type(error)):

View file

@ -103,73 +103,73 @@ class TestUser(object):
assert user.link is None assert user.link is None
def test_get_profile_photos(self, monkeypatch, user): def test_get_profile_photos(self, monkeypatch, user):
def test(_, *args, **kwargs): def test(*args, **kwargs):
return args[0] == user.id return args[0] == user.id
monkeypatch.setattr('telegram.Bot.get_user_profile_photos', test) monkeypatch.setattr(user.bot, 'get_user_profile_photos', test)
assert user.get_profile_photos() assert user.get_profile_photos()
def test_instance_method_send_message(self, monkeypatch, user): def test_instance_method_send_message(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test' return args[0] == user.id and args[1] == 'test'
monkeypatch.setattr('telegram.Bot.send_message', test) monkeypatch.setattr(user.bot, 'send_message', test)
assert user.send_message('test') assert user.send_message('test')
def test_instance_method_send_photo(self, monkeypatch, user): def test_instance_method_send_photo(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_photo' return args[0] == user.id and args[1] == 'test_photo'
monkeypatch.setattr('telegram.Bot.send_photo', test) monkeypatch.setattr(user.bot, 'send_photo', test)
assert user.send_photo('test_photo') assert user.send_photo('test_photo')
def test_instance_method_send_audio(self, monkeypatch, user): def test_instance_method_send_audio(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_audio' return args[0] == user.id and args[1] == 'test_audio'
monkeypatch.setattr('telegram.Bot.send_audio', test) monkeypatch.setattr(user.bot, 'send_audio', test)
assert user.send_audio('test_audio') assert user.send_audio('test_audio')
def test_instance_method_send_document(self, monkeypatch, user): def test_instance_method_send_document(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_document' return args[0] == user.id and args[1] == 'test_document'
monkeypatch.setattr('telegram.Bot.send_document', test) monkeypatch.setattr(user.bot, 'send_document', test)
assert user.send_document('test_document') assert user.send_document('test_document')
def test_instance_method_send_sticker(self, monkeypatch, user): def test_instance_method_send_sticker(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_sticker' return args[0] == user.id and args[1] == 'test_sticker'
monkeypatch.setattr('telegram.Bot.send_sticker', test) monkeypatch.setattr(user.bot, 'send_sticker', test)
assert user.send_sticker('test_sticker') assert user.send_sticker('test_sticker')
def test_instance_method_send_video(self, monkeypatch, user): def test_instance_method_send_video(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_video' return args[0] == user.id and args[1] == 'test_video'
monkeypatch.setattr('telegram.Bot.send_video', test) monkeypatch.setattr(user.bot, 'send_video', test)
assert user.send_video('test_video') assert user.send_video('test_video')
def test_instance_method_send_video_note(self, monkeypatch, user): def test_instance_method_send_video_note(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_video_note' return args[0] == user.id and args[1] == 'test_video_note'
monkeypatch.setattr('telegram.Bot.send_video_note', test) monkeypatch.setattr(user.bot, 'send_video_note', test)
assert user.send_video_note('test_video_note') assert user.send_video_note('test_video_note')
def test_instance_method_send_voice(self, monkeypatch, user): def test_instance_method_send_voice(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_voice' return args[0] == user.id and args[1] == 'test_voice'
monkeypatch.setattr('telegram.Bot.send_voice', test) monkeypatch.setattr(user.bot, 'send_voice', test)
assert user.send_voice('test_voice') assert user.send_voice('test_voice')
def test_instance_method_send_animation(self, monkeypatch, user): def test_instance_method_send_animation(self, monkeypatch, user):
def test(*args, **kwargs): def test(*args, **kwargs):
return args[1] == user.id and args[2] == 'test_animation' return args[0] == user.id and args[1] == 'test_animation'
monkeypatch.setattr('telegram.Bot.send_animation', test) monkeypatch.setattr(user.bot, 'send_animation', test)
assert user.send_animation('test_animation') assert user.send_animation('test_animation')
def test_mention_html(self, user): def test_mention_html(self, user):

View file

@ -22,6 +22,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import Video, TelegramError, Voice, PhotoSize from telegram import Video, TelegramError, Voice, PhotoSize
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -142,6 +143,39 @@ class TestVideo(object):
message = bot.send_video(chat_id, video=video) message = bot.send_video(chat_id, video=video)
assert message assert message
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_video_default_parse_mode_1(self, default_bot, chat_id, video):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_video(chat_id, video, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_video_default_parse_mode_2(self, default_bot, chat_id, video):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_video(chat_id, video, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_video_default_parse_mode_3(self, default_bot, chat_id, video):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_video(chat_id, video, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
def test_de_json(self, bot): def test_de_json(self, bot):
json_dict = { json_dict = {
'file_id': 'not a file id', 'file_id': 'not a file id',

View file

@ -22,6 +22,7 @@ import pytest
from flaky import flaky from flaky import flaky
from telegram import Audio, Voice, TelegramError from telegram import Audio, Voice, TelegramError
from telegram.utils.helpers import escape_markdown
@pytest.fixture(scope='function') @pytest.fixture(scope='function')
@ -112,6 +113,39 @@ class TestVoice(object):
message = bot.send_voice(chat_id, voice=voice) message = bot.send_voice(chat_id, voice=voice)
assert message assert message
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_voice_default_parse_mode_1(self, default_bot, chat_id, voice):
test_string = 'Italic Bold Code'
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_voice(chat_id, voice, caption=test_markdown_string)
assert message.caption_markdown == test_markdown_string
assert message.caption == test_string
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_voice_default_parse_mode_2(self, default_bot, chat_id, voice):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_voice(chat_id, voice, caption=test_markdown_string,
parse_mode=None)
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
@flaky(3, 1)
@pytest.mark.timeout(10)
@pytest.mark.parametrize('default_bot', [{'parse_mode': 'Markdown'}], indirect=True)
def test_send_voice_default_parse_mode_3(self, default_bot, chat_id, voice):
test_markdown_string = '_Italic_ *Bold* `Code`'
message = default_bot.send_voice(chat_id, voice, caption=test_markdown_string,
parse_mode='HTML')
assert message.caption == test_markdown_string
assert message.caption_markdown == escape_markdown(test_markdown_string)
def test_de_json(self, bot): def test_de_json(self, bot):
json_dict = { json_dict = {
'file_id': 'not a file id', 'file_id': 'not a file id',