Ticket #2245: cdefer.c

File cdefer.c, 23.5 KB (added by therve, 8 years ago)
Line 
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
34PyObject * failure_class;
35PyObject * already_called;
36
37typedef struct {
38    PyObject_HEAD
39    PyObject *result;
40    int paused;
41    PyObject *callbacks;
42    int called;
43} cdefer_Deferred;
44
45/* Prototypes */
46
47static PyObject * cdefer_Deferred_new(PyTypeObject *type, PyObject *args,
48        PyObject *kwargs);
49
50static void cdefer_Deferred_dealloc(PyObject *o);
51
52static int cdefer_Deferred_traverse(PyObject *o, visitproc visit, void *arg);
53
54static int cdefer_Deferred_clear(PyObject *o);
55
56static int cdefer_Deferred_clear(PyObject *o);
57
58static int cdefer_Deferred___init__(cdefer_Deferred *self, PyObject *args,
59        PyObject *kwargs);
60
61static PyObject *cdefer_Deferred__addCallbacks(cdefer_Deferred *self,
62        PyObject *callback, PyObject *errback, PyObject *callbackArgs,
63        PyObject *callbackKeywords, PyObject *errbackArgs,
64        PyObject *errbackKeywords);
65
66static PyObject *cdefer_Deferred_addCallback(cdefer_Deferred *self,
67        PyObject *args, PyObject *kwargs);
68
69static PyObject *cdefer_Deferred_addErrback(cdefer_Deferred *self,
70        PyObject *args, PyObject *kwargs);
71
72static PyObject *cdefer_Deferred_addBoth(cdefer_Deferred *self, PyObject *args,
73        PyObject *kwargs);
74
75static PyObject *cdefer_Deferred_pause(cdefer_Deferred *self, PyObject *args);
76
77static PyObject *cdefer_Deferred_unpause(cdefer_Deferred *self,
78        PyObject *args);
79
80static PyObject *cdefer_Deferred_chainDeferred(cdefer_Deferred *self,
81        PyObject *args, PyObject *kwargs);
82
83static PyObject *cdefer_Deferred__runCallbacks(cdefer_Deferred *self);
84
85static PyObject *cdefer_Deferred__startRunCallbacks(cdefer_Deferred *self,
86        PyObject *result);
87
88static PyObject *cdefer_Deferred_callback(cdefer_Deferred *self, PyObject *args,
89        PyObject *kwargs);
90
91static PyObject *cdefer_Deferred_errback(cdefer_Deferred *self, PyObject *args,
92        PyObject *kwargs);
93
94static PyObject *cdefer_Deferred__continue(cdefer_Deferred *self,
95        PyObject *args, PyObject *kwargs);
96
97static PyTypeObject cdefer_DeferredType;
98
99static 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
106static 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
115static 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
123static 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
131static 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
145static 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
201static 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
203static 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
229static char cdefer_Deferred_addCallback_doc[] = "Convenience method for adding just a callback.\n\nSee L{addCallbacks}.";
230
231static 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
266static char cdefer_Deferred_addErrback_doc[] = "Convenience method for adding just an errback.\n\nSee L{addCallbacks}.";
267
268static 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
303static char cdefer_Deferred_addBoth_doc[] = "Convenience method for adding a single callable as both a callback\nand an errback.\n\nSee L{addCallbacks}.";
304
305static 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
340static char cdefer_Deferred_pause_doc[] = "Stop processing on a Deferred until L{unpause}() is called.";
341
342static 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
350static char cdefer_Deferred_unpause_doc[] = "Process all callbacks made since L{pause}() was called.";
351
352static 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
362static 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
364static 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
389static 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    }
510endLabel:;
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
521static 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
534static 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
536static 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
546static 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
548static 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
572static 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
585static 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
609static 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
617static 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
666static PyMethodDef cdefer_methods[] = {
667    {NULL}  /* Sentinel */
668};
669
670#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
671#define PyMODINIT_FUNC void
672#endif
673PyMODINIT_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}
710