-
Notifications
You must be signed in to change notification settings - Fork 0
/
tools.py
89 lines (66 loc) · 2.01 KB
/
tools.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import functools
import sys
from queue import Queue
from threading import Thread
from typing import Iterable
class CyclicIterator:
def __init__(self, container: Iterable):
self.container = container
self.cont_iter = iter(container)
def __iter__(self):
return self
def __next__(self):
try:
return next(self.cont_iter)
except StopIteration:
self.cont_iter = iter(self.container)
return next(self.cont_iter)
class KThread(Thread):
"""A subclass of threading.Thread, with a kill() method."""
def __init__(self, *args, **keywords):
Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
"""Start the thread."""
self.__run_backup = self.run
self.run = self.__run
Thread.start(self)
def __run(self):
"""Hacked run function, which installs the trace."""
sys.settrace(self.globaltrace)
self.__run_backup()
self.run = self.__run_backup
def globaltrace(self, frame, why, arg):
if why == 'call':
return self.localtrace
else:
return None
def localtrace(self, frame, why, arg):
if self.killed:
if why == 'line':
raise SystemExit()
return self.localtrace
def kill(self):
self.killed = True
class JobException(BaseException):
pass
class KillException(BaseException):
pass
def result_decorator(queue: Queue):
def actual_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
try:
result = func(*args, **kwargs)
queue.put(result)
return result
except BaseException as ex:
queue.put(JobException(ex))
return wrapper
return actual_decorator
def coroutine(method):
def wrapper(*args, **kwargs):
gen = method(*args, **kwargs)
gen.send(None)
return gen
return wrapper