#include "Python.h" #include "structmember.h" /* identifiers used from some functions */ _Py_IDENTIFIER(call_soon); /* State of the _futures module */ static int _futuremod_ready; static PyObject *traceback_extract_stack; static PyObject *asyncio_get_event_loop; static PyObject *asyncio_repr_info_func; static PyObject *asyncio_InvalidStateError; static PyObject *asyncio_CancelledError; /* Get FutureIter from Future */ static PyObject* new_future_iter(PyObject *fut); /* make sure module state is initialized and ready to be used. */ static int _FuturesMod_EnsureState(void) { if (!_futuremod_ready) { PyErr_SetString(PyExc_RuntimeError, "_futures module wasn't properly initialized"); return -1; } return 0; } typedef enum { STATE_PENDING, STATE_CANCELLED, STATE_FINISHED } fut_state; typedef struct { PyObject_HEAD PyObject *fut_loop; PyObject *fut_callbacks; PyObject *fut_exception; PyObject *fut_result; PyObject *fut_source_tb; fut_state fut_state; int fut_log_tb; int fut_blocking; PyObject *dict; PyObject *fut_weakreflist; } FutureObj; static int _schedule_callbacks(FutureObj *fut) { Py_ssize_t len; PyObject* iters; int i; if (fut->fut_callbacks == NULL) { PyErr_SetString(PyExc_RuntimeError, "NULL callbacks"); return -1; } len = PyList_GET_SIZE(fut->fut_callbacks); if (len == 0) { return 0; } iters = PyList_GetSlice(fut->fut_callbacks, 0, len); if (iters == NULL) { return -1; } if (PyList_SetSlice(fut->fut_callbacks, 0, len, NULL) < 0) { Py_DECREF(iters); return -1; } for (i = 0; i < len; i++) { PyObject *handle = NULL; PyObject *cb = PyList_GET_ITEM(iters, i); handle = _PyObject_CallMethodId( fut->fut_loop, &PyId_call_soon, "OO", cb, fut, NULL); if (handle == NULL) { Py_DECREF(iters); return -1; } else { Py_DECREF(handle); } } Py_DECREF(iters); return 0; } static int FutureObj_init(FutureObj *fut, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"loop", NULL}; PyObject *loop = NULL; PyObject *res = NULL; _Py_IDENTIFIER(get_debug); if (_FuturesMod_EnsureState()) { return -1; } if (!PyArg_ParseTupleAndKeywords(args, kwds, "|$O", kwlist, &loop)) { return -1; } if (loop == NULL || loop == Py_None) { loop = PyObject_CallObject(asyncio_get_event_loop, NULL); if (loop == NULL) { return -1; } } else { Py_INCREF(loop); } Py_CLEAR(fut->fut_loop); fut->fut_loop = loop; res = _PyObject_CallMethodId(fut->fut_loop, &PyId_get_debug, "()", NULL); if (res == NULL) { return -1; } if (PyObject_IsTrue(res)) { Py_CLEAR(res); fut->fut_source_tb = PyObject_CallObject(traceback_extract_stack, NULL); if (fut->fut_source_tb == NULL) { return -1; } } else { Py_CLEAR(res); } fut->fut_callbacks = PyList_New(0); if (fut->fut_callbacks == NULL) { return -1; } return 0; } static int FutureObj_clear(FutureObj *fut) { Py_CLEAR(fut->fut_loop); Py_CLEAR(fut->fut_callbacks); Py_CLEAR(fut->fut_result); Py_CLEAR(fut->fut_exception); Py_CLEAR(fut->fut_source_tb); Py_CLEAR(fut->dict); return 0; } static int FutureObj_traverse(FutureObj *fut, visitproc visit, void *arg) { Py_VISIT(fut->fut_loop); Py_VISIT(fut->fut_callbacks); Py_VISIT(fut->fut_result); Py_VISIT(fut->fut_exception); Py_VISIT(fut->fut_source_tb); Py_VISIT(fut->dict); return 0; } PyDoc_STRVAR(pydoc_result, "Return the result this future represents.\n" "\n" "If the future has been cancelled, raises CancelledError. If the\n" "future's result isn't yet available, raises InvalidStateError. If\n" "the future is done and has an exception set, this exception is raised." ); static PyObject * FutureObj_result(FutureObj *fut, PyObject *arg) { if (fut->fut_state == STATE_CANCELLED) { PyErr_SetString(asyncio_CancelledError, ""); return NULL; } if (fut->fut_state != STATE_FINISHED) { PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); return NULL; } fut->fut_log_tb = 0; if (fut->fut_exception != NULL) { PyObject *type = NULL; type = PyExceptionInstance_Class(fut->fut_exception); PyErr_SetObject(type, fut->fut_exception); return NULL; } Py_INCREF(fut->fut_result); return fut->fut_result; } PyDoc_STRVAR(pydoc_exception, "Return the exception that was set on this future.\n" "\n" "The exception (or None if no exception was set) is returned only if\n" "the future is done. If the future has been cancelled, raises\n" "CancelledError. If the future isn't done yet, raises\n" "InvalidStateError." ); static PyObject * FutureObj_exception(FutureObj *fut, PyObject *arg) { if (_FuturesMod_EnsureState()) { return NULL; } if (fut->fut_state == STATE_CANCELLED) { PyErr_SetString(asyncio_CancelledError, ""); return NULL; } if (fut->fut_state != STATE_FINISHED) { PyErr_SetString(asyncio_InvalidStateError, "Result is not ready."); return NULL; } if (fut->fut_exception != NULL) { fut->fut_log_tb = 0; Py_INCREF(fut->fut_exception); return fut->fut_exception; } Py_RETURN_NONE; } PyDoc_STRVAR(pydoc_set_result, "Mark the future done and set its result.\n" "\n" "If the future is already done when this method is called, raises\n" "InvalidStateError." ); static PyObject * FutureObj_set_result(FutureObj *fut, PyObject *res) { if (_FuturesMod_EnsureState()) { return NULL; } if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; } Py_INCREF(res); fut->fut_result = res; fut->fut_state = STATE_FINISHED; if (_schedule_callbacks(fut) == -1) { return NULL; } Py_RETURN_NONE; } PyDoc_STRVAR(pydoc_set_exception, "Mark the future done and set an exception.\n" "\n" "If the future is already done when this method is called, raises\n" "InvalidStateError." ); static PyObject * FutureObj_set_exception(FutureObj *fut, PyObject *exc) { PyObject *exc_val = NULL; if (_FuturesMod_EnsureState()) { return NULL; } if (fut->fut_state != STATE_PENDING) { PyErr_SetString(asyncio_InvalidStateError, "invalid state"); return NULL; } if (PyExceptionClass_Check(exc)) { exc_val = PyObject_CallObject(exc, NULL); if (exc_val == NULL) { return NULL; } } else { exc_val = exc; Py_INCREF(exc_val); } if (!PyExceptionInstance_Check(exc_val)) { Py_DECREF(exc_val); PyErr_SetString(PyExc_TypeError, "invalid exception object"); return NULL; } if ((PyObject*)Py_TYPE(exc_val) == PyExc_StopIteration) { Py_DECREF(exc_val); PyErr_SetString(PyExc_TypeError, "StopIteration interacts badly with generators " "and cannot be raised into a Future"); return NULL; } fut->fut_exception = exc_val; fut->fut_state = STATE_FINISHED; if (_schedule_callbacks(fut) == -1) { return NULL; } fut->fut_log_tb = 1; Py_RETURN_NONE; } PyDoc_STRVAR(pydoc_add_done_callback, "Add a callback to be run when the future becomes done.\n" "\n" "The callback is called with a single argument - the future object. If\n" "the future is already done when this is called, the callback is\n" "scheduled with call_soon."; ); static PyObject * FutureObj_add_done_callback(FutureObj *fut, PyObject *arg) { if (fut->fut_state != STATE_PENDING) { PyObject *handle = _PyObject_CallMethodId( fut->fut_loop, &PyId_call_soon, "OO", arg, fut, NULL); if (handle == NULL) { return NULL; } else { Py_DECREF(handle); } } else { int err = PyList_Append(fut->fut_callbacks, arg); if (err != 0) { return NULL; } } Py_RETURN_NONE; } PyDoc_STRVAR(pydoc_remove_done_callback, "Remove all instances of a callback from the \"call when done\" list.\n" "\n" "Returns the number of callbacks removed." ); static PyObject * FutureObj_remove_done_callback(FutureObj *fut, PyObject *arg) { PyObject *newlist; Py_ssize_t len, i, j=0; len = PyList_GET_SIZE(fut->fut_callbacks); if (len == 0) { return PyLong_FromSsize_t(0); } newlist = PyList_New(len); if (newlist == NULL) { return NULL; } for (i = 0; i < len; i++) { int ret; PyObject *item = PyList_GET_ITEM(fut->fut_callbacks, i); if ((ret = PyObject_RichCompareBool(arg, item, Py_EQ)) < 0) { goto fail; } if (ret == 0) { Py_INCREF(item); PyList_SET_ITEM(newlist, j, item); j++; } } if (PyList_SetSlice(newlist, j, len, NULL) < 0) { goto fail; } if (PyList_SetSlice(fut->fut_callbacks, 0, len, newlist) < 0) { goto fail; } Py_DECREF(newlist); return PyLong_FromSsize_t(len - j); fail: Py_DECREF(newlist); return NULL; } PyDoc_STRVAR(pydoc_cancel, "Cancel the future and schedule callbacks.\n" "\n" "If the future is already done or cancelled, return False. Otherwise,\n" "change the future's state to cancelled, schedule the callbacks and\n" "return True." ); static PyObject * FutureObj_cancel(FutureObj *fut, PyObject *arg) { if (fut->fut_state != STATE_PENDING) { Py_RETURN_FALSE; } fut->fut_state = STATE_CANCELLED; if (_schedule_callbacks(fut) == -1) { return NULL; } Py_RETURN_TRUE; } PyDoc_STRVAR(pydoc_cancelled, "Return True if the future was cancelled."); static PyObject * FutureObj_cancelled(FutureObj *fut, PyObject *arg) { if (fut->fut_state == STATE_CANCELLED) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } PyDoc_STRVAR(pydoc_done, "Return True if the future is done.\n" "\n" "Done means either that a result / exception are available, or that the\n" "future was cancelled." ); static PyObject * FutureObj_done(FutureObj *fut, PyObject *arg) { if (fut->fut_state == STATE_PENDING) { Py_RETURN_FALSE; } else { Py_RETURN_TRUE; } } static PyObject * FutureObj_get_blocking(FutureObj *fut) { if (fut->fut_blocking) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static int FutureObj_set_blocking(FutureObj *fut, PyObject *val) { int is_true = PyObject_IsTrue(val); if (is_true < 0) { return -1; } fut->fut_blocking = is_true; return 0; } static PyObject * FutureObj_get_log_traceback(FutureObj *fut) { if (fut->fut_log_tb) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * FutureObj_get_loop(FutureObj *fut) { if (fut->fut_loop == NULL) { Py_RETURN_NONE; } Py_INCREF(fut->fut_loop); return fut->fut_loop; } static PyObject * FutureObj_get_callbacks(FutureObj *fut) { if (fut->fut_callbacks == NULL) { Py_RETURN_NONE; } Py_INCREF(fut->fut_callbacks); return fut->fut_callbacks; } static PyObject * FutureObj_get_result(FutureObj *fut) { if (fut->fut_result == NULL) { Py_RETURN_NONE; } Py_INCREF(fut->fut_result); return fut->fut_result; } static PyObject * FutureObj_get_exception(FutureObj *fut) { if (fut->fut_exception == NULL) { Py_RETURN_NONE; } Py_INCREF(fut->fut_exception); return fut->fut_exception; } static PyObject * FutureObj_get_source_traceback(FutureObj *fut) { if (fut->fut_source_tb == NULL) { Py_RETURN_NONE; } Py_INCREF(fut->fut_source_tb); return fut->fut_source_tb; } static PyObject * FutureObj_get_state(FutureObj *fut) { _Py_IDENTIFIER(PENDING); _Py_IDENTIFIER(CANCELLED); _Py_IDENTIFIER(FINISHED); PyObject *ret = NULL; switch (fut->fut_state) { case STATE_PENDING: ret = _PyUnicode_FromId(&PyId_PENDING); break; case STATE_CANCELLED: ret = _PyUnicode_FromId(&PyId_CANCELLED); break; case STATE_FINISHED: ret = _PyUnicode_FromId(&PyId_FINISHED); break; default: assert (0); } Py_INCREF(ret); return ret; } static PyObject* FutureObj__repr_info(FutureObj *fut) { if (asyncio_repr_info_func == NULL) { return PyList_New(0); } return PyObject_CallFunctionObjArgs(asyncio_repr_info_func, fut, NULL); } static PyObject * FutureObj_repr(FutureObj *fut) { _Py_IDENTIFIER(_repr_info); PyObject *_repr_info = _PyUnicode_FromId(&PyId__repr_info); // borrowed if (_repr_info == NULL) { return NULL; } PyObject *rinfo = PyObject_CallMethodObjArgs((PyObject*)fut, _repr_info, NULL); if (rinfo == NULL) { return NULL; } PyObject *sp = PyUnicode_FromString(" "); if (sp == NULL) { Py_DECREF(rinfo); return NULL; } PyObject *rinfo_s = PyUnicode_Join(sp, rinfo); Py_DECREF(sp); Py_DECREF(rinfo); if (rinfo_s == NULL) { return NULL; } PyObject *rstr = NULL; PyObject *type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); if (type_name != NULL) { rstr = PyUnicode_FromFormat("<%S %S>", type_name, rinfo_s); Py_DECREF(type_name); } Py_DECREF(rinfo_s); return rstr; } static void FutureObj_finalize(FutureObj *fut) { _Py_IDENTIFIER(call_exception_handler); _Py_IDENTIFIER(message); _Py_IDENTIFIER(exception); _Py_IDENTIFIER(future); _Py_IDENTIFIER(source_traceback); if (!fut->fut_log_tb) { return; } assert(fut->fut_exception != NULL); fut->fut_log_tb = 0;; PyObject *error_type, *error_value, *error_traceback; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); PyObject *context = NULL; PyObject *type_name = NULL; PyObject *message = NULL; PyObject *func = NULL; PyObject *res = NULL; context = PyDict_New(); if (context == NULL) { goto finally; } type_name = PyObject_GetAttrString((PyObject*)Py_TYPE(fut), "__name__"); if (type_name == NULL) { goto finally; } message = PyUnicode_FromFormat( "%S exception was never retrieved", type_name); if (message == NULL) { goto finally; } if (_PyDict_SetItemId(context, &PyId_message, message) < 0 || _PyDict_SetItemId(context, &PyId_exception, fut->fut_exception) < 0 || _PyDict_SetItemId(context, &PyId_future, (PyObject*)fut) < 0) { goto finally; } if (fut->fut_source_tb != NULL) { if (_PyDict_SetItemId(context, &PyId_source_traceback, fut->fut_source_tb) < 0) { goto finally; } } func = _PyObject_GetAttrId(fut->fut_loop, &PyId_call_exception_handler); if (func != NULL) { res = _PyObject_CallArg1(func, context); if (res == NULL) { PyErr_WriteUnraisable(func); } } finally: Py_CLEAR(context); Py_CLEAR(type_name); Py_CLEAR(message); Py_CLEAR(func); Py_CLEAR(res); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); } static PyAsyncMethods FutureType_as_async = { (unaryfunc)new_future_iter, /* am_await */ 0, /* am_aiter */ 0 /* am_anext */ }; static PyMethodDef FutureType_methods[] = { {"_repr_info", (PyCFunction)FutureObj__repr_info, METH_NOARGS, NULL}, {"add_done_callback", (PyCFunction)FutureObj_add_done_callback, METH_O, pydoc_add_done_callback}, {"remove_done_callback", (PyCFunction)FutureObj_remove_done_callback, METH_O, pydoc_remove_done_callback}, {"set_result", (PyCFunction)FutureObj_set_result, METH_O, pydoc_set_result}, {"set_exception", (PyCFunction)FutureObj_set_exception, METH_O, pydoc_set_exception}, {"cancel", (PyCFunction)FutureObj_cancel, METH_NOARGS, pydoc_cancel}, {"cancelled", (PyCFunction)FutureObj_cancelled, METH_NOARGS, pydoc_cancelled}, {"done", (PyCFunction)FutureObj_done, METH_NOARGS, pydoc_done}, {"result", (PyCFunction)FutureObj_result, METH_NOARGS, pydoc_result}, {"exception", (PyCFunction)FutureObj_exception, METH_NOARGS, pydoc_exception}, {NULL, NULL} /* Sentinel */ }; static PyGetSetDef FutureType_getsetlist[] = { {"_state", (getter)FutureObj_get_state, NULL, NULL}, {"_asyncio_future_blocking", (getter)FutureObj_get_blocking, (setter)FutureObj_set_blocking, NULL}, {"_loop", (getter)FutureObj_get_loop, NULL, NULL}, {"_callbacks", (getter)FutureObj_get_callbacks, NULL, NULL}, {"_result", (getter)FutureObj_get_result, NULL, NULL}, {"_exception", (getter)FutureObj_get_exception, NULL, NULL}, {"_log_traceback", (getter)FutureObj_get_log_traceback, NULL, NULL}, {"_source_traceback", (getter)FutureObj_get_source_traceback, NULL, NULL}, {NULL} /* Sentinel */ }; static void FutureObj_dealloc(PyObject *self); static PyTypeObject FutureType = { PyVarObject_HEAD_INIT(0, 0) "_futures.Future", sizeof(FutureObj), /* tp_basicsize */ .tp_dealloc = FutureObj_dealloc, .tp_as_async = &FutureType_as_async, .tp_repr = (reprfunc)FutureObj_repr, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, .tp_doc = "Fast asyncio.Future implementation.", .tp_traverse = (traverseproc)FutureObj_traverse, .tp_clear = (inquiry)FutureObj_clear, .tp_weaklistoffset = offsetof(FutureObj, fut_weakreflist), .tp_iter = (getiterfunc)new_future_iter, .tp_methods = FutureType_methods, .tp_getset = FutureType_getsetlist, .tp_dictoffset = offsetof(FutureObj, dict), .tp_init = (initproc)FutureObj_init, .tp_new = PyType_GenericNew, .tp_finalize = (destructor)FutureObj_finalize, }; static void FutureObj_dealloc(PyObject *self) { FutureObj *fut = (FutureObj *)self; if (Py_TYPE(fut) == &FutureType) { /* When fut is subclass of Future, finalizer is called from * subtype_dealloc. */ if (PyObject_CallFinalizerFromDealloc(self) < 0) { // resurrected. return; } } if (fut->fut_weakreflist != NULL) { PyObject_ClearWeakRefs(self); } FutureObj_clear(fut); Py_TYPE(fut)->tp_free(fut); } /*********************** Future Iterator **************************/ typedef struct { PyObject_HEAD FutureObj *future; } futureiterobject; static void FutureIter_dealloc(futureiterobject *it) { _PyObject_GC_UNTRACK(it); Py_XDECREF(it->future); PyObject_GC_Del(it); } static PyObject * FutureIter_iternext(futureiterobject *it) { PyObject *res; FutureObj *fut = it->future; if (fut == NULL) { return NULL; } if (fut->fut_state == STATE_PENDING) { if (!fut->fut_blocking) { fut->fut_blocking = 1; Py_INCREF(fut); return (PyObject *)fut; } PyErr_Format(PyExc_AssertionError, "yield from wasn't used with future"); return NULL; } res = FutureObj_result(fut, NULL); if (res != NULL) { // normal result PyErr_SetObject(PyExc_StopIteration, res); Py_DECREF(res); } it->future = NULL; Py_DECREF(fut); return NULL; } static PyObject * FutureIter_send(futureiterobject *self, PyObject *arg) { if (arg != Py_None) { PyErr_Format(PyExc_TypeError, "can't send non-None value to a FutureIter"); return NULL; } return FutureIter_iternext(self); } static PyObject * FutureIter_throw(futureiterobject *self, PyObject *args) { PyObject *type=NULL, *val=NULL, *tb=NULL; if (!PyArg_ParseTuple(args, "O|OO", &type, &val, &tb)) return NULL; if (val == Py_None) { val = NULL; } if (tb == Py_None) { tb = NULL; } Py_CLEAR(self->future); if (tb != NULL) { PyErr_Restore(type, val, tb); } else if (val != NULL) { PyErr_SetObject(type, val); } else { if (PyExceptionClass_Check(type)) { val = PyObject_CallObject(type, NULL); } else { val = type; assert (PyExceptionInstance_Check(val)); type = (PyObject*)Py_TYPE(val); assert (PyExceptionClass_Check(type)); } PyErr_SetObject(type, val); } return FutureIter_iternext(self); } static PyObject * FutureIter_close(futureiterobject *self, PyObject *arg) { Py_CLEAR(self->future); Py_RETURN_NONE; } static int FutureIter_traverse(futureiterobject *it, visitproc visit, void *arg) { Py_VISIT(it->future); return 0; } static PyMethodDef FutureIter_methods[] = { {"send", (PyCFunction)FutureIter_send, METH_O, NULL}, {"throw", (PyCFunction)FutureIter_throw, METH_VARARGS, NULL}, {"close", (PyCFunction)FutureIter_close, METH_NOARGS, NULL}, {NULL, NULL} /* Sentinel */ }; static PyTypeObject FutureIterType = { PyVarObject_HEAD_INIT(0, 0) "_futures.FutureIter", sizeof(futureiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)FutureIter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_as_async */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */ 0, /* tp_doc */ (traverseproc)FutureIter_traverse, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)FutureIter_iternext, /* tp_iternext */ FutureIter_methods, /* tp_methods */ 0, /* tp_members */ }; static PyObject * new_future_iter(PyObject *fut) { futureiterobject *it; if (!PyObject_TypeCheck(fut, &FutureType)) { PyErr_BadInternalCall(); return NULL; } it = PyObject_GC_New(futureiterobject, &FutureIterType); if (it == NULL) { return NULL; } Py_INCREF(fut); it->future = (FutureObj*)fut; _PyObject_GC_TRACK(it); return (PyObject*)it; } /*********************** Module **************************/ PyDoc_STRVAR(module_doc, "Fast asyncio.Future implementation.\n"); PyObject * _init_module(PyObject *self, PyObject *args) { PyObject *extract_stack; PyObject *get_event_loop; PyObject *repr_info_func; PyObject *invalidStateError; PyObject *cancelledError; if (!PyArg_UnpackTuple(args, "_init_module", 5, 5, &extract_stack, &get_event_loop, &repr_info_func, &invalidStateError, &cancelledError)) { return NULL; } Py_INCREF(extract_stack); Py_XSETREF(traceback_extract_stack, extract_stack); Py_INCREF(get_event_loop); Py_XSETREF(asyncio_get_event_loop, get_event_loop); Py_INCREF(repr_info_func); Py_XSETREF(asyncio_repr_info_func, repr_info_func); Py_INCREF(invalidStateError); Py_XSETREF(asyncio_InvalidStateError, invalidStateError); Py_INCREF(cancelledError); Py_XSETREF(asyncio_CancelledError, cancelledError); _futuremod_ready = 1; Py_RETURN_NONE; } static struct PyMethodDef futuresmod_methods[] = { {"_init_module", _init_module, METH_VARARGS, NULL}, {NULL, NULL} }; static struct PyModuleDef _futuresmodule = { PyModuleDef_HEAD_INIT, /* m_base */ "_futures", /* m_name */ module_doc, /* m_doc */ -1, /* m_size */ futuresmod_methods, /* m_methods */ NULL, /* m_slots */ NULL, /* m_traverse */ NULL, /* m_clear */ NULL, /* m_free */ }; PyMODINIT_FUNC PyInit__futures(void) { if (PyType_Ready(&FutureType) < 0) { return NULL; } if (PyType_Ready(&FutureIterType) < 0) { return NULL; } PyObject *m = PyModule_Create(&_futuresmodule); if (m == NULL) { return NULL; } Py_INCREF(&FutureType); if (PyModule_AddObject(m, "Future", (PyObject *)&FutureType) < 0) { Py_DECREF(&FutureType); return NULL; } return m; }