Skip to content

Commit 44b922e

Browse files
committed
Added tests and more elaborate documentation for autowire
1 parent 10e4aee commit 44b922e

23 files changed

+305
-50
lines changed

telegram/ext/callbackqueryhandler.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ class CallbackQueryHandler(Handler):
3333
3434
Attributes:
3535
callback (:obj:`callable`): The callback function for this handler.
36+
autowire (:obj:`bool`): Optional. Determines whether objects will be passed to the
37+
callback function automatically.
3638
pass_update_queue (:obj:`bool`): Optional. Determines whether ``update_queue`` will be
3739
passed to the callback function.
3840
pass_job_queue (:obj:`bool`): Optional. Determines whether ``job_queue`` will be passed to
@@ -58,6 +60,10 @@ class CallbackQueryHandler(Handler):
5860
callback (:obj:`callable`): A function that takes ``bot, update`` as positional arguments.
5961
It will be called when the :attr:`check_update` has determined that an update should be
6062
processed by this handler.
63+
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
64+
inspected for positional arguments and be passed objects whose names match any of the
65+
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
66+
``autowire`` will yield a warning.
6167
pass_update_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
6268
``update_queue`` will be passed to the callback function. It will be the ``Queue``
6369
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
@@ -72,25 +78,13 @@ class CallbackQueryHandler(Handler):
7278
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
7379
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
7480
Default is ``False``
75-
pass_groupdict (:obj:`bool`, import inspect
76-
77-
try:
78-
def inspect_arguments(func):
79-
args, _, _, defaults = inspect.getargspec(func)
80-
# Filter out positional arguments
81-
kwargs = args[:-len(defaults)]
82-
return kwargs
83-
except Warning: # `getargspec()` is deprecated in Python3
84-
def inspect_arguments(func):
85-
_, varargs, _, _, _, _, _ = inspect.getfullargspec(func)
86-
return varargsoptional): If the callback should be passed the result of
81+
pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of
8782
``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``.
8883
Default is ``False``
8984
pass_user_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
9085
``user_data`` will be passed to the callback function. Default is ``False``.
9186
pass_chat_data (:obj:`bool`, optional): If set to ``True``, a keyword argument called
9287
``chat_data`` will be passed to the callback function. Default is ``False``.
93-
9488
"""
9589

9690
def __init__(self,
@@ -119,7 +113,8 @@ def __init__(self,
119113
self.pass_groupdict = pass_groupdict
120114

121115
if self.autowire:
122-
self.set_autowired_flags(passable={'groups', 'groupdict', 'user_data', 'chat_data'})
116+
self.set_autowired_flags(passable={'groups', 'groupdict', 'user_data',
117+
'chat_data', 'update_queue', 'job_queue'})
123118

124119
def check_update(self, update):
125120
"""Determines whether an update should be passed to this handlers :attr:`callback`.
@@ -147,6 +142,7 @@ def handle_update(self, update, dispatcher):
147142
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
148143
149144
"""
145+
positional_args = self.collect_bot_update_args(dispatcher, update)
150146
optional_args = self.collect_optional_args(dispatcher, update)
151147

152148
if self.pattern:
@@ -157,4 +153,4 @@ def handle_update(self, update, dispatcher):
157153
if self.pass_groupdict:
158154
optional_args['groupdict'] = match.groupdict()
159155

160-
return self.callback(dispatcher.bot, update, **optional_args)
156+
return self.callback(*positional_args, **optional_args)

telegram/ext/choseninlineresulthandler.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ChosenInlineResultHandler(Handler):
5050
It will be called when the :attr:`check_update` has determined that an update should be
5151
processed by this handler.
5252
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
53-
inspected for positional arguments and pass objects whose names match any of the
53+
inspected for positional arguments and be passed objects whose names match any of the
5454
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
5555
``autowire`` will yield a warning.
5656
pass_update_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
@@ -105,9 +105,10 @@ def handle_update(self, update, dispatcher):
105105
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
106106
107107
"""
108+
positional_args = self.collect_bot_update_args(dispatcher, update)
108109
optional_args = self.collect_optional_args(dispatcher, update)
109110

110-
return self.callback(dispatcher.bot, update, **optional_args)
111+
return self.callback(*positional_args, **optional_args)
111112

112113
# old non-PEP8 Handler methods
113114
m = "telegram.ChosenInlineResultHandler."

telegram/ext/commandhandler.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class CommandHandler(Handler):
7171
allow_edited (:obj:`bool`, optional): Determines whether the handler should also accept
7272
edited messages. Default is ``False``.
7373
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
74-
inspected for positional arguments and pass objects whose names match any of the
74+
inspected for positional arguments and be passed objects whose names match any of the
7575
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
7676
``autowire`` will yield a warning.
7777
pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the
@@ -172,12 +172,12 @@ def handle_update(self, update, dispatcher):
172172
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
173173
174174
"""
175-
self.set_autowired_flags({'args', 'update_queue', 'job_queue', 'user_data', 'chat_data'})
175+
positional_args = self.collect_bot_update_args(dispatcher, update)
176176
optional_args = self.collect_optional_args(dispatcher, update)
177177

178178
message = update.message or update.edited_message
179179

180180
if self.pass_args:
181181
optional_args['args'] = message.text.split()[1:]
182182

183-
return self.callback(dispatcher.bot, update, **optional_args)
183+
return self.callback(*positional_args, **optional_args)

telegram/ext/handler.py

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,12 @@
2323

2424

2525
class Handler(object):
26-
"""The base class for all update handlers. Create custom handlers by inheriting from it.
26+
"""
27+
The base class for all update handlers. Create custom handlers by inheriting from it.
28+
29+
If your subclass needs the *autowiring* functionality, make sure to call ``set_autowired_flags``
30+
**after** initializing the ``pass_*`` members. The ``passable`` argument to this method denotes
31+
all the flags your Handler supports, e.g. ``{'update_queue', 'job_queue', 'args'}``.
2732
2833
Attributes:
2934
callback (:obj:`callable`): The callback function for this handler.
@@ -49,10 +54,9 @@ class Handler(object):
4954
It will be called when the :attr:`check_update` has determined that an update should be
5055
processed by this handler.
5156
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
52-
inspected for positional arguments and pass objects whose names match any of the
57+
inspected for positional arguments and be passed objects whose names match any of the
5358
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
54-
``autowire`` will yield
55-
a warning.
59+
``autowire`` will yield a warning.
5660
pass_update_queue (:obj:`bool`, optional): If set to ``True``, a keyword argument called
5761
``update_queue`` will be passed to the callback function. It will be the ``Queue``
5862
instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher`
@@ -116,7 +120,7 @@ def handle_update(self, update, dispatcher):
116120
def __get_available_pass_flags(self):
117121
"""
118122
Used to provide warnings if the user decides to use `autowire` in conjunction with
119-
`pass_*` flags, and to recalculate all flags.
123+
``pass_*`` flags, and to recalculate all flags.
120124
121125
Getting objects dynamically is better than hard-coding all passable objects and setting
122126
them to False in here, because the base class should not know about the existence of
@@ -126,9 +130,15 @@ def __get_available_pass_flags(self):
126130

127131
def set_autowired_flags(self, passable={'update_queue', 'job_queue', 'user_data', 'chat_data'}):
128132
"""
133+
This method inspects the callback handler for used arguments. If it finds arguments that
134+
are ``passable``, i.e. types that can also be passed by the various ``pass_*`` flags,
135+
it sets the according flags to true.
136+
137+
If the handler signature is prone to change at runtime for whatever reason, you can call
138+
this method again to recalculate the flags to use.
129139
130-
Make the passable arguments explicit as opposed to dynamically generated to be absolutely
131-
safe that no arguments will be passed that are not allowed.
140+
The ``passable`` arguments are required to be explicit as opposed to dynamically generated
141+
to be absolutely safe that no arguments will be passed that are not allowed.
132142
"""
133143

134144
if not self.autowire:
@@ -192,7 +202,8 @@ def collect_optional_args(self, dispatcher, update=None):
192202
optional_args = dict()
193203

194204
if self.autowire:
195-
# Subclasses are responsible for calling `set_autowired_flags` in their __init__
205+
# Subclasses are responsible for calling `set_autowired_flags`
206+
# at the end of their __init__
196207
assert self._autowire_initialized
197208

198209
if self.pass_update_queue:
@@ -209,6 +220,20 @@ def collect_optional_args(self, dispatcher, update=None):
209220
return optional_args
210221

211222
def collect_bot_update_args(self, dispatcher, update):
223+
"""
224+
Prepares the positional arguments ``bot`` and/or ``update`` that are required for every
225+
python-telegram-bot handler that is not **autowired**. If ``autowire`` is set to ``True``,
226+
this method uses the inspected callback arguments to decide whether bot or update,
227+
respectively, need to be passed. The order is always (bot, update).
228+
229+
230+
Args:
231+
dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher.
232+
update (:class:`telegram.Update`): The update.
233+
234+
Returns:
235+
A tuple of bot, update, or both
236+
"""
212237
if self.autowire:
213238
# Subclasses are responsible for calling `set_autowired_flags` in their __init__
214239
assert self._autowire_initialized
@@ -218,6 +243,6 @@ def collect_bot_update_args(self, dispatcher, update):
218243
positional_args.append(dispatcher.bot)
219244
if 'update' in self._callback_args:
220245
positional_args.append(update)
221-
return positional_args
246+
return tuple(positional_args)
222247
else:
223248
return (dispatcher.bot, update)

telegram/ext/inlinequeryhandler.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,14 @@ class InlineQueryHandler(Handler):
3333
3434
Attributes:
3535
callback (:obj:`callable`): The callback function for this handler.
36+
pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test
37+
:attr:`telegram.InlineQuery.query` against.
3638
autowire (:obj:`bool`): Optional. Determines whether objects will be passed to the
3739
callback function automatically.
3840
pass_update_queue (:obj:`bool`): Optional. Determines whether ``update_queue`` will be
3941
passed to the callback function.
4042
pass_job_queue (:obj:`bool`): Optional. Determines whether ``job_queue`` will be passed to
4143
the callback function.
42-
pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test
43-
:attr:`telegram.InlineQuery.query` against.
4444
pass_groups (:obj:`bool`): Optional. Determines whether ``groups`` will be passed to the
4545
callback function.
4646
pass_groupdict (:obj:`bool`): Optional. Determines whether ``groupdict``. will be passed to
@@ -60,8 +60,11 @@ class InlineQueryHandler(Handler):
6060
callback (:obj:`callable`): A function that takes ``bot, update`` as positional arguments.
6161
It will be called when the :attr:`check_update` has determined that an update should be
6262
processed by this handler.
63+
pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not ``None``,
64+
``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update
65+
should be handled by this handler.
6366
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
64-
inspected for positional arguments and pass objects whose names match any of the
67+
inspected for positional arguments and be passed objects whose names match any of the
6568
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
6669
``autowire`` will yield
6770
a warning.
@@ -73,9 +76,6 @@ class InlineQueryHandler(Handler):
7376
``job_queue`` will be passed to the callback function. It will be a
7477
:class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater`
7578
which can be used to schedule new jobs. Default is ``False``.
76-
pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not ``None``,
77-
``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update
78-
should be handled by this handler.
7979
pass_groups (:obj:`bool`, optional): If the callback should be passed the result of
8080
``re.match(pattern, data).groups()`` as a keyword argument called ``groups``.
8181
Default is ``False``
@@ -90,8 +90,8 @@ class InlineQueryHandler(Handler):
9090

9191
def __init__(self,
9292
callback,
93-
autowire=False,
9493
pattern=None,
94+
autowire=False,
9595
pass_update_queue=False,
9696
pass_job_queue=False,
9797
pass_groups=False,
@@ -113,7 +113,8 @@ def __init__(self,
113113
self.pass_groups = pass_groups
114114
self.pass_groupdict = pass_groupdict
115115
if self.autowire:
116-
self.set_autowired_flags(passable={'groups', 'groupdict', 'user_data', 'chat_data'})
116+
self.set_autowired_flags(passable={'update_queue', 'job_queue', 'user_data',
117+
'chat_data', 'groups', 'groupdict'})
117118

118119
def check_update(self, update):
119120
"""
@@ -142,7 +143,7 @@ def handle_update(self, update, dispatcher):
142143
update (:class:`telegram.Update`): Incoming telegram update.
143144
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
144145
"""
145-
146+
positional_args = self.collect_bot_update_args(dispatcher, update)
146147
optional_args = self.collect_optional_args(dispatcher, update)
147148

148149
if self.pattern:
@@ -153,7 +154,7 @@ def handle_update(self, update, dispatcher):
153154
if self.pass_groupdict:
154155
optional_args['groupdict'] = match.groupdict()
155156

156-
return self.callback(dispatcher.bot, update, **optional_args)
157+
return self.callback(*positional_args, **optional_args)
157158

158159
# old non-PEP8 Handler methods
159160
m = "telegram.InlineQueryHandler."

telegram/ext/messagehandler.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class MessageHandler(Handler):
6565
It will be called when the :attr:`check_update` has determined that an update should be
6666
processed by this handler.
6767
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
68-
inspected for positional arguments and pass objects whose names match any of the
68+
inspected for positional arguments and be passed objects whose names match any of the
6969
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
7070
``autowire`` will yield
7171
a warning.

telegram/ext/precheckoutqueryhandler.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class PreCheckoutQueryHandler(Handler):
4949
It will be called when the :attr:`check_update` has determined that an update should be
5050
processed by this handler.
5151
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
52-
inspected for positional arguments and pass objects whose names match any of the
52+
inspected for positional arguments and be passed objects whose names match any of the
5353
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
5454
``autowire`` will yield
5555
a warning.
@@ -105,5 +105,7 @@ def handle_update(self, update, dispatcher):
105105
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
106106
107107
"""
108+
positional_args = self.collect_bot_update_args(dispatcher, update)
108109
optional_args = self.collect_optional_args(dispatcher, update)
109-
return self.callback(dispatcher.bot, update, **optional_args)
110+
111+
return self.callback(*positional_args, **optional_args)

telegram/ext/regexhandler.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class RegexHandler(Handler):
6565
It will be called when the :attr:`check_update` has determined that an update should be
6666
processed by this handler.
6767
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
68-
inspected for positional arguments and pass objects whose names match any of the
68+
inspected for positional arguments and be passed objects whose names match any of the
6969
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
7070
``autowire`` will yield
7171
a warning.
@@ -173,6 +173,7 @@ def handle_update(self, update, dispatcher):
173173
174174
"""
175175

176+
positional_args = self.collect_bot_update_args(dispatcher, update)
176177
optional_args = self.collect_optional_args(dispatcher, update)
177178
match = re.match(self.pattern, update.effective_message.text)
178179

@@ -181,4 +182,4 @@ def handle_update(self, update, dispatcher):
181182
if self.pass_groupdict:
182183
optional_args['groupdict'] = match.groupdict()
183184

184-
return self.callback(dispatcher.bot, update, **optional_args)
185+
return self.callback(*positional_args, **optional_args)

telegram/ext/shippingqueryhandler.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class ShippingQueryHandler(Handler):
4949
It will be called when the :attr:`check_update` has determined that an update should be
5050
processed by this handler.
5151
autowire (:obj:`bool`, optional): If set to ``True``, your callback handler will be
52-
inspected for positional arguments and pass objects whose names match any of the
52+
inspected for positional arguments and be passed objects whose names match any of the
5353
``pass_*`` flags of this Handler. Using any ``pass_*`` argument in conjunction with
5454
``autowire`` will yield
5555
a warning.
@@ -105,5 +105,6 @@ def handle_update(self, update, dispatcher):
105105
dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update.
106106
107107
"""
108+
positional_args = self.collect_bot_update_args(dispatcher, update)
108109
optional_args = self.collect_optional_args(dispatcher, update)
109-
return self.callback(dispatcher.bot, update, **optional_args)
110+
return self.callback(*positional_args, **optional_args)

0 commit comments

Comments
 (0)