Ticket #2245: cdefer.7.patch
| File cdefer.7.patch, 9.7 KB (added by Peaker, 6 years ago) |
|---|
-
twisted/internet/cdefer/cdefer.c
37 37 PyObject * failure_class = NULL; 38 38 PyObject * already_called = NULL; 39 39 PyObject * debuginfo_class = NULL; 40 PyObject * format_stack = NULL; 40 41 41 42 typedef struct { 42 43 PyObject_HEAD … … 55 56 56 57 /* Prototypes */ 57 58 59 static PyObject *cdefer_setDebugging(cdefer_Deferred *self, 60 PyObject *args, PyObject *kwargs); 61 62 static PyObject *cdefer_getDebugging(cdefer_Deferred *self, 63 PyObject *args, PyObject *kwargs); 64 58 65 static PyObject * cdefer_Deferred_new(PyTypeObject *type, PyObject *args, 59 66 PyObject *kwargs); 60 67 … … 105 112 static PyObject *cdefer_Deferred__continue(cdefer_Deferred *self, 106 113 PyObject *args, PyObject *kwargs); 107 114 115 116 static int is_debug = 0; 117 118 static PyObject *cdefer_setDebugging(cdefer_Deferred *self, 119 PyObject *args, PyObject *kwargs) 120 { 121 int new_debug; 122 PyObject *on; 123 static char *argnames[] = {"on", NULL}; 124 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O", argnames, &on)) { 125 return NULL; 126 } 127 new_debug = PyObject_IsTrue(on); 128 if (-1 == new_debug) { 129 return NULL; 130 } 131 is_debug = new_debug; 132 Py_INCREF(Py_None); 133 return Py_None; 134 } 135 136 static char cdefer_setDebugging_doc[] = "Enable or disable Deferred debugging.\n\n When debugging is on, the call stacks from creation and invocation are\n recorded, and added to any AlreadyCalledErrors we raise.\n"; 137 138 139 static PyObject *cdefer_getDebugging(cdefer_Deferred *self, 140 PyObject *args, PyObject *kwargs) 141 { 142 static char *argnames[] = {NULL}; 143 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", argnames)) { 144 return NULL; 145 } 146 return PyBool_FromLong(is_debug); 147 } 148 149 static char cdefer_getDebugging_doc[] = "Determine whether Deferred debugging is enabled.\n"; 150 151 108 152 static PyTypeObject cdefer_DeferredType; 109 153 110 154 static PyObject * cdefer_Deferred_new(PyTypeObject *type, PyObject *args, 111 PyObject *kwargs) { 155 PyObject *kwargs) 156 { 112 157 cdefer_Deferred *self; 113 158 self = (cdefer_Deferred *)type->tp_alloc(type, 0); 114 159 return (PyObject *)self; … … 142 187 return 0; 143 188 } 144 189 190 static int cdefer_Deferred__set_debug_stack(cdefer_Deferred *self, char *name) 191 { 192 int rc; 193 PyObject *stack; 194 195 /* Keep the debug info object even if we fail to format stack 196 * or place it into the dict. */ 197 stack = PyObject_CallObject(format_stack, NULL); 198 if (!stack) { 199 return -1; 200 } 201 rc = PyObject_SetAttrString(self->debuginfo, name, stack); 202 /* Unlike other functions of this naming convention (and 203 * unlike PyDict_GetItemString), PyDict_SetItemString 204 * copies/creates a new reference, so we shouldn't keep ours 205 * too. */ 206 Py_DECREF(stack); 207 if (-1 == rc) { 208 return -1; 209 } 210 return 0; 211 } 212 145 213 static int cdefer_Deferred___init__(cdefer_Deferred *self, PyObject *args, 146 PyObject *kwargs) { 214 PyObject *kwargs) 215 { 147 216 static char *argnames[] = {NULL}; 148 217 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "", argnames)) { 149 218 return -1; 150 219 } 220 if (is_debug) { 221 self->debuginfo = PyObject_CallObject(debuginfo_class, NULL); 222 if (!self->debuginfo) { 223 return -1; 224 } 225 if (-1 == cdefer_Deferred__set_debug_stack(self, "creator")) { 226 return -1; 227 } 228 } 229 151 230 self->paused = 0; 152 231 self->callback_index = 0; 153 232 self->callbacks = PyList_New(0); … … 411 490 PyObject *newArgs2; 412 491 PyObject *kwargs; 413 492 PyObject *_continue; 414 PyObject *type, *value, *traceback , *failArgs;493 PyObject *type, *value, *traceback; 415 494 PyObject *tmp; 416 495 PyObject *result; 417 496 int size; … … 492 571 Py_INCREF(traceback); 493 572 } 494 573 495 failArgs = Py_BuildValue("(OOO)", value, type, traceback); 496 if (!failArgs) { 497 PyErr_Restore(type, value, traceback); 498 return NULL; 499 } 500 self->result = PyObject_CallObject(failure_class, failArgs); 501 Py_DECREF(failArgs); 574 self->result = PyObject_CallFunction(failure_class, "OOO", value, type, traceback); 502 575 if (!self->result) { 503 576 PyErr_Restore(type, value, traceback); 504 577 return NULL; … … 569 642 } 570 643 571 644 static PyObject *cdefer_Deferred__startRunCallbacks(cdefer_Deferred *self, 572 PyObject *result) { 645 PyObject *result) 646 { 647 PyObject * already_called_instance; 648 PyObject * debug_tracebacks; 649 650 if (is_debug && !self->debuginfo) { 651 self->debuginfo = PyObject_CallObject(debuginfo_class, NULL); 652 if (!self->debuginfo) { 653 return NULL; 654 } 655 } 656 573 657 if (self->called) { 658 if (is_debug) { 659 debug_tracebacks = PyObject_CallMethod( 660 self->debuginfo, "_getDebugTracebacks", "s", "\n"); 661 if (!debug_tracebacks) { 662 return NULL; 663 } 664 already_called_instance = PyObject_CallFunction(already_called, "O", debug_tracebacks); 665 Py_DECREF(debug_tracebacks); 666 if (!already_called_instance) { 667 return NULL; 668 } 669 PyErr_SetObject(already_called, already_called_instance); 670 Py_DECREF(already_called_instance); 671 return NULL; 672 } 574 673 PyErr_SetNone(already_called); 575 674 return NULL; 576 675 } 676 if (is_debug) { 677 if (-1 == cdefer_Deferred__set_debug_stack(self, "invoker")) { 678 return NULL; 679 } 680 } 681 577 682 self->called = 1; 578 683 Py_XDECREF(self->result); 579 684 self->result = result; … … 598 703 static PyObject *cdefer_Deferred_errback(cdefer_Deferred *self, PyObject *args, 599 704 PyObject *kwargs) { 600 705 PyObject *fail; 601 PyObject *tpl;602 706 PyObject *tmp; 603 707 PyObject *result; 604 708 static char *argnames[] = {"fail", NULL}; … … 612 716 * wrapper (If we do, the wrapper belongs to us) */ 613 717 Py_INCREF(fail); 614 718 } else { 615 tpl = Py_BuildValue("(O)", fail); 616 if (!tpl) { 617 return NULL; 618 } 619 tmp = PyObject_CallObject(failure_class, tpl); 620 Py_DECREF(tpl); 719 tmp = PyObject_CallFunction(failure_class, "(O)", fail); 621 720 if (!tmp) { 622 721 return NULL; 623 722 } … … 723 822 }; 724 823 725 824 static PyMethodDef cdefer_methods[] = { 825 {"setDebugging", (PyCFunction)cdefer_setDebugging, 826 METH_VARARGS|METH_KEYWORDS, cdefer_setDebugging_doc}, 827 828 {"getDebugging", (PyCFunction)cdefer_getDebugging, 829 METH_VARARGS|METH_KEYWORDS, cdefer_getDebugging_doc}, 830 726 831 {NULL} /* Sentinel */ 727 832 }; 728 833 … … 733 838 PyObject * m = NULL; 734 839 PyObject * f = NULL; 735 840 PyObject * d = NULL; 841 PyObject * traceback_module = NULL; 736 842 737 843 if (PyType_Ready(&cdefer_DeferredType) < 0) { 738 844 return; … … 771 877 if(!debuginfo_class) { 772 878 goto Error; 773 879 } 774 880 881 traceback_module = PyImport_ImportModule("traceback"); 882 if (!traceback_module) { 883 goto Error; 884 } 885 886 format_stack = PyObject_GetAttrString(traceback_module, "format_stack"); 887 if(!format_stack) { 888 goto Error; 889 } 890 775 891 return; 776 892 Error: 777 893 Py_XDECREF(f); … … 779 895 Py_XDECREF(d); 780 896 Py_XDECREF(already_called); 781 897 Py_XDECREF(debuginfo_class); 898 Py_XDECREF(traceback_module); 899 Py_XDECREF(format_stack); 782 900 } 783 901 -
twisted/internet/defer.py
281 281 self.unpause() 282 282 283 283 def _startRunCallbacks(self, result): 284 if self.debug and self._debugInfo is None: 285 self._debugInfo = DebugInfo() 284 286 if self.called: 285 287 if self.debug: 286 if self._debugInfo is None: 287 self._debugInfo = DebugInfo() 288 extra = "\n" + self._debugInfo._getDebugTracebacks() 288 extra = self._debugInfo._getDebugTracebacks("\n") 289 289 raise AlreadyCalledError(extra) 290 290 raise AlreadyCalledError 291 291 if self.debug: 292 if self._debugInfo is None:293 self._debugInfo = DebugInfo()294 292 self._debugInfo.invoker = traceback.format_stack()[:-2] 295 293 self.called = True 296 294 self.result = result … … 376 374 """Deferred debug helper""" 377 375 failResult = None 378 376 379 def _getDebugTracebacks(self ):380 info = ''377 def _getDebugTracebacks(self, prefix=''): 378 info = prefix 381 379 if hasattr(self, "creator"): 382 380 info += " C: Deferred was created:\n C:" 383 381 info += "".join(self.creator).rstrip().replace("\n","\n C:") … … 439 437 return False 440 438 441 439 try: 442 from twisted.internet.cdefer import Deferred as CDeferred440 from twisted.internet.cdefer import Deferred, setDebugging, getDebugging 443 441 except ImportError: 444 442 pass 445 else:446 PyDeferred = Deferred447 PyDeferred.debug = True448 # Debugging enabled via use of PyDeferred449 def setDebugging(new_value):450 global is_debug, Deferred451 is_debug = new_value452 if is_debug:453 Deferred = PyDeferred454 else:455 Deferred = CDeferred456 def getDebugging():457 global is_debug458 return is_debug459 443 460 setDebugging(False)461 462 444 class DeferredList(Deferred): 463 445 """I combine a group of deferreds into one callback. 464 446
