diff --git a/requirements.txt b/requirements.txt index c004d5fc790..6f926578e47 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,4 @@ future>=0.16.0 certifi tornado>=5.1 cryptography +decorator>=4.4.0 diff --git a/telegram/bot.py b/telegram/bot.py index bb9b3ecf5b2..d648404162c 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -21,6 +21,8 @@ """This module contains an object that represents a Telegram Bot.""" import functools +import inspect +from decorator import decorate try: import ujson as json @@ -39,7 +41,7 @@ PhotoSize, Audio, Document, Sticker, Video, Animation, Voice, VideoNote, Location, Venue, Contact, InputFile, Poll) from telegram.error import InvalidToken, TelegramError -from telegram.utils.helpers import to_timestamp +from telegram.utils.helpers import to_timestamp, Defaults, DEFAULT_NONE from telegram.utils.request import Request logging.getLogger(__name__).addHandler(logging.NullHandler()) @@ -57,18 +59,17 @@ def decorator(self, *args, **kwargs): return decorator -def log(func): +def log(func, *args, **kwargs): logger = logging.getLogger(func.__module__) - @functools.wraps(func) def decorator(self, *args, **kwargs): logger.debug('Entering: %s', func.__name__) - result = func(self, *args, **kwargs) + result = func(*args, **kwargs) logger.debug(result) logger.debug('Exiting: %s', func.__name__) return result - return decorator + return decorate(func, decorator) class Bot(TelegramObject): @@ -82,13 +83,70 @@ class Bot(TelegramObject): :obj:`telegram.utils.request.Request`. private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. private_key_password (:obj:`bytes`, optional): Password for above private key. + default_parse_mode (:obj:`str`, optional): Default parse mode used if not set explicitly in + method call. See the constants in :class:`telegram.ParseMode` for the available modes. + default_disable_notification (:obj:`bool`, optional): Default setting for the + `disable_notification` parameter used if not set explicitly in method call. + default_disable_web_page_preview (:obj:`bool`, optional): Default setting for the + `disable_web_page_preview` parameter used if not set explicitly in method call. + default_timeout (:obj:`int` | :obj:`float`, optional): Default setting for the + `timeout` parameter used if not set explicitly in method call. """ - def __init__(self, token, base_url=None, base_file_url=None, request=None, private_key=None, - private_key_password=None): + def __new__(cls, *args, **kwargs): + # Handle default_... kwargs for bot methods + # Transform default_x=y kwargs into Defaults.x=y + defaults = Defaults() + for kwarg in kwargs.keys(): + if kwarg.startswith('default_'): + setattr(defaults, kwarg[8:], kwargs[kwarg]) + + # Make an instance of the class + instance = super(Bot, cls).__new__(cls) + + # 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 kwarg_name in defaults.__dict__.keys() + ] + # ... 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, + default_parse_mode=None, + default_disable_notification=None, + default_disable_web_page_preview=None, + # Timeout needs special treatment, since the bot methods have two different + # default values for timeout (None and 20s) + default_timeout=DEFAULT_NONE): self.token = self._validate_token(token) + # Gather default + self.defaults = Defaults(parse_mode=default_parse_mode, + disable_notification=default_disable_notification, + disable_web_page_preview=default_disable_web_page_preview, + timeout=default_timeout) + if base_url is None: base_url = 'https://api.telegram.org/bot' @@ -120,6 +178,9 @@ def _message(self, url, data, reply_to_message_id=None, disable_notification=Non else: data['reply_markup'] = reply_markup + if data.get('media') and (data['media'].parse_mode is DEFAULT_NONE): + data['media'].parse_mode = self.defaults.parse_mode + result = self._request.post(url, data, timeout=timeout) if result is True: @@ -978,6 +1039,10 @@ def send_media_group(self, data = {'chat_id': chat_id, 'media': media} + for m in data['media']: + if m.parse_mode is DEFAULT_NONE: + m.parse_mode = self.defaults.parse_mode + if reply_to_message_id: data['reply_to_message_id'] = reply_to_message_id if disable_notification: @@ -1447,6 +1512,13 @@ def answer_inline_query(self, """ url = '{0}/answerInlineQuery'.format(self.base_url) + for res in results: + if res._has_parse_mode and res.parse_mode is 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 is DEFAULT_NONE): + res.input_message_content.parse_mode = self.defaults.parse_mode results = [res.to_dict() for res in results] data = {'inline_query_id': inline_query_id, 'results': results} diff --git a/telegram/ext/updater.py b/telegram/ext/updater.py index 8b6af368417..46519c8d6e6 100644 --- a/telegram/ext/updater.py +++ b/telegram/ext/updater.py @@ -28,7 +28,7 @@ from telegram import Bot, TelegramError from telegram.ext import Dispatcher, JobQueue from telegram.error import Unauthorized, InvalidToken, RetryAfter, TimedOut -from telegram.utils.helpers import get_signal_name +from telegram.utils.helpers import get_signal_name, DEFAULT_NONE from telegram.utils.request import Request from telegram.utils.webhookhandler import (WebhookServer, WebhookAppClass) @@ -81,6 +81,14 @@ class Updater(object): set this to ``True``. persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to store data that should be persistent over restarts. + default_parse_mode (:obj:`str`, optional): Default parse mode used if not set explicitly in + method call. See the constants in :class:`telegram.ParseMode` for the available modes. + default_disable_notification (:obj:`bool`, optional): Default setting for the + `disable_notification` parameter used if not set explicitly in method call. + default_disable_web_page_preview (:obj:`bool`, optional): Default setting for the + `disable_web_page_preview` parameter used if not set explicitly in method call. + default_timeout (:obj:`int` | :obj:`float`, optional): Default setting for the + `timeout` parameter used if not set explicitly in method call. Note: You must supply either a :attr:`bot` or a :attr:`token` argument. @@ -102,6 +110,10 @@ def __init__(self, user_sig_handler=None, request_kwargs=None, persistence=None, + default_parse_mode=None, + default_disable_notification=None, + default_disable_web_page_preview=None, + default_timeout=DEFAULT_NONE, use_context=False): if (token is None) and (bot is None): @@ -134,7 +146,11 @@ def __init__(self, request_kwargs['con_pool_size'] = con_pool_size self._request = Request(**request_kwargs) self.bot = Bot(token, base_url, request=self._request, private_key=private_key, - private_key_password=private_key_password) + private_key_password=private_key_password, + default_parse_mode=default_parse_mode, + default_disable_notification=default_disable_notification, + default_disable_web_page_preview=default_disable_web_page_preview, + default_timeout=default_timeout) self.user_sig_handler = user_sig_handler self.update_queue = Queue() self.job_queue = JobQueue() diff --git a/telegram/files/inputmedia.py b/telegram/files/inputmedia.py index e8187ba544a..2760223bc33 100644 --- a/telegram/files/inputmedia.py +++ b/telegram/files/inputmedia.py @@ -19,6 +19,7 @@ """Base class for Telegram InputMedia Objects.""" from telegram import TelegramObject, InputFile, PhotoSize, Animation, Video, Audio, Document +from telegram.utils.helpers import DEFAULT_NONE class InputMedia(TelegramObject): @@ -77,7 +78,13 @@ class InputMediaAnimation(InputMedia): 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): self.type = 'animation' @@ -98,8 +105,7 @@ def __init__(self, media, thumb=None, caption=None, parse_mode=None, width=None, if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if width: self.width = width if height: @@ -133,7 +139,7 @@ class InputMediaPhoto(InputMedia): 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' if isinstance(media, PhotoSize): @@ -145,8 +151,7 @@ def __init__(self, media, caption=None, parse_mode=None): if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode class InputMediaVideo(InputMedia): @@ -198,7 +203,7 @@ class InputMediaVideo(InputMedia): """ 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' if isinstance(media, Video): @@ -218,8 +223,7 @@ def __init__(self, media, caption=None, width=None, height=None, duration=None, if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if width: self.width = width if height: @@ -276,7 +280,7 @@ class InputMediaAudio(InputMedia): 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): self.type = 'audio' @@ -297,8 +301,7 @@ def __init__(self, media, thumb=None, caption=None, parse_mode=None, if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if duration: self.duration = duration if performer: @@ -340,7 +343,7 @@ class InputMediaDocument(InputMedia): 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' if isinstance(media, Document): @@ -357,5 +360,4 @@ def __init__(self, media, thumb=None, caption=None, parse_mode=None): if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode diff --git a/telegram/inline/inlinequeryresult.py b/telegram/inline/inlinequeryresult.py index 6feaf56512d..a2ec5e18056 100644 --- a/telegram/inline/inlinequeryresult.py +++ b/telegram/inline/inlinequeryresult.py @@ -41,3 +41,11 @@ def __init__(self, type, id, **kwargs): self.id = str(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') diff --git a/telegram/inline/inlinequeryresultaudio.py b/telegram/inline/inlinequeryresultaudio.py index 0bd2c3ce584..13f3c08f43b 100644 --- a/telegram/inline/inlinequeryresultaudio.py +++ b/telegram/inline/inlinequeryresultaudio.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultAudio.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultAudio(InlineQueryResult): @@ -70,7 +71,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required @@ -85,8 +86,7 @@ def __init__(self, self.audio_duration = audio_duration if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedaudio.py b/telegram/inline/inlinequeryresultcachedaudio.py index d225f4129e5..034029f1fef 100644 --- a/telegram/inline/inlinequeryresultcachedaudio.py +++ b/telegram/inline/inlinequeryresultcachedaudio.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultCachedAudio.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedAudio(InlineQueryResult): @@ -61,7 +62,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedAudio, self).__init__('audio', id) @@ -70,8 +71,7 @@ def __init__(self, # Optionals if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcacheddocument.py b/telegram/inline/inlinequeryresultcacheddocument.py index 28606949ab5..fef116d97ee 100644 --- a/telegram/inline/inlinequeryresultcacheddocument.py +++ b/telegram/inline/inlinequeryresultcacheddocument.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultCachedDocument.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedDocument(InlineQueryResult): @@ -67,7 +68,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedDocument, self).__init__('document', id) @@ -79,8 +80,7 @@ def __init__(self, self.description = description if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedgif.py b/telegram/inline/inlinequeryresultcachedgif.py index bfdb5bb9789..404c33b2265 100644 --- a/telegram/inline/inlinequeryresultcachedgif.py +++ b/telegram/inline/inlinequeryresultcachedgif.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultCachedGif.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedGif(InlineQueryResult): @@ -65,7 +66,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedGif, self).__init__('gif', id) @@ -76,8 +77,7 @@ def __init__(self, self.title = title if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedmpeg4gif.py b/telegram/inline/inlinequeryresultcachedmpeg4gif.py index 4dfbd8d9e44..1f870ea58cb 100644 --- a/telegram/inline/inlinequeryresultcachedmpeg4gif.py +++ b/telegram/inline/inlinequeryresultcachedmpeg4gif.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): @@ -65,7 +66,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedMpeg4Gif, self).__init__('mpeg4_gif', id) @@ -76,8 +77,7 @@ def __init__(self, self.title = title if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedphoto.py b/telegram/inline/inlinequeryresultcachedphoto.py index dd2c5845141..6828f49d44a 100644 --- a/telegram/inline/inlinequeryresultcachedphoto.py +++ b/telegram/inline/inlinequeryresultcachedphoto.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultPhoto""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedPhoto(InlineQueryResult): @@ -68,7 +69,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedPhoto, self).__init__('photo', id) @@ -81,8 +82,7 @@ def __init__(self, self.description = description if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedvideo.py b/telegram/inline/inlinequeryresultcachedvideo.py index 0038adf8c6f..a9f6a8ca686 100644 --- a/telegram/inline/inlinequeryresultcachedvideo.py +++ b/telegram/inline/inlinequeryresultcachedvideo.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultCachedVideo.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedVideo(InlineQueryResult): @@ -68,7 +69,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedVideo, self).__init__('video', id) @@ -80,8 +81,7 @@ def __init__(self, self.description = description if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultcachedvoice.py b/telegram/inline/inlinequeryresultcachedvoice.py index 687be9baeb5..fe295b44d45 100644 --- a/telegram/inline/inlinequeryresultcachedvoice.py +++ b/telegram/inline/inlinequeryresultcachedvoice.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultCachedVoice.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultCachedVoice(InlineQueryResult): @@ -64,7 +65,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultCachedVoice, self).__init__('voice', id) @@ -74,8 +75,7 @@ def __init__(self, # Optionals if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultdocument.py b/telegram/inline/inlinequeryresultdocument.py index bb480e4d519..c3335916986 100644 --- a/telegram/inline/inlinequeryresultdocument.py +++ b/telegram/inline/inlinequeryresultdocument.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultDocument""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultDocument(InlineQueryResult): @@ -82,7 +83,7 @@ def __init__(self, thumb_url=None, thumb_width=None, thumb_height=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultDocument, self).__init__('document', id) @@ -93,8 +94,7 @@ def __init__(self, # Optionals if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if description: self.description = description if reply_markup: diff --git a/telegram/inline/inlinequeryresultgif.py b/telegram/inline/inlinequeryresultgif.py index 53b863f06ad..ba6ddb8d3f7 100644 --- a/telegram/inline/inlinequeryresultgif.py +++ b/telegram/inline/inlinequeryresultgif.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultGif.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultGif(InlineQueryResult): @@ -76,7 +77,7 @@ def __init__(self, reply_markup=None, input_message_content=None, gif_duration=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required @@ -95,8 +96,7 @@ def __init__(self, self.title = title if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultmpeg4gif.py b/telegram/inline/inlinequeryresultmpeg4gif.py index 63610b43a36..49eff09488f 100644 --- a/telegram/inline/inlinequeryresultmpeg4gif.py +++ b/telegram/inline/inlinequeryresultmpeg4gif.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultMpeg4Gif(InlineQueryResult): @@ -77,7 +78,7 @@ def __init__(self, reply_markup=None, input_message_content=None, mpeg4_duration=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required @@ -96,8 +97,7 @@ def __init__(self, self.title = title if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultphoto.py b/telegram/inline/inlinequeryresultphoto.py index 243e6f43a53..a5d6e21e8d9 100644 --- a/telegram/inline/inlinequeryresultphoto.py +++ b/telegram/inline/inlinequeryresultphoto.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultPhoto.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultPhoto(InlineQueryResult): @@ -78,7 +79,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required super(InlineQueryResultPhoto, self).__init__('photo', id) @@ -96,8 +97,7 @@ def __init__(self, self.description = description if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inlinequeryresultvideo.py b/telegram/inline/inlinequeryresultvideo.py index ac885dee4f5..279415bfc2b 100644 --- a/telegram/inline/inlinequeryresultvideo.py +++ b/telegram/inline/inlinequeryresultvideo.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultVideo.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultVideo(InlineQueryResult): @@ -83,7 +84,7 @@ def __init__(self, description=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required @@ -96,8 +97,7 @@ def __init__(self, # Optional if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if video_width: self.video_width = video_width if video_height: diff --git a/telegram/inline/inlinequeryresultvoice.py b/telegram/inline/inlinequeryresultvoice.py index 535d8b6c635..78caff3de3a 100644 --- a/telegram/inline/inlinequeryresultvoice.py +++ b/telegram/inline/inlinequeryresultvoice.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InlineQueryResultVoice.""" from telegram import InlineQueryResult +from telegram.utils.helpers import DEFAULT_NONE class InlineQueryResultVoice(InlineQueryResult): @@ -68,7 +69,7 @@ def __init__(self, caption=None, reply_markup=None, input_message_content=None, - parse_mode=None, + parse_mode=DEFAULT_NONE, **kwargs): # Required @@ -81,8 +82,7 @@ def __init__(self, self.voice_duration = voice_duration if caption: self.caption = caption - if parse_mode: - self.parse_mode = parse_mode + self.parse_mode = parse_mode if reply_markup: self.reply_markup = reply_markup if input_message_content: diff --git a/telegram/inline/inputmessagecontent.py b/telegram/inline/inputmessagecontent.py index f7b706580d2..e1fea9fc188 100644 --- a/telegram/inline/inputmessagecontent.py +++ b/telegram/inline/inputmessagecontent.py @@ -29,4 +29,6 @@ class InputMessageContent(TelegramObject): :class:`telegram.InputVenueMessageContent` for more details. """ - pass + @property + def _has_parse_mode(self): + return hasattr(self, 'parse_mode') diff --git a/telegram/inline/inputtextmessagecontent.py b/telegram/inline/inputtextmessagecontent.py index 3e08d6b978b..de7af87c97b 100644 --- a/telegram/inline/inputtextmessagecontent.py +++ b/telegram/inline/inputtextmessagecontent.py @@ -19,6 +19,7 @@ """This module contains the classes that represent Telegram InputTextMessageContent.""" from telegram import InputMessageContent +from telegram.utils.helpers import DEFAULT_NONE 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=None, + **kwargs): # Required self.message_text = message_text # Optionals diff --git a/telegram/utils/helpers.py b/telegram/utils/helpers.py index ca149e55f71..53e92ed983c 100644 --- a/telegram/utils/helpers.py +++ b/telegram/utils/helpers.py @@ -256,3 +256,112 @@ def decode_user_chat_data_from_json(data): pass tmp[user][key] = value 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) + + # For Python 2.x + __nonzero__ = __bool__ + + +DEFAULT_NONE = DefaultValue(None) +""":class:`DefaultValue`: 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). + + 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). + """ + 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): + self.parse_mode = parse_mode + self.disable_notification = disable_notification + self.disable_web_page_preview = disable_web_page_preview + self.timeout = timeout + + def __hash__(self): + return hash((self.parse_mode, + self.disable_notification, + self.disable_web_page_preview, + self.timeout)) + + def __eq__(self, other): + if isinstance(other, Defaults): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other): + return not self == other diff --git a/tests/conftest.py b/tests/conftest.py index c702b0f639f..5b0417eead0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -30,6 +30,7 @@ from telegram import Bot, Message, User, Chat, MessageEntity, Update, \ InlineQuery, CallbackQuery, ShippingQuery, PreCheckoutQuery, ChosenInlineResult from telegram.ext import Dispatcher, JobQueue, Updater, BaseFilter +from telegram.utils.helpers import Defaults from tests.bots import get_bot TRAVIS = os.getenv('TRAVIS', False) @@ -52,6 +53,28 @@ def 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 {} + + # allow both `default_parse_mode` and `parse_mode` + for kwarg in list(param.keys()): + if kwarg.startswith('default_'): + value = param.pop(kwarg) + param[kwarg[8:]] = value + def_param = {'default_' + k: v for (k, v) in param.items()} + + defaults = Defaults(**param) + default_bot = DEFAULT_BOTS.get(defaults) + if default_bot: + return default_bot + else: + default_bot = make_bot(bot_info, **def_param) + DEFAULT_BOTS[defaults] = default_bot + return default_bot + + @pytest.fixture(scope='session') def chat_id(bot_info): return bot_info['chat_id'] @@ -151,8 +174,8 @@ def pytest_configure(config): # TODO: Write so good code that we don't need to ignore ResourceWarnings anymore -def make_bot(bot_info): - return Bot(bot_info['token'], private_key=PRIVATE_KEY) +def make_bot(bot_info, **kwargs): + return Bot(bot_info['token'], private_key=PRIVATE_KEY, **kwargs) CMD_PATTERN = re.compile(r'/[\da-z_]{1,32}(?:@\w{1,32})?') diff --git a/tests/test_animation.py b/tests/test_animation.py index ae694fde565..ac82934f561 100644 --- a/tests/test_animation.py +++ b/tests/test_animation.py @@ -22,6 +22,7 @@ from flaky import flaky from telegram import PhotoSize, Animation, Voice, TelegramError +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -107,6 +108,39 @@ def test_send_animation_url_file(self, bot, chat_id, animation): assert message.animation.mime_type == animation.mime_type assert message.animation.file_size == animation.file_size + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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) @pytest.mark.timeout(10) def test_resend(self, bot, chat_id, animation): diff --git a/tests/test_audio.py b/tests/test_audio.py index 9433edbd7bc..a189dff5fec 100644 --- a/tests/test_audio.py +++ b/tests/test_audio.py @@ -22,6 +22,7 @@ from flaky import flaky from telegram import Audio, TelegramError, Voice +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -132,6 +133,39 @@ def test(_, url, data, **kwargs): message = bot.send_audio(audio=audio, chat_id=chat_id) assert message + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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): json_dict = {'file_id': 'not a file id', 'duration': self.duration, diff --git a/tests/test_bot.py b/tests/test_bot.py index 5eb58136050..a45b71a182b 100644 --- a/tests/test_bot.py +++ b/tests/test_bot.py @@ -30,7 +30,7 @@ InlineKeyboardButton, InlineQueryResultArticle, InputTextMessageContent, ShippingOption, LabeledPrice, ChatPermissions, Poll) 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() HIGHSCORE_DELTA = 1450000000 @@ -308,6 +308,34 @@ def test_edit_message_text(self, bot, message): assert message.text == 'new_text' + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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') def test_edit_message_text_inline(self): pass @@ -322,6 +350,36 @@ def test_edit_message_caption(self, bot, media_message): # edit_message_media is tested in test_inputmedia + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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) @pytest.mark.timeout(10) def test_edit_message_caption_with_parse_mode(self, bot, media_message): @@ -721,3 +779,22 @@ def request_wrapper(*args, **kwargs): # Test file uploading with pytest.raises(OkException): bot.send_photo(chat_id, open('tests/data/telegram.jpg', 'rb')) + + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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) diff --git a/tests/test_callbackquery.py b/tests/test_callbackquery.py index 842a8bc1858..870d64453b9 100644 --- a/tests/test_callbackquery.py +++ b/tests/test_callbackquery.py @@ -80,15 +80,15 @@ def test_to_dict(self, callback_query): def test_answer(self, monkeypatch, callback_query): 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 assert callback_query.answer() def test_edit_message_text(self, monkeypatch, callback_query): def test(*args, **kwargs): - text = args[1] == 'test' + text = args[0] == 'test' try: id = kwargs['inline_message_id'] == callback_query.inline_message_id return id and text @@ -97,7 +97,7 @@ def test(*args, **kwargs): message_id = kwargs['message_id'] == callback_query.message.message_id 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('test') @@ -112,7 +112,7 @@ def test(*args, **kwargs): message = kwargs['message_id'] == callback_query.message.message_id 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('new caption') @@ -127,7 +127,7 @@ def test(*args, **kwargs): message = kwargs['message_id'] == callback_query.message.message_id 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([['1', '2']]) diff --git a/tests/test_chat.py b/tests/test_chat.py index 23e95806a15..3b39dcd4644 100644 --- a/tests/test_chat.py +++ b/tests/test_chat.py @@ -86,139 +86,139 @@ def test_link(self, chat): def test_send_action(self, monkeypatch, chat): def test(*args, **kwargs): - id = args[1] == chat.id + id = args[0] == chat.id action = kwargs['action'] == ChatAction.TYPING 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) def test_leave(self, monkeypatch, chat): 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() def test_get_administrators(self, monkeypatch, chat): 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() def test_get_members_count(self, monkeypatch, chat): 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() def test_get_member(self, monkeypatch, chat): def test(*args, **kwargs): - chat_id = args[1] == chat.id - user_id = args[2] == 42 + chat_id = args[0] == chat.id + user_id = args[1] == 42 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) def test_kick_member(self, monkeypatch, chat): def test(*args, **kwargs): - chat_id = args[1] == chat.id - user_id = args[2] == 42 + chat_id = args[0] == chat.id + user_id = args[1] == 42 until = kwargs['until_date'] == 43 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) def test_unban_member(self, monkeypatch, chat): def test(*args, **kwargs): - chat_id = args[1] == chat.id - user_id = args[2] == 42 + chat_id = args[0] == chat.id + user_id = args[1] == 42 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) def test_set_permissions(self, monkeypatch, chat): def test(*args, **kwargs): - chat_id = args[1] == chat.id - permissions = args[2] == self.permissions + chat_id = args[0] == chat.id + permissions = args[1] == self.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) def test_instance_method_send_message(self, monkeypatch, chat): 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') def test_instance_method_send_photo(self, monkeypatch, chat): 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') def test_instance_method_send_audio(self, monkeypatch, chat): 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') def test_instance_method_send_document(self, monkeypatch, chat): 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') def test_instance_method_send_sticker(self, monkeypatch, chat): 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') def test_instance_method_send_video(self, monkeypatch, chat): 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') def test_instance_method_send_video_note(self, monkeypatch, chat): 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') def test_instance_method_send_voice(self, monkeypatch, chat): 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') def test_instance_method_send_animation(self, monkeypatch, chat): 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') def test_instance_method_send_poll(self, monkeypatch, chat): 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') def test_equality(self): diff --git a/tests/test_document.py b/tests/test_document.py index 2aa4d5dd7fb..c74c58fa7ab 100644 --- a/tests/test_document.py +++ b/tests/test_document.py @@ -22,6 +22,7 @@ from flaky import flaky from telegram import Document, PhotoSize, TelegramError, Voice +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -123,6 +124,39 @@ def test(_, url, data, **kwargs): assert message + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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): json_dict = {'file_id': 'not a file id', 'thumb': document.thumb.to_dict(), diff --git a/tests/test_inlinequery.py b/tests/test_inlinequery.py index a3f2fd481ad..eb59c3faa3e 100644 --- a/tests/test_inlinequery.py +++ b/tests/test_inlinequery.py @@ -63,9 +63,9 @@ def test_to_dict(self, inline_query): def test_answer(self, monkeypatch, inline_query): 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() def test_equality(self): diff --git a/tests/test_message.py b/tests/test_message.py index 6aaf63a9e88..4af714302c5 100644 --- a/tests/test_message.py +++ b/tests/test_message.py @@ -328,15 +328,15 @@ def test_effective_attachment(self, message_params): def test_reply_text(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id - text = args[2] == 'test' + id = args[0] == message.chat_id + text = args[1] == 'test' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id else: reply = True 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', quote=True) assert message.reply_text('test', reply_to_message_id=message.message_id, quote=True) @@ -347,8 +347,8 @@ def test_reply_markdown(self, monkeypatch, message): 'http://google.com') def test(*args, **kwargs): - cid = args[1] == message.chat_id - markdown_text = args[2] == test_md_string + cid = args[0] == message.chat_id + markdown_text = args[1] == test_md_string markdown_enabled = kwargs['parse_mode'] == ParseMode.MARKDOWN if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -359,7 +359,7 @@ def test(*args, **kwargs): text_markdown = self.test_message.text_markdown 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, quote=True) assert message.reply_markdown(self.test_message.text_markdown, @@ -373,8 +373,8 @@ def test_reply_html(self, monkeypatch, message): '
pre. http://google.com') def test(*args, **kwargs): - cid = args[1] == message.chat_id - html_text = args[2] == test_html_string + cid = args[0] == message.chat_id + html_text = args[1] == test_html_string html_enabled = kwargs['parse_mode'] == ParseMode.HTML if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -385,7 +385,7 @@ def test(*args, **kwargs): text_html = self.test_message.text_html 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, quote=True) assert message.reply_html(self.test_message.text_html, @@ -394,7 +394,7 @@ def test(*args, **kwargs): def test_reply_media_group(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id media = kwargs['media'] == 'reply_media_group' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -402,13 +402,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_photo(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id photo = kwargs['photo'] == 'test_photo' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -416,13 +416,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_audio(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id audio = kwargs['audio'] == 'test_audio' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -430,13 +430,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_document(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id document = kwargs['document'] == 'test_document' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -444,13 +444,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_animation(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id animation = kwargs['animation'] == 'test_animation' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -458,13 +458,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_sticker(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id sticker = kwargs['sticker'] == 'test_sticker' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -472,13 +472,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_video(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id video = kwargs['video'] == 'test_video' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -486,13 +486,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_video_note(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id video_note = kwargs['video_note'] == 'test_video_note' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -500,13 +500,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_voice(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id voice = kwargs['voice'] == 'test_voice' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -514,13 +514,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_location(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id location = kwargs['location'] == 'test_location' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -528,13 +528,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_venue(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id venue = kwargs['venue'] == 'test_venue' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -542,13 +542,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_contact(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id contact = kwargs['contact'] == 'test_contact' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -556,13 +556,13 @@ def test(*args, **kwargs): reply = True 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', quote=True) def test_reply_poll(self, monkeypatch, message): def test(*args, **kwargs): - id = args[1] == message.chat_id + id = args[0] == message.chat_id contact = kwargs['contact'] == 'test_poll' if kwargs.get('reply_to_message_id'): reply = kwargs['reply_to_message_id'] == message.message_id @@ -570,7 +570,7 @@ def test(*args, **kwargs): reply = True 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', quote=True) @@ -585,7 +585,7 @@ def test(*args, **kwargs): notification = True 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, disable_notification=True) assert not message.forward(635241) @@ -597,7 +597,7 @@ def test(*args, **kwargs): text = kwargs['text'] == 'test' 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') def test_edit_caption(self, monkeypatch, message): @@ -607,7 +607,7 @@ def test(*args, **kwargs): caption = kwargs['caption'] == 'new 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') def test_edit_media(self, monkeypatch, message): @@ -617,7 +617,7 @@ def test(*args, **kwargs): media = kwargs['media'] == 'my_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') def test_edit_reply_markup(self, monkeypatch, message): @@ -627,7 +627,7 @@ def test(*args, **kwargs): reply_markup = kwargs['reply_markup'] == [['1', '2']] 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']]) def test_delete(self, monkeypatch, message): @@ -636,7 +636,7 @@ def test(*args, **kwargs): message_id = kwargs['message_id'] == message.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() def test_equality(self): diff --git a/tests/test_passport.py b/tests/test_passport.py index 276fc2a3be9..9228f04eef4 100644 --- a/tests/test_passport.py +++ b/tests/test_passport.py @@ -296,9 +296,9 @@ def test_mocked_download_passport_file(self, passport_data, monkeypatch): selfie = passport_data.decrypted_data[1].selfie 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() assert file.file_id == selfie.file_id assert file._credentials.file_hash == self.driver_license_selfie_credentials_file_hash diff --git a/tests/test_photo.py b/tests/test_photo.py index 9a3d8aee6b9..a7d6bbede11 100644 --- a/tests/test_photo.py +++ b/tests/test_photo.py @@ -23,6 +23,7 @@ from flaky import flaky from telegram import Sticker, TelegramError, PhotoSize, InputFile +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -139,6 +140,39 @@ def test_send_photo_parse_mode_html(self, bot, chat_id, photo_file, thumb, photo assert message.caption == TestPhoto.caption.replace('', '').replace('', '') assert len(message.caption_entities) == 1 + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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) @pytest.mark.timeout(10) def test_get_and_download(self, bot, photo): diff --git a/tests/test_precheckoutquery.py b/tests/test_precheckoutquery.py index cf5a2127069..64b85ffde40 100644 --- a/tests/test_precheckoutquery.py +++ b/tests/test_precheckoutquery.py @@ -77,9 +77,9 @@ def test_to_dict(self, pre_checkout_query): def test_answer(self, monkeypatch, pre_checkout_query): 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() def test_equality(self): diff --git a/tests/test_shippingquery.py b/tests/test_shippingquery.py index d88bfa84e6e..5fd572a3fb0 100644 --- a/tests/test_shippingquery.py +++ b/tests/test_shippingquery.py @@ -63,9 +63,9 @@ def test_to_dict(self, shipping_query): def test_answer(self, monkeypatch, shipping_query): 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() def test_equality(self): diff --git a/tests/test_updater.py b/tests/test_updater.py index 1da48b89c68..a23d15c06e1 100644 --- a/tests/test_updater.py +++ b/tests/test_updater.py @@ -79,8 +79,8 @@ def test_get_updates_normal_err(self, monkeypatch, updater, error): def test(*args, **kwargs): raise error - monkeypatch.setattr('telegram.Bot.get_updates', test) - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) + monkeypatch.setattr(updater.bot, 'get_updates', test) + monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) updater.dispatcher.add_error_handler(self.error_handler) updater.start_polling(0.01) @@ -99,8 +99,8 @@ def test(*args, **kwargs): raise error with caplog.at_level(logging.DEBUG): - monkeypatch.setattr('telegram.Bot.get_updates', test) - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) + monkeypatch.setattr(updater.bot, 'get_updates', test) + monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) updater.dispatcher.add_error_handler(self.error_handler) updater.start_polling(0.01) assert self.err_handler_called.wait(1) is not True @@ -127,8 +127,8 @@ def test(*args, **kwargs): event.set() raise error - monkeypatch.setattr('telegram.Bot.get_updates', test) - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) + monkeypatch.setattr(updater.bot, 'get_updates', test) + monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) updater.dispatcher.add_error_handler(self.error_handler) updater.start_polling(0.01) @@ -144,8 +144,8 @@ def test(*args, **kwargs): def test_webhook(self, monkeypatch, updater): q = Queue() - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) - monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) + 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' @@ -182,8 +182,8 @@ def test_webhook(self, monkeypatch, updater): updater.stop() def test_webhook_ssl(self, monkeypatch, updater): - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) - monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) + monkeypatch.setattr(updater.bot, 'set_webhook', lambda *args, **kwargs: True) + monkeypatch.setattr(updater.bot, 'delete_webhook', lambda *args, **kwargs: True) ip = '127.0.0.1' port = randrange(1024, 49152) # Select random port for travis tg_err = False @@ -204,8 +204,8 @@ def test_webhook_ssl(self, monkeypatch, updater): def test_webhook_no_ssl(self, monkeypatch, updater): q = Queue() - monkeypatch.setattr('telegram.Bot.set_webhook', lambda *args, **kwargs: True) - monkeypatch.setattr('telegram.Bot.delete_webhook', lambda *args, **kwargs: True) + 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' @@ -227,12 +227,12 @@ def test_webhook_no_ssl(self, monkeypatch, updater): def test_bootstrap_retries_success(self, monkeypatch, updater, error): retries = 2 - def attempt(_, *args, **kwargs): + def attempt(*args, **kwargs): if self.attempts < retries: self.attempts += 1 raise error - monkeypatch.setattr('telegram.Bot.set_webhook', attempt) + monkeypatch.setattr(updater.bot, 'set_webhook', attempt) updater.running = True updater._bootstrap(retries, False, 'path', None, bootstrap_interval=0) @@ -246,11 +246,11 @@ def attempt(_, *args, **kwargs): def test_bootstrap_retries_error(self, monkeypatch, updater, error, attempts): retries = 1 - def attempt(_, *args, **kwargs): + def attempt(*args, **kwargs): self.attempts += 1 raise error - monkeypatch.setattr('telegram.Bot.set_webhook', attempt) + monkeypatch.setattr(updater.bot, 'set_webhook', attempt) updater.running = True with pytest.raises(type(error)): diff --git a/tests/test_user.py b/tests/test_user.py index cdcdea50f29..da73a15f8d8 100644 --- a/tests/test_user.py +++ b/tests/test_user.py @@ -103,73 +103,73 @@ def test_link(self, user): assert user.link is None def test_get_profile_photos(self, monkeypatch, user): - def test(_, *args, **kwargs): + def test(*args, **kwargs): 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() def test_instance_method_send_message(self, monkeypatch, user): 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') def test_instance_method_send_photo(self, monkeypatch, user): 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') def test_instance_method_send_audio(self, monkeypatch, user): 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') def test_instance_method_send_document(self, monkeypatch, user): 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') def test_instance_method_send_sticker(self, monkeypatch, user): 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') def test_instance_method_send_video(self, monkeypatch, user): 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') def test_instance_method_send_video_note(self, monkeypatch, user): 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') def test_instance_method_send_voice(self, monkeypatch, user): 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') def test_instance_method_send_animation(self, monkeypatch, user): 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') def test_mention_html(self, user): diff --git a/tests/test_video.py b/tests/test_video.py index 2e009ff68b1..e5922715b3f 100644 --- a/tests/test_video.py +++ b/tests/test_video.py @@ -22,6 +22,7 @@ from flaky import flaky from telegram import Video, TelegramError, Voice, PhotoSize +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -141,6 +142,39 @@ def test(_, url, data, **kwargs): message = bot.send_video(chat_id, video=video) assert message + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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): json_dict = { 'file_id': 'not a file id', diff --git a/tests/test_voice.py b/tests/test_voice.py index 407bf66f708..d52fea6b00a 100644 --- a/tests/test_voice.py +++ b/tests/test_voice.py @@ -22,6 +22,7 @@ from flaky import flaky from telegram import Audio, Voice, TelegramError +from telegram.utils.helpers import escape_markdown @pytest.fixture(scope='function') @@ -111,6 +112,39 @@ def test(_, url, data, **kwargs): message = bot.send_voice(chat_id, voice=voice) assert message + @flaky(3, 1) + @pytest.mark.timeout(10) + @pytest.mark.parametrize('default_bot', [{'default_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', [{'default_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', [{'default_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): json_dict = { 'file_id': 'not a file id',