Description
Steps to reproduce
- At the lowest level, create a
telegram.ext.utils.Promise
, throw an exception from thepooled_function
on which the promise was built. - Use
DelayQueue
using@mq.queuedmessage
decorator on a subclassed Bot class. any exception like TimeOut or flood control within asend_message
for example ends up with this problem - Use MessageQueue - I know this is deprecated, but that isn't the problematic code here. Promise itself isn't correctly handling exceptions.
If you get any telegram exception, it just gets eaten up by Promise's run method in this specific area:
if self._done_callback:
try:
self._done_callback(self.result())
except Exception as exc:
logger.warning(
"`done_callback` of a Promise raised the following exception."
" The exception won't be handled by error handlers."
)
logger.warning("Full traceback:", exc_info=exc)
Here's the bug: even if there's an exception in self.result()
it will treat it as an exception from self._done_callback()
which isn't correct.
The funny thing is that code speaks out the problem on its own:
try:
self._result = self.pooled_function(*self.args, **self.kwargs)
except Exception as exc:
self._exception = exc
if there's an exception in pooled_function
, it is stored in self._exception
and then it is raised from self.result()
:
def result(self, timeout: float = None) -> Optional[RT]:
self.done.wait(timeout=timeout)
if self._exception is not None:
raise self._exception # pylint: disable=raising-bad-type
return self._result
why? this way all exception from pooled_function
are forcibly going to be taken as exceptions of done_callback
, eaten up by the promise code and never raised.
Expected behaviour
Promise
should ideally have another method called add_exception_callback
or similar just like add_done_callback
, and pass any exception from pooled_function
to that callback
Actual behaviour
Promise mistreats pooled_function
exceptions as done_callback
exceptions
Configuration
Operating System:
linux
Version of Python, python-telegram-bot & dependencies:
Bot API 5.2
certifi 2020.12.05
Python 3.8.5 (default, Jul 21 2020, 10:42:08) [Clang 11.0.0 (clang-1100.0.33.17)]
Logs
Insert logs here (if necessary)
2021-06-04 12:23:17:WARNING:DelayQueue-1:telegram.ext.utils.promise:91: `done_callback` of a Promise raised the following exception. The exception won't be handled by error handlers.
2021-06-04 12:23:17:WARNING:DelayQueue-1:telegram.ext.utils.promise:95: Full traceback:
Traceback (most recent call last):
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 402, in _make_request
six.raise_from(e, None)
File "<string>", line 2, in raise_from
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 398, in _make_request
httplib_response = conn.getresponse()
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py", line 1347, in getresponse
response.begin()
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py", line 307, in begin
version, status, reason = self._read_status()
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/http/client.py", line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/socket.py", line 669, in readinto
return self._sock.recv_into(b)
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1241, in recv_into
return self.read(nbytes, buffer)
File "/usr/local/Cellar/python@3.8/3.8.5/Frameworks/Python.framework/Versions/3.8/lib/python3.8/ssl.py", line 1099, in read
return self._sslobj.read(len, buffer)
socket.timeout: The read operation timed out
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/utils/request.py", line 253, in _request_wrapper
resp = self._con_pool.request(*args, **kwargs)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 68, in request
return self.request_encode_body(method, url, fields=fields,
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py", line 148, in request_encode_body
return self.urlopen(method, url, **extra_kw)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py", line 244, in urlopen
response = conn.urlopen(method, u.request_uri, **kw)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 665, in urlopen
retries = retries.increment(method, url, error=e, _pool=self,
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py", line 347, in increment
raise six.reraise(type(error), error, _stacktrace)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py", line 686, in reraise
raise value
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 614, in urlopen
httplib_response = self._make_request(conn, method, url,
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 404, in _make_request
self._raise_timeout(err=e, url=url, timeout_value=read_timeout,
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py", line 321, in _raise_timeout
raise exc_cls(*args)
telegram.vendor.ptb_urllib3.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='api.telegram.org', port=443): Read timed out. (read timeout=5.0)
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py", line 89, in run
self._done_callback(self.result())
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py", line 116, in result
raise self._exception # pylint: disable=raising-bad-type
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py", line 80, in run
self._result = self.pooled_function(*self.args, **self.kwargs)
File "/Users/asingh/workspace/tgbot/tgbotschedulebot/tg_mq_bot.py", line 31, in editMessageText
return super(MQBot, self).edit_message_text(*args, **kwargs)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/bot.py", line 127, in decorator
result = func(*args, **kwargs)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/bot.py", line 2483, in edit_message_text
return self._message(
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/bot.py", line 296, in _message
result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs)
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/bot.py", line 259, in _post
return self.request.post(
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/utils/request.py", line 350, in post
result = self._request_wrapper(
File "/Users/asingh/workspace/tgbot/venv/lib/python3.8/site-packages/telegram/utils/request.py", line 255, in _request_wrapper
raise TimedOut() from error
telegram.error.TimedOut: Timed out