agronholm / jython-swingutils (http://pypi.python.org/pypi/jython-swingutils/)

An assortment of utility classes and functions that ease the task of writing GUI applications with the Java Swing toolkit.

commit 64: 3307347572cf
parent 63: 16a75bb2a223
branch: default
Background tasks now return AsyncResult objects, and runNamedTask now supports callbacks
Alex Grönholm / agronholm
4 months ago

Changed (Δ1.9 KB):

raw changeset »

swingutils/threads.py (76 lines added, 16 lines removed)

Up to file-list swingutils/threads.py:

1
from java.lang import Runnable
2
from java.util.concurrent import (ThreadPoolExecutor, TimeUnit,
3
                                  LinkedBlockingDeque)
1
from threading import Event
2
import traceback
3
4
from java.lang import Runnable, Throwable
5
from java.util.concurrent import ThreadPoolExecutor, TimeUnit, \
6
    LinkedBlockingDeque, Future, ExecutionException, \
7
    CancellationException
4
8
5
9
__all__ = ('TaskExecutor',)
6
10
11
7
12
class RunnableWrapper(Runnable):
8
13
    def __init__(self, func, args, kwargs, name=None, beforeCallback=None,
9
14
                 afterCallback=None):
10
        self.func = func
11
        self.args = args
12
        self.kwargs = kwargs
15
        self._func = func
16
        self._args = args
17
        self._kwargs = kwargs
13
18
        self.name = name
14
19
        self.beforeCallback = beforeCallback
15
20
        self.afterCallback = afterCallback
16
21
17
22
    def run(self):
18
        self.func(*self.args, **self.kwargs)
23
        self._func(*self._args, **self._kwargs)
24
25
26
class AsyncResult(RunnableWrapper, Future):
27
    """
28
    Class that stores both the function reference, and the return value or
29
    raised exception from an asynchronously invoked callable. Users should not
30
    instantiate or run these directly.
31
32
    """
33
    def __init__(self, func, args, kwargs, name=None, beforeCallback=None,
34
                 afterCallback=None):
35
        RunnableWrapper.__init__(self, func, args, kwargs, name,
36
                                 beforeCallback, afterCallback)
37
        self._event = Event()
38
39
    def run(self):
40
        if not self._func:
41
            return
42
43
        try:
44
            self._retval = self._func(*self._args, **self._kwargs)
45
        except BaseException, e:
46
            self._exception = e
47
            traceback.print_exc()
48
49
        self._func = None        # Free any memory taken by possible closures
50
        self._event.set()
51
52
    def cancel(self, mayInterruptIfRunning):
53
        if self.isDone():
54
            return False
55
        self._func = None
56
        return True
57
58
    def get(self, timeout=None, unit=None):
59
        if timeout and unit:
60
            timeout = unit.toMillis(timeout) / 1000.0
61
        self._event.wait(timeout)
62
        if hasattr(self, '_exception'):
63
            if isinstance(self._exception, Throwable):
64
                raise ExecutionException(self._exception)
65
            raise ExecutionException(unicode(self._exception), None)
66
        if not hasattr(self, '_retval'):
67
            raise CancellationException
68
        return self._retval
69
70
    def isCancelled(self):
71
        return self._func is None
72
73
    def isDone(self):
74
        return hasattr(self, '_retval') or hasattr(self, '_exception')
19
75
20
76
21
77
class TaskExecutor(ThreadPoolExecutor):
@@ -44,23 +100,27 @@ class TaskExecutor(ThreadPoolExecutor):
44
100
45
101
    def task(self, func):
46
102
        def wrapper(*args, **kwargs):
47
            runnable = RunnableWrapper(func, args, kwargs)
48
            self.execute(runnable)
103
            return self.runTask(func, *args, **kwargs)
49
104
        return wrapper
50
105
51
106
    def namedTask(self, name, beforeCallback=None, afterCallback=None):
52
107
        def outer(func):
53
108
            def inner(*args, **kwargs):
54
                runnable = RunnableWrapper(func, args, kwargs, name,
55
                                           beforeCallback, afterCallback)
56
                self.execute(runnable)
109
                kwargs['beforeCallback'] = beforeCallback
110
                kwargs['afterCallback'] = afterCallback
111
                return self.runNamedTask(func, name, *args, **kwargs)
57
112
            return inner
58
113
        return outer
59
114
60
115
    def runTask(self, func, *args, **kwargs):
61
        runnable = RunnableWrapper(func, args, kwargs)
62
        self.execute(runnable)
116
        result = AsyncResult(func, args, kwargs)
117
        self.execute(result)
118
        return result
63
119
64
120
    def runNamedTask(self, func, name, *args, **kwargs):
65
        runnable = RunnableWrapper(func, args, kwargs, name)
66
        self.execute(runnable)
121
        beforeCallback = kwargs.pop('beforeCallback', None)
122
        afterCallback = kwargs.pop('afterCallback', None)
123
        result = AsyncResult(func, args, kwargs, name, beforeCallback,
124
                             afterCallback)
125
        self.execute(result)
126
        return result