Skip to content

WIP: Default values #1585

New issue

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

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

Already on GitHub? Sign in to your account

Closed
wants to merge 16 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ future>=0.16.0
certifi
tornado>=5.1
cryptography
decorator>=4.4.0
86 changes: 79 additions & 7 deletions telegram/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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())
Expand All @@ -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):
Expand All @@ -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'

Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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}
Expand Down
20 changes: 18 additions & 2 deletions telegram/ext/updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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.
Expand All @@ -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):
Expand Down Expand Up @@ -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()
Expand Down
32 changes: 17 additions & 15 deletions telegram/files/inputmedia.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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'

Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -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):
Expand All @@ -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:
Expand Down Expand Up @@ -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'

Expand All @@ -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:
Expand Down Expand Up @@ -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):
Expand All @@ -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
8 changes: 8 additions & 0 deletions telegram/inline/inlinequeryresult.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
6 changes: 3 additions & 3 deletions telegram/inline/inlinequeryresultaudio.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions telegram/inline/inlinequeryresultcachedaudio.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down
6 changes: 3 additions & 3 deletions telegram/inline/inlinequeryresultcacheddocument.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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)
Expand All @@ -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:
Expand Down
Loading