2016-11-30 06:21:53 +01:00
|
|
|
"""Python threading tools."""
|
2019-07-12 08:46:20 +02:00
|
|
|
from __future__ import (absolute_import, division, print_function)
|
|
|
|
__metaclass__ = type
|
2016-11-30 06:21:53 +01:00
|
|
|
|
|
|
|
import threading
|
|
|
|
import sys
|
|
|
|
|
|
|
|
try:
|
|
|
|
# noinspection PyPep8Naming
|
|
|
|
import Queue as queue
|
|
|
|
except ImportError:
|
|
|
|
# noinspection PyUnresolvedReferences
|
|
|
|
import queue # pylint: disable=locally-disabled, import-error
|
|
|
|
|
|
|
|
|
|
|
|
class WrappedThread(threading.Thread):
|
|
|
|
"""Wrapper around Thread which captures results and exceptions."""
|
|
|
|
def __init__(self, action):
|
|
|
|
"""
|
|
|
|
:type action: () -> any
|
|
|
|
"""
|
2017-05-03 17:19:44 +02:00
|
|
|
# noinspection PyOldStyleClasses
|
2016-11-30 06:21:53 +01:00
|
|
|
super(WrappedThread, self).__init__()
|
|
|
|
self._result = queue.Queue()
|
|
|
|
self.action = action
|
2017-11-15 02:08:48 +01:00
|
|
|
self.result = None
|
2016-11-30 06:21:53 +01:00
|
|
|
|
|
|
|
def run(self):
|
|
|
|
"""
|
|
|
|
Run action and capture results or exception.
|
|
|
|
Do not override. Do not call directly. Executed by the start() method.
|
|
|
|
"""
|
2018-09-08 02:59:46 +02:00
|
|
|
# We truly want to catch anything that the worker thread might do including call sys.exit.
|
|
|
|
# Therefore we catch *everything* (including old-style class exceptions)
|
2018-09-21 20:38:22 +02:00
|
|
|
# noinspection PyBroadException, PyPep8
|
2016-11-30 06:21:53 +01:00
|
|
|
try:
|
|
|
|
self._result.put((self.action(), None))
|
2018-09-08 02:59:46 +02:00
|
|
|
# pylint: disable=locally-disabled, bare-except
|
|
|
|
except: # noqa
|
2016-11-30 06:21:53 +01:00
|
|
|
self._result.put((None, sys.exc_info()))
|
|
|
|
|
|
|
|
def wait_for_result(self):
|
|
|
|
"""
|
|
|
|
Wait for thread to exit and return the result or raise an exception.
|
|
|
|
:rtype: any
|
|
|
|
"""
|
|
|
|
result, exception = self._result.get()
|
2017-11-15 02:08:48 +01:00
|
|
|
|
2016-11-30 06:21:53 +01:00
|
|
|
if exception:
|
|
|
|
if sys.version_info[0] > 2:
|
2017-05-18 19:37:53 +02:00
|
|
|
raise exception[1].with_traceback(exception[2])
|
2016-11-30 06:21:53 +01:00
|
|
|
# noinspection PyRedundantParentheses
|
|
|
|
exec('raise exception[0], exception[1], exception[2]') # pylint: disable=locally-disabled, exec-used
|
2017-11-15 02:08:48 +01:00
|
|
|
|
|
|
|
self.result = result
|
|
|
|
|
2016-11-30 06:21:53 +01:00
|
|
|
return result
|