-
Notifications
You must be signed in to change notification settings - Fork 0
/
promises.py
216 lines (172 loc) · 6.86 KB
/
promises.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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
import traceback
import logging
import json
from threading import Thread
from threading import Event
class Promise(object):
def __init__(self, resolver = None):
self._event = Event()
self._rejected = False
self._result = None
if resolver:
self.resolver(resolver)
def resolver(self, resolver):
def deferredTask():
try:
resolver(self._resolve, self._reject)
except Exception as e:
self._reject(e.message)
traceback.print_exc()
Thread(target = deferredTask).start()
def _resolve(self, value):
# set promise to resolved
# set result to value
self._rejected = False
self._result = value
self._event.set()
def _reject(self, reason):
# set promise to rejected
# set result to reason
self._rejected = True
self._result = reason
self._event.set()
def wait(self):
return self._event.wait()
def result(self):
return self._result
def isRejected(self):
return self._rejected
def toJson(self):
# return a dict containing the current state of the promise
return {
'result': self._result,
'rejected': self._rejected
}
def then(self, onFulfilled = None, onRejected = None):
promise = self.__class__()
catch = False
if not onFulfilled and onRejected:
catch = True
def deferredTask():
try:
self.wait()
if self._rejected:
# the current promise has been rejected
# all following onFulfilled methods will be skipped
if onRejected:
# there is a method for handling onRejected
# call method with current value as argument
result = onRejected(self.result())
if result != None:
# the result is not none
if catch:
# set new promise to resolve to result value
promise._resolve(result)
else:
# this is not an attempt to catch and resolve
# set new promise to reject with current value
promise._reject(result)
else:
# the result is none, nothing was returned
if catch:
# set new promise to resolve to current value
promise._resolve(self.result())
else:
# this is not an attempt to catch and resolve
# set new promise to reject with current value
promise._reject(self.result())
else:
# there is no method for handling onRejected
# set new promise to reject with current value
promise._reject(self.result())
else:
# the current promise has not been rejected
# all following onRejected methods will be skipped
if onFulfilled:
# there is a method for handling onFulfilled
# call method with current value as argument
result = onFulfilled(self.result())
if result != None:
# the result is not none
# set new promise to resolve to result value
promise._resolve(result)
else:
# the result is none, nothing was returned
# set new promise to resolve to current value
promise._resolve(self.result())
else:
# there is no method for handling onFulfilled
# set new promise to resolve to current value
promise._resolve(self.result())
except Exception as e:
# there has been an error along the way
# set new promise to reject with error message
promise._reject(e.message)
traceback.print_exc()
Thread(target = deferredTask).start()
#deferredTask()
return promise
def catch(self, onRejected):
# sugar for then(None, onRejected)
return self.then(None, onRejected)
@staticmethod
def resolve(value):
promise = Promise()
def deferredTask():
if isinstance(value, Promise):
value.wait()
if value._rejected:
promise._reject(value._result)
else:
promise._resolve(value._result)
elif hasattr(value, '__call__'):
# the value is callable
try:
result = value()
except Exception as e:
# the called method raises an Exception
# reject promise
promise._reject(e.message)
traceback.print_exc()
else:
# resolve promise with return value from method
promise._resolve(result)
else:
# resolve promise with value
promise._resolve(value)
Thread(target = deferredTask).start()
return promise
@staticmethod
def reject(reason):
promise = Promise()
promise._reject(reason)
return promise
@staticmethod
def all(promises):
new_promise = Promise()
new_promise_results = []
def deferredTask():
for index, promise in enumerate(promises):
promise.wait()
if promise.isRejected():
new_promise._reject(promise.result())
break
else:
new_promise_results.append(promise.result())
if not new_promise.isRejected():
new_promise._resolve(new_promise_results)
Thread(target = deferredTask).start()
return new_promise
@staticmethod
def race(promises):
threads = []
new_promise = Promise()
def deferredTask(promise):
promise.wait()
if promise.isRejected():
new_promise._reject(promise.result())
else:
new_promise._resolve(promise.result())
for index, promise in enumerate(promises):
threads.append(Thread(target = deferredTask, args = (promise, )).start())
return new_promise