| 1 | /* |
|---|
| 2 | * A Deferred implementation in C. Cover most of the Deferred API but try |
|---|
| 3 | * to be faster. |
|---|
| 4 | * |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include <Python.h> |
|---|
| 8 | #include "structmember.h" |
|---|
| 9 | |
|---|
| 10 | /* Py_VISIT and Py_CLEAR are defined here to be compatible with Python 2.3 */ |
|---|
| 11 | |
|---|
| 12 | #ifndef Py_VISIT |
|---|
| 13 | #define Py_VISIT(op) \ |
|---|
| 14 | do { \ |
|---|
| 15 | if (op) { \ |
|---|
| 16 | int vret = visit((PyObject *)(op), arg); \ |
|---|
| 17 | if (vret) \ |
|---|
| 18 | return vret; \ |
|---|
| 19 | } \ |
|---|
| 20 | } while (0) |
|---|
| 21 | #endif |
|---|
| 22 | |
|---|
| 23 | #ifndef Py_CLEAR |
|---|
| 24 | #define Py_CLEAR(op) \ |
|---|
| 25 | do { \ |
|---|
| 26 | if (op) { \ |
|---|
| 27 | PyObject *tmp = (PyObject *)(op); \ |
|---|
| 28 | (op) = NULL; \ |
|---|
| 29 | Py_DECREF(tmp); \ |
|---|
| 30 | } \ |
|---|
| 31 | } while (0) |
|---|
| 32 | #endif |
|---|
| 33 | |
|---|
| 34 | PyObject * failure_class; |
|---|
| 35 | PyObject * already_called; |
|---|
| 36 | |
|---|
| 37 | typedef struct { |
|---|
| 38 | PyObject_HEAD |
|---|
| 39 | PyObject *result; |
|---|
| 40 | int paused; |
|---|
| 41 | PyObject *callbacks; |
|---|
| 42 | int called; |
|---|
| 43 | } cdefer_Deferred; |
|---|
| 44 | |
|---|
| 45 | /* Prototypes */ |
|---|
| 46 | |
|---|
| 47 | static PyObject * cdefer_Deferred_new(PyTypeObject *type, PyObject *args, |
|---|
| 48 | PyObject *kwargs); |
|---|
| 49 | |
|---|
| 50 | static void cdefer_Deferred_dealloc(PyObject *o); |
|---|
| 51 | |
|---|
| 52 | static int cdefer_Deferred_traverse(PyObject *o, visitproc visit, void *arg); |
|---|
| 53 | |
|---|
| 54 | static int cdefer_Deferred_clear(PyObject *o); |
|---|
| 55 | |
|---|
| 56 | static int cdefer_Deferred_clear(PyObject *o); |
|---|
| 57 | |
|---|
| 58 | static int cdefer_Deferred___init__(cdefer_Deferred *self, PyObject *args, |
|---|
| 59 | PyObject *kwargs); |
|---|
| 60 | |
|---|
| 61 | static PyObject *cdefer_Deferred__addCallbacks(cdefer_Deferred *self, |
|---|
| 62 | PyObject *callback, PyObject *errback, PyObject *callbackArgs, |
|---|
| 63 | PyObject *callbackKeywords, PyObject *errbackArgs, |
|---|
| 64 | PyObject *errbackKeywords); |
|---|
| 65 | |
|---|
| 66 | static PyObject *cdefer_Deferred_addCallback(cdefer_Deferred *self, |
|---|
| 67 | PyObject *args, PyObject *kwargs); |
|---|
| 68 | |
|---|
| 69 | static PyObject *cdefer_Deferred_addErrback(cdefer_Deferred *self, |
|---|
| 70 | PyObject *args, PyObject *kwargs); |
|---|
| 71 | |
|---|
| 72 | static PyObject *cdefer_Deferred_addBoth(cdefer_Deferred *self, PyObject *args, |
|---|
| 73 | PyObject *kwargs); |
|---|
| 74 | |
|---|
| 75 | static PyObject *cdefer_Deferred_pause(cdefer_Deferred *self, PyObject *args); |
|---|
| 76 | |
|---|
| 77 | static PyObject *cdefer_Deferred_unpause(cdefer_Deferred *self, |
|---|
| 78 | PyObject *args); |
|---|
| 79 | |
|---|
| 80 | static PyObject *cdefer_Deferred_chainDeferred(cdefer_Deferred *self, |
|---|
| 81 | PyObject *args, PyObject *kwargs); |
|---|
| 82 | |
|---|
| 83 | static PyObject *cdefer_Deferred__runCallbacks(cdefer_Deferred *self); |
|---|
| 84 | |
|---|
| 85 | static PyObject *cdefer_Deferred__startRunCallbacks(cdefer_Deferred *self, |
|---|
| 86 | PyObject *result); |
|---|
| 87 | |
|---|
| 88 | static PyObject *cdefer_Deferred_callback(cdefer_Deferred *self, PyObject *args, |
|---|
| 89 | PyObject *kwargs); |
|---|
| 90 | |
|---|
| 91 | static PyObject *cdefer_Deferred_errback(cdefer_Deferred *self, PyObject *args, |
|---|
| 92 | PyObject *kwargs); |
|---|
| 93 | |
|---|
| 94 | static PyObject *cdefer_Deferred__continue(cdefer_Deferred *self, |
|---|
| 95 | PyObject *args, PyObject *kwargs); |
|---|
| 96 | |
|---|
| 97 | static PyTypeObject cdefer_DeferredType; |
|---|
| 98 | |
|---|
| 99 | static PyObject * cdefer_Deferred_new(PyTypeObject *type, PyObject *args, |
|---|
| 100 | PyObject *kwargs) { |
|---|
| 101 | cdefer_Deferred *self; |
|---|
| 102 | self = (cdefer_Deferred *)type->tp_alloc(type, 0); |
|---|
| 103 | return (PyObject *)self; |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | static void cdefer_Deferred_dealloc(PyObject *o) { |
|---|
| 107 | cdefer_Deferred *self; |
|---|
| 108 | self = (cdefer_Deferred *)o; |
|---|
| 109 | PyObject_GC_UnTrack(self); |
|---|
| 110 | Py_XDECREF(self->result); |
|---|
| 111 | Py_XDECREF(self->callbacks); |
|---|
| 112 | (*o->ob_type->tp_free)(o); |
|---|
| 113 | } |
|---|
| 114 | |
|---|
| 115 | static int cdefer_Deferred_traverse(PyObject *o, visitproc visit, void *arg) { |
|---|
| 116 | cdefer_Deferred *self; |
|---|
| 117 | self = (cdefer_Deferred *)o; |
|---|
| 118 | Py_VISIT(self->result); |
|---|
| 119 | Py_VISIT(self->callbacks); |
|---|
| 120 | return 0; |
|---|
| 121 | } |
|---|
| 122 | |
|---|
| 123 | static int cdefer_Deferred_clear(PyObject *o) { |
|---|
| 124 | cdefer_Deferred *self; |
|---|
| 125 | self = (cdefer_Deferred *)o; |
|---|
| 126 | Py_CLEAR(self->result); |
|---|
| 127 | Py_CLEAR(self->callbacks); |
|---|
| 128 | return 0; |
|---|
| 129 | } |
|---|
| 130 | |
|---|
| 131 | static int cdefer_Deferred___init__(cdefer_Deferred *self, PyObject *args, |
|---|
| 132 | PyObject *kwargs) { |
|---|
| 133 | static char *argnames[] = {NULL}; |
|---|
| 134 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", argnames)) { |
|---|
| 135 | return -1; |
|---|
| 136 | } |
|---|
| 137 | self->paused = 0; |
|---|
| 138 | self->callbacks = PyList_New(0); |
|---|
| 139 | if (!self->callbacks) { |
|---|
| 140 | return -1; |
|---|
| 141 | } |
|---|
| 142 | return 0; |
|---|
| 143 | } |
|---|
| 144 | |
|---|
| 145 | static PyObject *cdefer_Deferred__addCallbacks(cdefer_Deferred *self, |
|---|
| 146 | PyObject *callback, PyObject *errback, PyObject *callbackArgs, |
|---|
| 147 | PyObject *callbackKeywords, PyObject *errbackArgs, |
|---|
| 148 | PyObject *errbackKeywords) { |
|---|
| 149 | PyObject *result; |
|---|
| 150 | PyObject *cbs = 0; |
|---|
| 151 | |
|---|
| 152 | if (callback != Py_None) { |
|---|
| 153 | if (!PyCallable_Check(callback)) { |
|---|
| 154 | PyErr_SetNone(PyExc_AssertionError); |
|---|
| 155 | return NULL; |
|---|
| 156 | } |
|---|
| 157 | } |
|---|
| 158 | if (errback != Py_None) { |
|---|
| 159 | if (!PyCallable_Check(errback)) { |
|---|
| 160 | PyErr_SetNone(PyExc_AssertionError); |
|---|
| 161 | return NULL; |
|---|
| 162 | } |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | Py_INCREF(callback); |
|---|
| 166 | Py_INCREF(callbackArgs); |
|---|
| 167 | Py_INCREF(callbackKeywords); |
|---|
| 168 | Py_INCREF(errback); |
|---|
| 169 | Py_INCREF(errbackArgs); |
|---|
| 170 | Py_INCREF(errbackKeywords); |
|---|
| 171 | |
|---|
| 172 | cbs = Py_BuildValue("(OOOOOO)", callback, callbackArgs, callbackKeywords, |
|---|
| 173 | errback, errbackArgs, errbackKeywords); |
|---|
| 174 | if (!cbs) { |
|---|
| 175 | return NULL; |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | if (PyList_Append(self->callbacks, cbs) == -1) { |
|---|
| 179 | return NULL; |
|---|
| 180 | } |
|---|
| 181 | Py_CLEAR(cbs); |
|---|
| 182 | |
|---|
| 183 | Py_DECREF(callback); |
|---|
| 184 | Py_DECREF(callbackArgs); |
|---|
| 185 | Py_DECREF(callbackKeywords); |
|---|
| 186 | Py_DECREF(errback); |
|---|
| 187 | Py_DECREF(errbackArgs); |
|---|
| 188 | Py_DECREF(errbackKeywords); |
|---|
| 189 | |
|---|
| 190 | if (self->called) { |
|---|
| 191 | if (cdefer_Deferred__runCallbacks(self) == NULL) { |
|---|
| 192 | return NULL; |
|---|
| 193 | } |
|---|
| 194 | } |
|---|
| 195 | |
|---|
| 196 | result = (PyObject *)self; |
|---|
| 197 | Py_INCREF(result); |
|---|
| 198 | return result; |
|---|
| 199 | } |
|---|
| 200 | |
|---|
| 201 | static char cdefer_Deferred_addCallbacks_doc[] = "Add a pair of callbacks (success and error) to this Deferred.\n\nThese will be executed when the \'master\' callback is run."; |
|---|
| 202 | |
|---|
| 203 | static PyObject *cdefer_Deferred_addCallbacks(cdefer_Deferred *self, |
|---|
| 204 | PyObject *args, PyObject *kwargs) { |
|---|
| 205 | PyObject *callback; |
|---|
| 206 | PyObject *errback; |
|---|
| 207 | PyObject *callbackArgs; |
|---|
| 208 | PyObject *callbackKeywords; |
|---|
| 209 | PyObject *errbackArgs; |
|---|
| 210 | PyObject *errbackKeywords; |
|---|
| 211 | PyObject *result; |
|---|
| 212 | errback = Py_None; |
|---|
| 213 | callbackArgs = Py_None; |
|---|
| 214 | callbackKeywords = Py_None; |
|---|
| 215 | errbackArgs = Py_None; |
|---|
| 216 | errbackKeywords = Py_None; |
|---|
| 217 | static char *argnames[] = {"callback", "errback", "callbackArgs", |
|---|
| 218 | "callbackKeywords", "errbackArgs", "errbackKeywords", NULL}; |
|---|
| 219 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OOOOO", argnames, |
|---|
| 220 | &callback, &errback, &callbackArgs, |
|---|
| 221 | &callbackKeywords, &errbackArgs, &errbackKeywords)) { |
|---|
| 222 | return NULL; |
|---|
| 223 | } |
|---|
| 224 | result = cdefer_Deferred__addCallbacks(self, callback, errback, |
|---|
| 225 | callbackArgs, callbackKeywords, errbackArgs, errbackKeywords); |
|---|
| 226 | return result; |
|---|
| 227 | } |
|---|
| 228 | |
|---|
| 229 | static char cdefer_Deferred_addCallback_doc[] = "Convenience method for adding just a callback.\n\nSee L{addCallbacks}."; |
|---|
| 230 | |
|---|
| 231 | static PyObject *cdefer_Deferred_addCallback(cdefer_Deferred *self, |
|---|
| 232 | PyObject *args, PyObject *kwargs) { |
|---|
| 233 | PyObject *callback; |
|---|
| 234 | PyObject *callbackArgs; |
|---|
| 235 | PyObject *callbackKeywords; |
|---|
| 236 | PyObject *result; |
|---|
| 237 | if (PyTuple_Size(args) > 0) { |
|---|
| 238 | callback = PyTuple_GET_ITEM(args, 0); |
|---|
| 239 | if (!callback) { |
|---|
| 240 | return NULL; |
|---|
| 241 | } |
|---|
| 242 | callbackArgs = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); |
|---|
| 243 | if (!callbackArgs) { |
|---|
| 244 | return NULL; |
|---|
| 245 | } |
|---|
| 246 | } else { |
|---|
| 247 | callback = PyDict_GetItemString(kwargs, "callback"); |
|---|
| 248 | if (!callback) { |
|---|
| 249 | return NULL; |
|---|
| 250 | } |
|---|
| 251 | callbackArgs = Py_None; |
|---|
| 252 | if (PyDict_DelItemString(kwargs, "callback") == -1) { |
|---|
| 253 | return NULL; |
|---|
| 254 | } |
|---|
| 255 | } |
|---|
| 256 | callbackKeywords = kwargs; |
|---|
| 257 | if (!callbackKeywords) { |
|---|
| 258 | callbackKeywords = Py_None; |
|---|
| 259 | } |
|---|
| 260 | result = cdefer_Deferred__addCallbacks(self, callback, Py_None, callbackArgs, |
|---|
| 261 | callbackKeywords, Py_None, Py_None); |
|---|
| 262 | Py_DECREF(callbackArgs); |
|---|
| 263 | return result; |
|---|
| 264 | } |
|---|
| 265 | |
|---|
| 266 | static char cdefer_Deferred_addErrback_doc[] = "Convenience method for adding just an errback.\n\nSee L{addCallbacks}."; |
|---|
| 267 | |
|---|
| 268 | static PyObject *cdefer_Deferred_addErrback(cdefer_Deferred *self, |
|---|
| 269 | PyObject *args, PyObject *kwargs) { |
|---|
| 270 | PyObject *errback; |
|---|
| 271 | PyObject *errbackArgs; |
|---|
| 272 | PyObject *errbackKeywords; |
|---|
| 273 | PyObject *result; |
|---|
| 274 | if (PyTuple_Size(args) > 0) { |
|---|
| 275 | errback = PyTuple_GET_ITEM(args, 0); |
|---|
| 276 | if (!errback) { |
|---|
| 277 | return NULL; |
|---|
| 278 | } |
|---|
| 279 | errbackArgs = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); |
|---|
| 280 | if (!errbackArgs) { |
|---|
| 281 | return NULL; |
|---|
| 282 | } |
|---|
| 283 | } else { |
|---|
| 284 | errback = PyDict_GetItemString(kwargs, "errback"); |
|---|
| 285 | if (!errback) { |
|---|
| 286 | return errback; |
|---|
| 287 | } |
|---|
| 288 | errbackArgs = Py_None; |
|---|
| 289 | if (PyDict_DelItemString(kwargs, "errback") == -1) { |
|---|
| 290 | return NULL; |
|---|
| 291 | } |
|---|
| 292 | } |
|---|
| 293 | errbackKeywords = kwargs; |
|---|
| 294 | if (!errbackKeywords) { |
|---|
| 295 | errbackKeywords = Py_None; |
|---|
| 296 | } |
|---|
| 297 | result = cdefer_Deferred__addCallbacks(self, Py_None, errback, Py_None, |
|---|
| 298 | Py_None, errbackArgs, errbackKeywords); |
|---|
| 299 | Py_DECREF(errbackArgs); |
|---|
| 300 | return result; |
|---|
| 301 | } |
|---|
| 302 | |
|---|
| 303 | static char cdefer_Deferred_addBoth_doc[] = "Convenience method for adding a single callable as both a callback\nand an errback.\n\nSee L{addCallbacks}."; |
|---|
| 304 | |
|---|
| 305 | static PyObject *cdefer_Deferred_addBoth(cdefer_Deferred *self, PyObject *args, |
|---|
| 306 | PyObject *kwargs) { |
|---|
| 307 | PyObject *callback; |
|---|
| 308 | PyObject *callbackArgs; |
|---|
| 309 | PyObject *callbackKeywords; |
|---|
| 310 | PyObject *result; |
|---|
| 311 | if (PyTuple_Size(args) > 0) { |
|---|
| 312 | callback = PyTuple_GET_ITEM(args, 0); |
|---|
| 313 | if (!callback) { |
|---|
| 314 | return NULL; |
|---|
| 315 | } |
|---|
| 316 | callbackArgs = PyTuple_GetSlice(args, 1, PyTuple_Size(args)); |
|---|
| 317 | if (!callbackArgs) { |
|---|
| 318 | return NULL; |
|---|
| 319 | } |
|---|
| 320 | } else { |
|---|
| 321 | callback = PyDict_GetItemString(kwargs, "callback"); |
|---|
| 322 | if (!callback) { |
|---|
| 323 | return NULL; |
|---|
| 324 | } |
|---|
| 325 | callbackArgs = Py_None; |
|---|
| 326 | if (PyDict_DelItemString(kwargs, "callback") == -1) { |
|---|
| 327 | return NULL; |
|---|
| 328 | } |
|---|
| 329 | } |
|---|
| 330 | callbackKeywords = kwargs; |
|---|
| 331 | if (!callbackKeywords) { |
|---|
| 332 | callbackKeywords = Py_None; |
|---|
| 333 | } |
|---|
| 334 | result = cdefer_Deferred__addCallbacks(self, callback, callback, |
|---|
| 335 | callbackArgs, callbackKeywords, callbackArgs, callbackKeywords); |
|---|
| 336 | Py_DECREF(callbackArgs); |
|---|
| 337 | return result; |
|---|
| 338 | } |
|---|
| 339 | |
|---|
| 340 | static char cdefer_Deferred_pause_doc[] = "Stop processing on a Deferred until L{unpause}() is called."; |
|---|
| 341 | |
|---|
| 342 | static PyObject *cdefer_Deferred_pause(cdefer_Deferred *self, PyObject *args) { |
|---|
| 343 | PyObject *result; |
|---|
| 344 | self->paused++; |
|---|
| 345 | result = Py_None; |
|---|
| 346 | Py_INCREF(Py_None); |
|---|
| 347 | return result; |
|---|
| 348 | } |
|---|
| 349 | |
|---|
| 350 | static char cdefer_Deferred_unpause_doc[] = "Process all callbacks made since L{pause}() was called."; |
|---|
| 351 | |
|---|
| 352 | static PyObject *cdefer_Deferred_unpause(cdefer_Deferred *self, |
|---|
| 353 | PyObject *args) { |
|---|
| 354 | self->paused--; |
|---|
| 355 | if (!self->paused && self->called) { |
|---|
| 356 | return cdefer_Deferred__runCallbacks(self); |
|---|
| 357 | } |
|---|
| 358 | Py_INCREF(Py_None); |
|---|
| 359 | return Py_None; |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | static char cdefer_Deferred_chainDeferred_doc[] = "Chain another Deferred to this Deferred.\n\nThis method adds callbacks to this Deferred to call d\'s callback or\nerrback, as appropriate."; |
|---|
| 363 | |
|---|
| 364 | static PyObject *cdefer_Deferred_chainDeferred(cdefer_Deferred *self, |
|---|
| 365 | PyObject *args, PyObject *kwargs) { |
|---|
| 366 | PyObject *d; |
|---|
| 367 | PyObject *callback; |
|---|
| 368 | PyObject *errback; |
|---|
| 369 | PyObject *result; |
|---|
| 370 | static char *argnames[] = {"d", NULL}; |
|---|
| 371 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", argnames, &d)) { |
|---|
| 372 | return NULL; |
|---|
| 373 | } |
|---|
| 374 | callback = PyObject_GetAttrString(d, "callback"); |
|---|
| 375 | if (!callback) { |
|---|
| 376 | return NULL; |
|---|
| 377 | } |
|---|
| 378 | errback = PyObject_GetAttrString(d, "errback"); |
|---|
| 379 | if (!errback) { |
|---|
| 380 | return NULL; |
|---|
| 381 | } |
|---|
| 382 | result = cdefer_Deferred__addCallbacks(self, callback, errback, Py_None, |
|---|
| 383 | Py_None, Py_None, Py_None); |
|---|
| 384 | Py_DECREF(callback); |
|---|
| 385 | Py_DECREF(errback); |
|---|
| 386 | return result; |
|---|
| 387 | } |
|---|
| 388 | |
|---|
| 389 | static PyObject *cdefer_Deferred__runCallbacks(cdefer_Deferred *self) { |
|---|
| 390 | PyObject *cb; |
|---|
| 391 | PyObject *item; |
|---|
| 392 | PyObject *callback; |
|---|
| 393 | PyObject *args; |
|---|
| 394 | PyObject *newArgs; |
|---|
| 395 | PyObject *newArgs2; |
|---|
| 396 | PyObject *kwargs; |
|---|
| 397 | PyObject *_continue; |
|---|
| 398 | PyObject *type, *value, *traceback, *failArgs; |
|---|
| 399 | PyObject *tmp; |
|---|
| 400 | int i; |
|---|
| 401 | int size; |
|---|
| 402 | int offset; |
|---|
| 403 | |
|---|
| 404 | if (!self->paused) { |
|---|
| 405 | cb = self->callbacks; |
|---|
| 406 | size = PyList_GET_SIZE(cb); |
|---|
| 407 | if (size == -1) { |
|---|
| 408 | return NULL; |
|---|
| 409 | } |
|---|
| 410 | for (i = 0; i < size; i++) { |
|---|
| 411 | item = PyList_GET_ITEM(cb, i); |
|---|
| 412 | if (!item) { |
|---|
| 413 | return NULL; |
|---|
| 414 | } |
|---|
| 415 | |
|---|
| 416 | offset = 0; |
|---|
| 417 | if (PyObject_IsInstance(self->result, failure_class)) { |
|---|
| 418 | offset = 3; |
|---|
| 419 | } |
|---|
| 420 | |
|---|
| 421 | callback = PyTuple_GET_ITEM(item, offset + 0); |
|---|
| 422 | if (!callback) { |
|---|
| 423 | return NULL; |
|---|
| 424 | } |
|---|
| 425 | if (callback == Py_None) { |
|---|
| 426 | continue; |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | args = PyTuple_GET_ITEM(item, offset + 1); |
|---|
| 430 | if (!args) { |
|---|
| 431 | return NULL; |
|---|
| 432 | } |
|---|
| 433 | |
|---|
| 434 | kwargs = PyTuple_GET_ITEM(item, offset + 2); |
|---|
| 435 | if (!kwargs) { |
|---|
| 436 | return NULL; |
|---|
| 437 | } |
|---|
| 438 | |
|---|
| 439 | newArgs = Py_BuildValue("(O)", self->result); |
|---|
| 440 | if (!newArgs) { |
|---|
| 441 | return NULL; |
|---|
| 442 | } |
|---|
| 443 | |
|---|
| 444 | if (args != Py_None) { |
|---|
| 445 | newArgs2 = PySequence_InPlaceConcat(newArgs, args); |
|---|
| 446 | if (!newArgs2) { |
|---|
| 447 | return NULL; |
|---|
| 448 | } |
|---|
| 449 | } else { |
|---|
| 450 | newArgs2 = newArgs; |
|---|
| 451 | } |
|---|
| 452 | |
|---|
| 453 | if (kwargs == Py_None) { |
|---|
| 454 | tmp = PyObject_Call(callback, newArgs2, NULL); |
|---|
| 455 | } else { |
|---|
| 456 | tmp = PyObject_Call(callback, newArgs2, kwargs); |
|---|
| 457 | } |
|---|
| 458 | Py_DECREF(self->result); |
|---|
| 459 | self->result = tmp; |
|---|
| 460 | |
|---|
| 461 | Py_CLEAR(newArgs2); |
|---|
| 462 | Py_CLEAR(newArgs); |
|---|
| 463 | |
|---|
| 464 | if (!self->result) { |
|---|
| 465 | PyErr_Fetch(&type, &value, &traceback); |
|---|
| 466 | PyErr_NormalizeException(&type, &value, &traceback); |
|---|
| 467 | if (!value) { |
|---|
| 468 | value = Py_None; |
|---|
| 469 | Py_INCREF(value); |
|---|
| 470 | } |
|---|
| 471 | if (!traceback) { |
|---|
| 472 | traceback = Py_None; |
|---|
| 473 | Py_INCREF(traceback); |
|---|
| 474 | } |
|---|
| 475 | |
|---|
| 476 | failArgs = Py_BuildValue("(OOO)", value, type, traceback); |
|---|
| 477 | if (!failArgs) { |
|---|
| 478 | PyErr_Restore(type, value, traceback); |
|---|
| 479 | return NULL; |
|---|
| 480 | } |
|---|
| 481 | self->result = PyObject_CallObject(failure_class, failArgs); |
|---|
| 482 | Py_INCREF(self->result); |
|---|
| 483 | continue; |
|---|
| 484 | } |
|---|
| 485 | Py_INCREF(self->result); |
|---|
| 486 | if (PyObject_TypeCheck(self->result, &cdefer_DeferredType)) { |
|---|
| 487 | if (PyList_SetSlice(cb, 0, i+1, NULL) == -1) { |
|---|
| 488 | return NULL; |
|---|
| 489 | } |
|---|
| 490 | if (!PyObject_CallMethod((PyObject *)self, "pause", NULL)) { |
|---|
| 491 | return NULL; |
|---|
| 492 | } |
|---|
| 493 | _continue = PyObject_GetAttrString((PyObject *)self, |
|---|
| 494 | "_continue"); |
|---|
| 495 | if (!_continue) { |
|---|
| 496 | return NULL; |
|---|
| 497 | } |
|---|
| 498 | if (!cdefer_Deferred__addCallbacks( |
|---|
| 499 | (cdefer_Deferred *)self->result, _continue, |
|---|
| 500 | _continue, Py_None, Py_None, Py_None, Py_None)) { |
|---|
| 501 | return NULL; |
|---|
| 502 | } |
|---|
| 503 | goto endLabel; |
|---|
| 504 | } |
|---|
| 505 | } |
|---|
| 506 | if (PyList_SetSlice(cb, 0, PyList_GET_SIZE(cb), NULL) == -1) { |
|---|
| 507 | return NULL; |
|---|
| 508 | } |
|---|
| 509 | } |
|---|
| 510 | endLabel:; |
|---|
| 511 | if (PyObject_IsInstance(self->result, failure_class)) { |
|---|
| 512 | if (!PyObject_CallMethod((PyObject *)self->result, |
|---|
| 513 | "cleanFailure", NULL)) { |
|---|
| 514 | return NULL; |
|---|
| 515 | } |
|---|
| 516 | } |
|---|
| 517 | Py_INCREF(Py_None); |
|---|
| 518 | return Py_None; |
|---|
| 519 | } |
|---|
| 520 | |
|---|
| 521 | static PyObject *cdefer_Deferred__startRunCallbacks(cdefer_Deferred *self, |
|---|
| 522 | PyObject *result) { |
|---|
| 523 | if (self->called) { |
|---|
| 524 | PyErr_SetNone(already_called); |
|---|
| 525 | return NULL; |
|---|
| 526 | } |
|---|
| 527 | self->called = 1; |
|---|
| 528 | Py_XDECREF(self->result); |
|---|
| 529 | self->result = result; |
|---|
| 530 | Py_INCREF(self->result); |
|---|
| 531 | return cdefer_Deferred__runCallbacks(self); |
|---|
| 532 | } |
|---|
| 533 | |
|---|
| 534 | static char cdefer_Deferred_callback_doc[] = "Run all success callbacks that have been added to this Deferred.\n\nEach callback will have its result passed as the first\nargument to the next; this way, the callbacks act as a\n\'processing chain\'. Also, if the success-callback returns a Failure\nor raises an Exception, processing will continue on the *error*-\ncallback chain."; |
|---|
| 535 | |
|---|
| 536 | static PyObject *cdefer_Deferred_callback(cdefer_Deferred *self, PyObject *args, |
|---|
| 537 | PyObject *kwargs) { |
|---|
| 538 | PyObject *result; |
|---|
| 539 | static char *argnames[] = {"result", NULL}; |
|---|
| 540 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", argnames, &result)) { |
|---|
| 541 | return NULL; |
|---|
| 542 | } |
|---|
| 543 | return cdefer_Deferred__startRunCallbacks(self, result); |
|---|
| 544 | } |
|---|
| 545 | |
|---|
| 546 | static char cdefer_Deferred_errback_doc[] = "Run all error callbacks that have been added to this Deferred.\n\nEach callback will have its result passed as the first\nargument to the next; this way, the callbacks act as a\n\'processing chain\'. Also, if the error-callback returns a non-Failure\nor doesn\'t raise an Exception, processing will continue on the\n*success*-callback chain.\n\nIf the argument that\'s passed to me is not a Failure instance,\nit will be embedded in one. If no argument is passed, a Failure\ninstance will be created based on the current traceback stack.\n\nPassing a string as `fail\' is deprecated, and will be punished with\na warning message."; |
|---|
| 547 | |
|---|
| 548 | static PyObject *cdefer_Deferred_errback(cdefer_Deferred *self, PyObject *args, |
|---|
| 549 | PyObject *kwargs) { |
|---|
| 550 | PyObject *fail; |
|---|
| 551 | PyObject *tpl; |
|---|
| 552 | PyObject *tmp; |
|---|
| 553 | static char *argnames[] = {"fail", NULL}; |
|---|
| 554 | fail = Py_None; |
|---|
| 555 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", argnames, &fail)) { |
|---|
| 556 | return NULL; |
|---|
| 557 | } |
|---|
| 558 | if (!PyObject_IsInstance(fail, failure_class)) { |
|---|
| 559 | tpl = Py_BuildValue("(O)", fail); |
|---|
| 560 | if (!tpl) { |
|---|
| 561 | return NULL; |
|---|
| 562 | } |
|---|
| 563 | Py_INCREF(fail); |
|---|
| 564 | tmp = PyObject_CallObject(failure_class, tpl); |
|---|
| 565 | Py_CLEAR(tpl); |
|---|
| 566 | Py_DECREF(fail); |
|---|
| 567 | fail = tmp; |
|---|
| 568 | } |
|---|
| 569 | return cdefer_Deferred__startRunCallbacks(self, fail); |
|---|
| 570 | } |
|---|
| 571 | |
|---|
| 572 | static PyObject *cdefer_Deferred__continue(cdefer_Deferred *self, |
|---|
| 573 | PyObject *args, PyObject *kwargs) { |
|---|
| 574 | PyObject *result; |
|---|
| 575 | static char *argnames[] = {"result", NULL}; |
|---|
| 576 | if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", argnames, &result)) { |
|---|
| 577 | return NULL; |
|---|
| 578 | } |
|---|
| 579 | Py_XDECREF(self->result); |
|---|
| 580 | self->result = result; |
|---|
| 581 | Py_INCREF(self->result); |
|---|
| 582 | return PyObject_CallMethod((PyObject *)self, "unpause", NULL); |
|---|
| 583 | } |
|---|
| 584 | |
|---|
| 585 | static struct PyMethodDef cdefer_Deferred_methods[] = { |
|---|
| 586 | {"addCallbacks", (PyCFunction)cdefer_Deferred_addCallbacks, |
|---|
| 587 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_addCallbacks_doc}, |
|---|
| 588 | {"addCallback", (PyCFunction)cdefer_Deferred_addCallback, |
|---|
| 589 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_addCallback_doc}, |
|---|
| 590 | {"addErrback", (PyCFunction)cdefer_Deferred_addErrback, |
|---|
| 591 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_addErrback_doc}, |
|---|
| 592 | {"addBoth", (PyCFunction)cdefer_Deferred_addBoth, |
|---|
| 593 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_addBoth_doc}, |
|---|
| 594 | {"chainDeferred", (PyCFunction)cdefer_Deferred_chainDeferred, |
|---|
| 595 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_chainDeferred_doc}, |
|---|
| 596 | {"callback", (PyCFunction)cdefer_Deferred_callback, |
|---|
| 597 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_callback_doc}, |
|---|
| 598 | {"errback", (PyCFunction)cdefer_Deferred_errback, |
|---|
| 599 | METH_VARARGS|METH_KEYWORDS, cdefer_Deferred_errback_doc}, |
|---|
| 600 | {"pause", (PyCFunction)cdefer_Deferred_pause, |
|---|
| 601 | METH_VARARGS, cdefer_Deferred_pause_doc}, |
|---|
| 602 | {"unpause", (PyCFunction)cdefer_Deferred_unpause, |
|---|
| 603 | METH_VARARGS, cdefer_Deferred_unpause_doc}, |
|---|
| 604 | {"_continue", (PyCFunction)cdefer_Deferred__continue, |
|---|
| 605 | METH_VARARGS|METH_KEYWORDS, ""}, |
|---|
| 606 | {0, 0, 0, 0} |
|---|
| 607 | }; |
|---|
| 608 | |
|---|
| 609 | static struct PyMemberDef cdefer_Deferred_members[] = { |
|---|
| 610 | {"result", T_OBJECT, offsetof(cdefer_Deferred, result), 0, 0}, |
|---|
| 611 | {"paused", T_INT, offsetof(cdefer_Deferred, paused), READONLY, 0}, |
|---|
| 612 | {"called", T_INT, offsetof(cdefer_Deferred, called), READONLY, 0}, |
|---|
| 613 | {"callbacks", T_OBJECT, offsetof(cdefer_Deferred, callbacks), READONLY, 0}, |
|---|
| 614 | {0, 0, 0, 0, 0} |
|---|
| 615 | }; |
|---|
| 616 | |
|---|
| 617 | static PyTypeObject cdefer_DeferredType = { |
|---|
| 618 | PyObject_HEAD_INIT(0) |
|---|
| 619 | 0, /*ob_size*/ |
|---|
| 620 | "cdefer.Deferred", /*tp_name*/ |
|---|
| 621 | sizeof(cdefer_Deferred), /*tp_basicsize*/ |
|---|
| 622 | 0, /*tp_itemsize*/ |
|---|
| 623 | (destructor)cdefer_Deferred_dealloc, /*tp_dealloc*/ |
|---|
| 624 | 0, /*tp_print*/ |
|---|
| 625 | 0, /*tp_getattr*/ |
|---|
| 626 | 0, /*tp_setattr*/ |
|---|
| 627 | 0, /*tp_compare*/ |
|---|
| 628 | 0, /*tp_repr*/ |
|---|
| 629 | 0, /*tp_as_number*/ |
|---|
| 630 | 0, /*tp_as_sequence*/ |
|---|
| 631 | 0, /*tp_as_mapping*/ |
|---|
| 632 | 0, /*tp_hash */ |
|---|
| 633 | 0, /*tp_call*/ |
|---|
| 634 | 0, /*tp_str*/ |
|---|
| 635 | 0, /*tp_getattro*/ |
|---|
| 636 | 0, /*tp_setattro*/ |
|---|
| 637 | 0, /*tp_as_buffer*/ |
|---|
| 638 | Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE|Py_TPFLAGS_HAVE_GC, /*tp_flags*/ |
|---|
| 639 | "This is a callback which will be put off until later.\n\nWhy do we want this? Well, in cases where a function in a threaded\nprogram would block until it gets a result, for Twisted it should\nnot block. Instead, it should return a Deferred.\n\nThis can be implemented for protocols that run over the network by\nwriting an asynchronous protocol for twisted.internet. For methods\nthat come from outside packages that are not under our control, we use\nthreads (see for example L{twisted.enterprise.adbapi}).\n\nFor more information about Deferreds, see doc/howto/defer.html or\nU{http://www.twistedmatrix.com/documents/howto/defer}.", /*tp_doc*/ |
|---|
| 640 | (traverseproc)cdefer_Deferred_traverse, /*tp_traverse*/ |
|---|
| 641 | (inquiry)cdefer_Deferred_clear, /*tp_clear*/ |
|---|
| 642 | 0, /*tp_richcompare*/ |
|---|
| 643 | 0, /*tp_weaklistoffset*/ |
|---|
| 644 | 0, /*tp_iter*/ |
|---|
| 645 | 0, /*tp_iternext*/ |
|---|
| 646 | cdefer_Deferred_methods, /*tp_methods*/ |
|---|
| 647 | cdefer_Deferred_members, /*tp_members*/ |
|---|
| 648 | 0, /*tp_getset*/ |
|---|
| 649 | 0, /*tp_base*/ |
|---|
| 650 | 0, /*tp_dict*/ |
|---|
| 651 | 0, /*tp_descr_get*/ |
|---|
| 652 | 0, /*tp_descr_set*/ |
|---|
| 653 | 0, /*tp_dictoffset*/ |
|---|
| 654 | (initproc)cdefer_Deferred___init__, /*tp_init*/ |
|---|
| 655 | 0, /*tp_alloc*/ |
|---|
| 656 | cdefer_Deferred_new, /*tp_new*/ |
|---|
| 657 | PyObject_GC_Del, /*tp_free*/ |
|---|
| 658 | 0, /*tp_is_gc*/ |
|---|
| 659 | 0, /*tp_bases*/ |
|---|
| 660 | 0, /*tp_mro*/ |
|---|
| 661 | 0, /*tp_cache*/ |
|---|
| 662 | 0, /*tp_subclasses*/ |
|---|
| 663 | 0, /*tp_weaklist*/ |
|---|
| 664 | }; |
|---|
| 665 | |
|---|
| 666 | static PyMethodDef cdefer_methods[] = { |
|---|
| 667 | {NULL} /* Sentinel */ |
|---|
| 668 | }; |
|---|
| 669 | |
|---|
| 670 | #ifndef PyMODINIT_FUNC /* declarations for DLL import/export */ |
|---|
| 671 | #define PyMODINIT_FUNC void |
|---|
| 672 | #endif |
|---|
| 673 | PyMODINIT_FUNC initcdefer(void) { |
|---|
| 674 | PyObject* m; |
|---|
| 675 | PyObject* f; |
|---|
| 676 | PyObject* d; |
|---|
| 677 | |
|---|
| 678 | if (PyType_Ready(&cdefer_DeferredType) < 0) { |
|---|
| 679 | return; |
|---|
| 680 | } |
|---|
| 681 | |
|---|
| 682 | m = Py_InitModule3("cdefer", cdefer_methods, |
|---|
| 683 | "cdefer"); |
|---|
| 684 | |
|---|
| 685 | if (!m) { |
|---|
| 686 | return; |
|---|
| 687 | } |
|---|
| 688 | |
|---|
| 689 | Py_INCREF(&cdefer_DeferredType); |
|---|
| 690 | PyModule_AddObject(m, "Deferred", (PyObject *)&cdefer_DeferredType); |
|---|
| 691 | |
|---|
| 692 | f = PyImport_ImportModule("twisted.python.failure"); |
|---|
| 693 | if (!f) { |
|---|
| 694 | return; |
|---|
| 695 | } |
|---|
| 696 | failure_class = PyObject_GetAttrString(f, "Failure"); |
|---|
| 697 | if (!failure_class) { |
|---|
| 698 | return; |
|---|
| 699 | } |
|---|
| 700 | |
|---|
| 701 | d = PyImport_ImportModule("twisted.internet.defer"); |
|---|
| 702 | if (!d) { |
|---|
| 703 | return; |
|---|
| 704 | } |
|---|
| 705 | already_called = PyObject_GetAttrString(d, "AlreadyCalledError"); |
|---|
| 706 | if (!already_called) { |
|---|
| 707 | return; |
|---|
| 708 | } |
|---|
| 709 | } |
|---|