Skip to content
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
8 changes: 0 additions & 8 deletions docs/source/telegram.chatmemberbanned.rst
Original file line number Diff line number Diff line change
@@ -1,8 +0,0 @@
:github_url: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/telegram/chatmember.py

telegram.ChatMemberBanned
=========================

.. autoclass:: telegram.ChatMemberBanned
:members:
:show-inheritance:
5 changes: 4 additions & 1 deletion telegram/ext/callbackqueryhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ class CallbackQueryHandler(Handler[Update, CCT]):
Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
5 changes: 4 additions & 1 deletion telegram/ext/chatmemberhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ class ChatMemberHandler(Handler[Update, CCT]):
Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
5 changes: 4 additions & 1 deletion telegram/ext/choseninlineresulthandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,10 @@ class ChosenInlineResultHandler(Handler[Update, CCT]):
Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
10 changes: 8 additions & 2 deletions telegram/ext/commandhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ class CommandHandler(Handler[Update, CCT]):
Limitations are the same as described here https://core.telegram.org/bots#commands
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down Expand Up @@ -212,7 +215,10 @@ class PrefixHandler(CommandHandler):
The command or list of commands this handler should listen for.
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
126 changes: 59 additions & 67 deletions telegram/ext/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@

class DispatcherHandlerStop(Exception):
"""
Raise this in handler to prevent execution of any other handler (even in different group).
Raise this in handler or error handler to prevent execution of any other handler (even in
different group).

In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the
optional ``state`` parameter instead of returning the next state:
Expand All @@ -73,6 +74,9 @@ def callback(update, context):
...
raise DispatcherHandlerStop(next_state)

Note:
Has no effect, if the handler or error handler is run asynchronously.

Attributes:
state (:obj:`object`): Optional. The next state of the conversation.

Expand Down Expand Up @@ -320,15 +324,16 @@ def _pooled(self) -> None:

# Avoid infinite recursion of error handlers.
if promise.pooled_function in self.error_handlers:
self.logger.error('An uncaught error was raised while handling the error.')
self.logger.exception(
'An error was raised and an uncaught error was raised while '
'handling the error with an error_handler.',
exc_info=promise.exception,
)
continue

# If we arrive here, an exception happened in the promise and was neither
# DispatcherHandlerStop nor raised by an error handler. So we can and must handle it
try:
self.dispatch_error(promise.update, promise.exception, promise=promise)
except Exception:
self.logger.exception('An uncaught error was raised while handling the error.')
self.dispatch_error(promise.update, promise.exception, promise=promise)

def run_async(
self, func: Callable[..., object], *args: object, update: object = None, **kwargs: object
Expand Down Expand Up @@ -452,10 +457,7 @@ def process_update(self, update: object) -> None:
"""
# An error happened while polling
if isinstance(update, TelegramError):
try:
self.dispatch_error(None, update)
except Exception:
self.logger.exception('An uncaught error was raised while handling the error.')
self.dispatch_error(None, update)
return

context = None
Expand Down Expand Up @@ -483,14 +485,9 @@ def process_update(self, update: object) -> None:

# Dispatch any error.
except Exception as exc:
try:
self.dispatch_error(update, exc)
except DispatcherHandlerStop:
self.logger.debug('Error handler stopped further handlers')
if self.dispatch_error(update, exc):
self.logger.debug('Error handler stopped further handlers.')
break
# Errors should not stop the thread.
except Exception:
self.logger.exception('An uncaught error was raised while handling the error.')

# Update persistence, if handled
handled_only_async = all(sync_modes)
Expand Down Expand Up @@ -606,76 +603,44 @@ def __update_persistence(self, update: object = None) -> None:
self.bot.callback_data_cache.persistence_data
)
except Exception as exc:
try:
self.dispatch_error(update, exc)
except Exception:
message = (
'Saving callback data raised an error and an '
'uncaught error was raised while handling '
'the error with an error_handler'
)
self.logger.exception(message)
self.dispatch_error(update, exc)
if self.persistence.store_data.bot_data:
try:
self.persistence.update_bot_data(self.bot_data)
except Exception as exc:
try:
self.dispatch_error(update, exc)
except Exception:
message = (
'Saving bot data raised an error and an '
'uncaught error was raised while handling '
'the error with an error_handler'
)
self.logger.exception(message)
self.dispatch_error(update, exc)
if self.persistence.store_data.chat_data:
for chat_id in chat_ids:
try:
self.persistence.update_chat_data(chat_id, self.chat_data[chat_id])
except Exception as exc:
try:
self.dispatch_error(update, exc)
except Exception:
message = (
'Saving chat data raised an error and an '
'uncaught error was raised while handling '
'the error with an error_handler'
)
self.logger.exception(message)
self.dispatch_error(update, exc)
if self.persistence.store_data.user_data:
for user_id in user_ids:
try:
self.persistence.update_user_data(user_id, self.user_data[user_id])
except Exception as exc:
try:
self.dispatch_error(update, exc)
except Exception:
message = (
'Saving user data raised an error and an '
'uncaught error was raised while handling '
'the error with an error_handler'
)
self.logger.exception(message)
self.dispatch_error(update, exc)

def add_error_handler(
self,
callback: Callable[[object, CCT], None],
run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, # pylint: disable=W0621
) -> None:
"""Registers an error handler in the Dispatcher. This handler will receive every error
which happens in your bot.
which happens in your bot. See the docs of :meth:`dispatch_error` for more details on how
errors are handled.

Note:
Attempts to add the same callback multiple times will be ignored.

Warning:
The errors handled within these handlers won't show up in the logger, so you
need to make sure that you reraise the error.

Args:
callback (:obj:`callable`): The callback function for this error handler. Will be
called when an error is raised.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The error that happened will be present in context.error.
run_async (:obj:`bool`, optional): Whether this handlers callback should be run
Expand All @@ -700,19 +665,35 @@ def remove_error_handler(self, callback: Callable[[object, CCT], None]) -> None:
self.error_handlers.pop(callback, None)

def dispatch_error(
self, update: Optional[object], error: Exception, promise: Promise = None
) -> None:
"""Dispatches an error.
self,
update: Optional[object],
error: Exception,
promise: Promise = None,
) -> bool:
"""Dispatches an error by passing it to all error handlers registered with
:meth:`add_error_handler`. If one of the error handlers raises
:class:`telegram.ext.DispatcherHandlerStop`, the update will not be handled by other error
handler or handlers (even in other groups). All other exceptions raised by an error handler
will be logged.

.. versionchanged:: 14.0
* Exceptions raised by error handlers are now properly logged.
* :class:`telegram.ext.DispatcherHandlerStop` is no longer reraised but converted into
the return value.

Args:
update (:obj:`object` | :class:`telegram.Update`): The update that caused the error.
error (:obj:`Exception`): The error that was raised.
promise (:class:`telegram.utils.Promise`, optional): The promise whose pooled function
raised the error.

Returns:
:obj:`bool`: :obj:`True` if one of the error handlers raised
:class:`telegram.ext.DispatcherHandlerStop`. :obj:`False`, otherwise.
"""
async_args = None if not promise else promise.args
async_kwargs = None if not promise else promise.kwargs
dispatcher_handler_stop = False

if self.error_handlers:
for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621
Expand All @@ -722,9 +703,20 @@ def dispatch_error(
if run_async:
self.run_async(callback, update, context, update=update)
else:
callback(update, context)
try:
callback(update, context)
except DispatcherHandlerStop:
dispatcher_handler_stop = True
break
except Exception as exc:
self.logger.exception(
'An error was raised and an uncaught error was raised while '
'handling the error with an error_handler.',
exc_info=exc,
)
return dispatcher_handler_stop

else:
self.logger.exception(
'No error handlers are registered, logging exception.', exc_info=error
)
self.logger.exception(
'No error handlers are registered, logging exception.', exc_info=error
)
return False
5 changes: 4 additions & 1 deletion telegram/ext/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ class Handler(Generic[UT, CCT], ABC):
Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
5 changes: 4 additions & 1 deletion telegram/ext/inlinequeryhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,10 @@ class InlineQueryHandler(Handler[Update, CCT]):
Args:
callback (:obj:`callable`): The callback function for this handler. Will be called when
:attr:`check_update` has determined that an update should be processed by this handler.
Callback signature: ``def callback(update: Update, context: CallbackContext)``
Callback signature:


``def callback(update: Update, context: CallbackContext)``

The return value of the callback is usually ignored except for the special case of
:class:`telegram.ext.ConversationHandler`.
Expand Down
Loading