# Buggy code
def Add(
    self,
    sender,
    workerFn,
    args=(),
    kwargs={},
    name=None,
    delay=0.0,
    uId=None,
    retryOnBusy=False,
    priority=0,
    workerType="dbthread",
):
    """The sender will send the return value of
    workerFn(*args, **kwargs) to the main thread.
    """
    if self.utility.abcquitting:
        self._logger.debug("GUIDBHandler: abcquitting ignoring Task(%s)", name)
        return

    assert uId is None or isinstance(uId, unicode), type(uId)
    assert name is None or isinstance(name, unicode), type(name)

    if uId:
        try:
            self.uIdsLock.acquire()
            if uId in self.uIds:
                self._logger.debug(
                    "GUIDBHandler: Task(%s) already scheduled in queue, ignoring uId = %s",
                    name,
                    uId,
                )
                return
            else:
                self.uIds.add(uId)
        finally:
            self.uIdsLock.release()

        callbackId = uId
    else:
        callbackId = name

    self._logger.debug("GUIDBHandler: adding Task(%s)", callbackId)

    if __debug__:
        self.uIdsLock.acquire()
        self.nrCallbacks[callbackId] = self.nrCallbacks.get(callbackId, 0) + 1
        if self.nrCallbacks[callbackId] > 10:
            self._logger.debug(
                "GUIDBHandler: Scheduled Task(%s) %d times",
                callbackId,
                self.nrCallbacks[callbackId],
            )

        self.uIdsLock.release()

    t1 = time()

    def wrapper():
        if __debug__:
            self.uIdsLock.acquire()
            self.nrCallbacks[callbackId] = self.nrCallbacks.get(callbackId, 0) - 1
            self.uIdsLock.release()

        # Call the actual function
        try:
            t2 = time()
            result = workerFn(*args, **kwargs)

        except (AbortedException, wx.PyDeadObjectError):
            return

        except Exception as exc:
            originalTb = format_exc()
            sender.sendException(exc, originalTb)
            return

        t3 = time()
        self._logger.debug(
            "GUIDBHandler: Task(%s) took to be called %.1f (expected %.1f), actual task took %.1f %s",
            name,
            t2 - t1,
            delay,
            t3 - t2,
            workerType,
        )

        if uId:
            try:
                self.uIdsLock.acquire()
                if uId in self.uIds:
                    self.uIds.discard(uId)

                # this callback has been removed during wrapper, cancel now
                else:
                    return
            finally:
                self.uIdsLock.release()

        # if we get to this step, send result to callback
        try:
            sender.sendResult(result)
        except:
            print_exc()
            self._logger.error("GUIDBHandler: Could not send result of Task(%s)", name)

    wrapper.__name__ = str(name)

    # Have in mind that setting workerType to "ThreadPool" means that the
    # task wants to be executed OUT of the GUI thread, nothing more.
    if delay or not (isInIOThread() or isInThreadPool()):
        if workerType == "dbThread":
            # Schedule the task to be called later in the reactor thread.
            self.utility.session.lm.threadpool.add_task(wrapper, delay)
        elif workerType == "ThreadPool":
            self.utility.session.lm.threadpool.add_task_in_thread(wrapper, delay)
        else:
            raise RuntimeError(
                "Asked to schedule a task with unknown workerType: %s", workerType
            )
    elif workerType == "dbThread" and not isInIOThread():
        reactor.callFromThread(wrapper)
    else:
        self._logger.debug(
            "GUIDBHandler: Task(%s) scheduled to be called on non GUI thread from non GUI thread, "
            "executing synchronously.",
            name,
        )
        wrapper()


# Traceback (isError)
Regression

Tribler.Test.Core.Modules.RestApi.test_downloads_endpoint.TestDownloadsEndpoint.test_remove_download_no_remove_data_param (from nosetests)
Failing for the past 1 build (Since Failed#2109 )
Took 4.4 sec.
Error Message

Test raised 1 unhandled Twisted exceptions:
[{'log_namespace': u'log_legacy', 'log_time': 1467938979.639, 'format': '%(log_legacy)s', 'log_system': '-', 'log_legacy': <twisted.logger._stdlib.StringifiableFromEvent object at 0x06D22830>, 'log_level': <LogLevel=critical>, 'system': '-', 'isError': 1, 'failure': <twisted.python.failure.Failure exceptions.AttributeError: 'NoneType' object has no attribute 'add_task'>, 'time': 1467938979.639, 'log_text': 'Unhandled Error\nTraceback (most recent call last):\n  File "C:\\Python27\\lib\\threading.py", line 763, in run\n    self.__target(*self.__args, **self.__kwargs)\n  File "C:\\workspace\\jenkins\\workspace\\GH_Tribler_PR_tests_win32\\tribler\\Tribler\\Core\\Utilities\\twisted_thread.py", line 55, in _reactor_runner\n    reactor.run(installSignalHandlers=False)\n  File "C:\\Python27\\lib\\site-packages\\twisted\\internet\\base.py", line 1194, in run\n    self.mainLoop()\n  File "C:\\Python27\\lib\\site-packages\\twisted\\internet\\base.py", line 1203, in mainLoop\n    self.runUntilCurrent()\n--- <exception caught here> ---\n  File "C:\\Python27\\lib\\site-packages\\twisted\\internet\\base.py", line 825, in runUntilCurrent\n    call.func(*call.args, **call.kw)\n  File "C:\\workspace\\jenkins\\workspace\\GH_Tribler_PR_tests_win32\\tribler\\Tribler\\Core\\Libtorrent\\__init__.py", line 27, in <lambda>\n    lambda_f = lambda a = args, kwa = kwargs: invoke_func(*a, **kwa)\n  File "C:\\workspace\\jenkins\\workspace\\GH_Tribler_PR_tests_win32\\tribler\\Tribler\\Core\\Libtorrent\\__init__.py", line 28, in invoke_func\n    download.session.lm.threadpool.add_task(lambda_f, 1)\nexceptions.AttributeError: \'NoneType\' object has no attribute \'add_task\'\n', 'log_format': u'{log_text}', 'message': (), 'why': None}]

# Fixed code
def Add(
    self,
    sender,
    workerFn,
    args=(),
    kwargs={},
    name=None,
    delay=0.0,
    uId=None,
    retryOnBusy=False,
    priority=0,
    workerType="dbthread",
):
    """The sender will send the return value of
    workerFn(*args, **kwargs) to the main thread.
    """
    if self.utility.abcquitting:
        self._logger.debug("GUIDBHandler: abcquitting ignoring Task(%s)", name)
        return

    assert uId is None or isinstance(uId, unicode), type(uId)
    assert name is None or isinstance(name, unicode), type(name)

    if uId:
        try:
            self.uIdsLock.acquire()
            if uId in self.uIds:
                self._logger.debug(
                    "GUIDBHandler: Task(%s) already scheduled in queue, ignoring uId = %s",
                    name,
                    uId,
                )
                return
            else:
                self.uIds.add(uId)
        finally:
            self.uIdsLock.release()

        callbackId = uId
    else:
        callbackId = name

    self._logger.debug("GUIDBHandler: adding Task(%s)", callbackId)

    if __debug__:
        self.uIdsLock.acquire()
        self.nrCallbacks[callbackId] = self.nrCallbacks.get(callbackId, 0) + 1
        if self.nrCallbacks[callbackId] > 10:
            self._logger.debug(
                "GUIDBHandler: Scheduled Task(%s) %d times",
                callbackId,
                self.nrCallbacks[callbackId],
            )

        self.uIdsLock.release()

    t1 = time()

    def wrapper():
        if __debug__:
            self.uIdsLock.acquire()
            self.nrCallbacks[callbackId] = self.nrCallbacks.get(callbackId, 0) - 1
            self.uIdsLock.release()

        # Call the actual function
        try:
            t2 = time()
            result = workerFn(*args, **kwargs)

        except (AbortedException, wx.PyDeadObjectError):
            return

        except Exception as exc:
            originalTb = format_exc()
            sender.sendException(exc, originalTb)
            return

        t3 = time()
        self._logger.debug(
            "GUIDBHandler: Task(%s) took to be called %.1f (expected %.1f), actual task took %.1f %s",
            name,
            t2 - t1,
            delay,
            t3 - t2,
            workerType,
        )

        if uId:
            try:
                self.uIdsLock.acquire()
                if uId in self.uIds:
                    self.uIds.discard(uId)

                # this callback has been removed during wrapper, cancel now
                else:
                    return
            finally:
                self.uIdsLock.release()

        # if we get to this step, send result to callback
        try:
            sender.sendResult(result)
        except:
            print_exc()
            self._logger.error("GUIDBHandler: Could not send result of Task(%s)", name)

    wrapper.__name__ = str(name)

    # Have in mind that setting workerType to "ThreadPool" means that the
    # task wants to be executed OUT of the GUI thread, nothing more.
    if delay or not (isInIOThread() or isInThreadPool()):
        random_id = "".join(choice("0123456789abcdef") for _ in xrange(10))
        if workerType == "dbThread":
            # Schedule the task to be called later in the reactor thread.
            delayed_call = reactor.callLater(delay, reactor.callFromThread, wrapper)
            self.register_task(str(self.__class__) + random_id, delayed_call)
        elif workerType == "ThreadPool":

            def schedule_call():
                delayed_call = reactor.callLater(delay, reactor.callInThread, wrapper)
                self.register_task(str(self.__class__) + random_id, delayed_call)

            reactor.callFromThread(schedule_call)
        else:
            raise RuntimeError(
                "Asked to schedule a task with unknown workerType: %s", workerType
            )
    elif workerType == "dbThread" and not isInIOThread():
        reactor.callFromThread(wrapper)
    else:
        self._logger.debug(
            "GUIDBHandler: Task(%s) scheduled to be called on non GUI thread from non GUI thread, "
            "executing synchronously.",
            name,
        )
        wrapper()