Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(363)

Side by Side Diff: third_party/pycoverage/coverage/tracer.c

Issue 727003004: Add python coverage module to third_party (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/pycoverage/coverage/templite.py ('k') | third_party/pycoverage/coverage/version.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* C-based Tracer for Coverage. */
2
3 #include "Python.h"
4 #include "compile.h" /* in 2.3, this wasn't part of Python.h */
5 #include "eval.h" /* or this. */
6 #include "structmember.h"
7 #include "frameobject.h"
8
9 /* Compile-time debugging helpers */
10 #undef WHAT_LOG /* Define to log the WHAT params in the trace function. */
11 #undef TRACE_LOG /* Define to log our bookkeeping. */
12 #undef COLLECT_STATS /* Collect counters: stats are printed when tracer is st opped. */
13
14 #if COLLECT_STATS
15 #define STATS(x) x
16 #else
17 #define STATS(x)
18 #endif
19
20 /* Py 2.x and 3.x compatibility */
21
22 #ifndef Py_TYPE
23 #define Py_TYPE(o) (((PyObject*)(o))->ob_type)
24 #endif
25
26 #if PY_MAJOR_VERSION >= 3
27
28 #define MyText_Type PyUnicode_Type
29 #define MyText_Check(o) PyUnicode_Check(o)
30 #define MyText_AS_BYTES(o) PyUnicode_AsASCIIString(o)
31 #define MyText_AS_STRING(o) PyBytes_AS_STRING(o)
32 #define MyInt_FromLong(l) PyLong_FromLong(l)
33
34 #define MyType_HEAD_INIT PyVarObject_HEAD_INIT(NULL, 0)
35
36 #else
37
38 #define MyText_Type PyString_Type
39 #define MyText_Check(o) PyString_Check(o)
40 #define MyText_AS_BYTES(o) (Py_INCREF(o), o)
41 #define MyText_AS_STRING(o) PyString_AS_STRING(o)
42 #define MyInt_FromLong(l) PyInt_FromLong(l)
43
44 #define MyType_HEAD_INIT PyObject_HEAD_INIT(NULL) 0,
45
46 #endif /* Py3k */
47
48 /* The values returned to indicate ok or error. */
49 #define RET_OK 0
50 #define RET_ERROR -1
51
52 /* An entry on the data stack. For each call frame, we need to record the
53 dictionary to capture data, and the last line number executed in that
54 frame.
55 */
56 typedef struct {
57 PyObject * file_data; /* PyMem_Malloc'ed, a borrowed ref. */
58 int last_line;
59 } DataStackEntry;
60
61 /* The CTracer type. */
62
63 typedef struct {
64 PyObject_HEAD
65
66 /* Python objects manipulated directly by the Collector class. */
67 PyObject * should_trace;
68 PyObject * warn;
69 PyObject * data;
70 PyObject * should_trace_cache;
71 PyObject * arcs;
72
73 /* Has the tracer been started? */
74 int started;
75 /* Are we tracing arcs, or just lines? */
76 int tracing_arcs;
77
78 /*
79 The data stack is a stack of dictionaries. Each dictionary collects
80 data for a single source file. The data stack parallels the call stack:
81 each call pushes the new frame's file data onto the data stack, and each
82 return pops file data off.
83
84 The file data is a dictionary whose form depends on the tracing options.
85 If tracing arcs, the keys are line number pairs. If not tracing arcs,
86 the keys are line numbers. In both cases, the value is irrelevant
87 (None).
88 */
89 /* The index of the last-used entry in data_stack. */
90 int depth;
91 /* The file data at each level, or NULL if not recording. */
92 DataStackEntry * data_stack;
93 int data_stack_alloc; /* number of entries allocated at data_stack. */
94
95 /* The current file_data dictionary. Borrowed. */
96 PyObject * cur_file_data;
97
98 /* The line number of the last line recorded, for tracing arcs.
99 -1 means there was no previous line, as when entering a code object.
100 */
101 int last_line;
102
103 /* The parent frame for the last exception event, to fix missing returns. */
104 PyFrameObject * last_exc_back;
105 int last_exc_firstlineno;
106
107 #if COLLECT_STATS
108 struct {
109 unsigned int calls;
110 unsigned int lines;
111 unsigned int returns;
112 unsigned int exceptions;
113 unsigned int others;
114 unsigned int new_files;
115 unsigned int missed_returns;
116 unsigned int stack_reallocs;
117 unsigned int errors;
118 } stats;
119 #endif /* COLLECT_STATS */
120 } CTracer;
121
122 #define STACK_DELTA 100
123
124 static int
125 CTracer_init(CTracer *self, PyObject *args_unused, PyObject *kwds_unused)
126 {
127 #if COLLECT_STATS
128 self->stats.calls = 0;
129 self->stats.lines = 0;
130 self->stats.returns = 0;
131 self->stats.exceptions = 0;
132 self->stats.others = 0;
133 self->stats.new_files = 0;
134 self->stats.missed_returns = 0;
135 self->stats.stack_reallocs = 0;
136 self->stats.errors = 0;
137 #endif /* COLLECT_STATS */
138
139 self->should_trace = NULL;
140 self->warn = NULL;
141 self->data = NULL;
142 self->should_trace_cache = NULL;
143 self->arcs = NULL;
144
145 self->started = 0;
146 self->tracing_arcs = 0;
147
148 self->depth = -1;
149 self->data_stack = PyMem_Malloc(STACK_DELTA*sizeof(DataStackEntry));
150 if (self->data_stack == NULL) {
151 STATS( self->stats.errors++; )
152 PyErr_NoMemory();
153 return RET_ERROR;
154 }
155 self->data_stack_alloc = STACK_DELTA;
156
157 self->cur_file_data = NULL;
158 self->last_line = -1;
159
160 self->last_exc_back = NULL;
161
162 return RET_OK;
163 }
164
165 static void
166 CTracer_dealloc(CTracer *self)
167 {
168 if (self->started) {
169 PyEval_SetTrace(NULL, NULL);
170 }
171
172 Py_XDECREF(self->should_trace);
173 Py_XDECREF(self->warn);
174 Py_XDECREF(self->data);
175 Py_XDECREF(self->should_trace_cache);
176
177 PyMem_Free(self->data_stack);
178
179 Py_TYPE(self)->tp_free((PyObject*)self);
180 }
181
182 #if TRACE_LOG
183 static const char *
184 indent(int n)
185 {
186 static const char * spaces =
187 " "
188 " "
189 " "
190 " "
191 ;
192 return spaces + strlen(spaces) - n*2;
193 }
194
195 static int logging = 0;
196 /* Set these constants to be a file substring and line number to start logging. */
197 static const char * start_file = "tests/views";
198 static int start_line = 27;
199
200 static void
201 showlog(int depth, int lineno, PyObject * filename, const char * msg)
202 {
203 if (logging) {
204 printf("%s%3d ", indent(depth), depth);
205 if (lineno) {
206 printf("%4d", lineno);
207 }
208 else {
209 printf(" ");
210 }
211 if (filename) {
212 PyObject *ascii = MyText_AS_BYTES(filename);
213 printf(" %s", MyText_AS_STRING(ascii));
214 Py_DECREF(ascii);
215 }
216 if (msg) {
217 printf(" %s", msg);
218 }
219 printf("\n");
220 }
221 }
222
223 #define SHOWLOG(a,b,c,d) showlog(a,b,c,d)
224 #else
225 #define SHOWLOG(a,b,c,d)
226 #endif /* TRACE_LOG */
227
228 #if WHAT_LOG
229 static const char * what_sym[] = {"CALL", "EXC ", "LINE", "RET "};
230 #endif
231
232 /* Record a pair of integers in self->cur_file_data. */
233 static int
234 CTracer_record_pair(CTracer *self, int l1, int l2)
235 {
236 int ret = RET_OK;
237
238 PyObject * t = Py_BuildValue("(ii)", l1, l2);
239 if (t != NULL) {
240 if (PyDict_SetItem(self->cur_file_data, t, Py_None) < 0) {
241 STATS( self->stats.errors++; )
242 ret = RET_ERROR;
243 }
244 Py_DECREF(t);
245 }
246 else {
247 STATS( self->stats.errors++; )
248 ret = RET_ERROR;
249 }
250 return ret;
251 }
252
253 /*
254 * The Trace Function
255 */
256 static int
257 CTracer_trace(CTracer *self, PyFrameObject *frame, int what, PyObject *arg_unuse d)
258 {
259 int ret = RET_OK;
260 PyObject * filename = NULL;
261 PyObject * tracename = NULL;
262 #if WHAT_LOG || TRACE_LOG
263 PyObject * ascii = NULL;
264 #endif
265
266 #if WHAT_LOG
267 if (what <= sizeof(what_sym)/sizeof(const char *)) {
268 ascii = MyText_AS_BYTES(frame->f_code->co_filename);
269 printf("trace: %s @ %s %d\n", what_sym[what], MyText_AS_STRING(ascii), f rame->f_lineno);
270 Py_DECREF(ascii);
271 }
272 #endif
273
274 #if TRACE_LOG
275 ascii = MyText_AS_BYTES(frame->f_code->co_filename);
276 if (strstr(MyText_AS_STRING(ascii), start_file) && frame->f_lineno == start_ line) {
277 logging = 1;
278 }
279 Py_DECREF(ascii);
280 #endif
281
282 /* See below for details on missing-return detection. */
283 if (self->last_exc_back) {
284 if (frame == self->last_exc_back) {
285 /* Looks like someone forgot to send a return event. We'll clear
286 the exception state and do the RETURN code here. Notice that the
287 frame we have in hand here is not the correct frame for the RETUR N,
288 that frame is gone. Our handling for RETURN doesn't need the
289 actual frame, but we do log it, so that will look a little off if
290 you're looking at the detailed log.
291
292 If someday we need to examine the frame when doing RETURN, then
293 we'll need to keep more of the missed frame's state.
294 */
295 STATS( self->stats.missed_returns++; )
296 if (self->depth >= 0) {
297 if (self->tracing_arcs && self->cur_file_data) {
298 if (CTracer_record_pair(self, self->last_line, -self->last_e xc_firstlineno) < 0) {
299 return RET_ERROR;
300 }
301 }
302 SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename , "missedreturn");
303 self->cur_file_data = self->data_stack[self->depth].file_data;
304 self->last_line = self->data_stack[self->depth].last_line;
305 self->depth--;
306 }
307 }
308 self->last_exc_back = NULL;
309 }
310
311
312 switch (what) {
313 case PyTrace_CALL: /* 0 */
314 STATS( self->stats.calls++; )
315 /* Grow the stack. */
316 self->depth++;
317 if (self->depth >= self->data_stack_alloc) {
318 STATS( self->stats.stack_reallocs++; )
319 /* We've outgrown our data_stack array: make it bigger. */
320 int bigger = self->data_stack_alloc + STACK_DELTA;
321 DataStackEntry * bigger_data_stack = PyMem_Realloc(self->data_stack, bigger * sizeof(DataStackEntry));
322 if (bigger_data_stack == NULL) {
323 STATS( self->stats.errors++; )
324 PyErr_NoMemory();
325 self->depth--;
326 return RET_ERROR;
327 }
328 self->data_stack = bigger_data_stack;
329 self->data_stack_alloc = bigger;
330 }
331
332 /* Push the current state on the stack. */
333 self->data_stack[self->depth].file_data = self->cur_file_data;
334 self->data_stack[self->depth].last_line = self->last_line;
335
336 /* Check if we should trace this line. */
337 filename = frame->f_code->co_filename;
338 tracename = PyDict_GetItem(self->should_trace_cache, filename);
339 if (tracename == NULL) {
340 STATS( self->stats.new_files++; )
341 /* We've never considered this file before. */
342 /* Ask should_trace about it. */
343 PyObject * args = Py_BuildValue("(OO)", filename, frame);
344 tracename = PyObject_Call(self->should_trace, args, NULL);
345 Py_DECREF(args);
346 if (tracename == NULL) {
347 /* An error occurred inside should_trace. */
348 STATS( self->stats.errors++; )
349 return RET_ERROR;
350 }
351 if (PyDict_SetItem(self->should_trace_cache, filename, tracename) < 0) {
352 STATS( self->stats.errors++; )
353 return RET_ERROR;
354 }
355 }
356 else {
357 Py_INCREF(tracename);
358 }
359
360 /* If tracename is a string, then we're supposed to trace. */
361 if (MyText_Check(tracename)) {
362 PyObject * file_data = PyDict_GetItem(self->data, tracename);
363 if (file_data == NULL) {
364 file_data = PyDict_New();
365 if (file_data == NULL) {
366 STATS( self->stats.errors++; )
367 return RET_ERROR;
368 }
369 ret = PyDict_SetItem(self->data, tracename, file_data);
370 Py_DECREF(file_data);
371 if (ret < 0) {
372 STATS( self->stats.errors++; )
373 return RET_ERROR;
374 }
375 }
376 self->cur_file_data = file_data;
377 /* Make the frame right in case settrace(gettrace()) happens. */
378 Py_INCREF(self);
379 frame->f_trace = (PyObject*)self;
380 SHOWLOG(self->depth, frame->f_lineno, filename, "traced");
381 }
382 else {
383 self->cur_file_data = NULL;
384 SHOWLOG(self->depth, frame->f_lineno, filename, "skipped");
385 }
386
387 Py_DECREF(tracename);
388
389 self->last_line = -1;
390 break;
391
392 case PyTrace_RETURN: /* 3 */
393 STATS( self->stats.returns++; )
394 /* A near-copy of this code is above in the missing-return handler. */
395 if (self->depth >= 0) {
396 if (self->tracing_arcs && self->cur_file_data) {
397 int first = frame->f_code->co_firstlineno;
398 if (CTracer_record_pair(self, self->last_line, -first) < 0) {
399 return RET_ERROR;
400 }
401 }
402
403 SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "r eturn");
404 self->cur_file_data = self->data_stack[self->depth].file_data;
405 self->last_line = self->data_stack[self->depth].last_line;
406 self->depth--;
407 }
408 break;
409
410 case PyTrace_LINE: /* 2 */
411 STATS( self->stats.lines++; )
412 if (self->depth >= 0) {
413 SHOWLOG(self->depth, frame->f_lineno, frame->f_code->co_filename, "l ine");
414 if (self->cur_file_data) {
415 /* We're tracing in this frame: record something. */
416 if (self->tracing_arcs) {
417 /* Tracing arcs: key is (last_line,this_line). */
418 if (CTracer_record_pair(self, self->last_line, frame->f_line no) < 0) {
419 return RET_ERROR;
420 }
421 }
422 else {
423 /* Tracing lines: key is simply this_line. */
424 PyObject * this_line = MyInt_FromLong(frame->f_lineno);
425 if (this_line == NULL) {
426 STATS( self->stats.errors++; )
427 return RET_ERROR;
428 }
429 ret = PyDict_SetItem(self->cur_file_data, this_line, Py_None );
430 Py_DECREF(this_line);
431 if (ret < 0) {
432 STATS( self->stats.errors++; )
433 return RET_ERROR;
434 }
435 }
436 }
437 self->last_line = frame->f_lineno;
438 }
439 break;
440
441 case PyTrace_EXCEPTION:
442 /* Some code (Python 2.3, and pyexpat anywhere) fires an exception event
443 without a return event. To detect that, we'll keep a copy of the
444 parent frame for an exception event. If the next event is in that
445 frame, then we must have returned without a return event. We can
446 synthesize the missing event then.
447
448 Python itself fixed this problem in 2.4. Pyexpat still has the bug.
449 I've reported the problem with pyexpat as http://bugs.python.org/issu e6359 .
450 If it gets fixed, this code should still work properly. Maybe some d ay
451 the bug will be fixed everywhere coverage.py is supported, and we can
452 remove this missing-return detection.
453
454 More about this fix: http://nedbatchelder.com/blog/200907/a_nasty_lit tle_bug.html
455 */
456 STATS( self->stats.exceptions++; )
457 self->last_exc_back = frame->f_back;
458 self->last_exc_firstlineno = frame->f_code->co_firstlineno;
459 break;
460
461 default:
462 STATS( self->stats.others++; )
463 break;
464 }
465
466 return RET_OK;
467 }
468
469 /*
470 * Python has two ways to set the trace function: sys.settrace(fn), which
471 * takes a Python callable, and PyEval_SetTrace(func, obj), which takes
472 * a C function and a Python object. The way these work together is that
473 * sys.settrace(pyfn) calls PyEval_SetTrace(builtin_func, pyfn), using the
474 * Python callable as the object in PyEval_SetTrace. So sys.gettrace()
475 * simply returns the Python object used as the second argument to
476 * PyEval_SetTrace. So sys.gettrace() will return our self parameter, which
477 * means it must be callable to be used in sys.settrace().
478 *
479 * So we make our self callable, equivalent to invoking our trace function.
480 *
481 * To help with the process of replaying stored frames, this function has an
482 * optional keyword argument:
483 *
484 * def CTracer_call(frame, event, arg, lineno=0)
485 *
486 * If provided, the lineno argument is used as the line number, and the
487 * frame's f_lineno member is ignored.
488 */
489 static PyObject *
490 CTracer_call(CTracer *self, PyObject *args, PyObject *kwds)
491 {
492 PyFrameObject *frame;
493 PyObject *what_str;
494 PyObject *arg;
495 int lineno = 0;
496 int what;
497 int orig_lineno;
498 PyObject *ret = NULL;
499
500 static char *what_names[] = {
501 "call", "exception", "line", "return",
502 "c_call", "c_exception", "c_return",
503 NULL
504 };
505
506 #if WHAT_LOG
507 printf("pytrace\n");
508 #endif
509
510 static char *kwlist[] = {"frame", "event", "arg", "lineno", NULL};
511
512 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O|i:Tracer_call", kwlist,
513 &PyFrame_Type, &frame, &MyText_Type, &what_str, &arg, &lineno)) {
514 goto done;
515 }
516
517 /* In Python, the what argument is a string, we need to find an int
518 for the C function. */
519 for (what = 0; what_names[what]; what++) {
520 PyObject *ascii = MyText_AS_BYTES(what_str);
521 int should_break = !strcmp(MyText_AS_STRING(ascii), what_names[what]);
522 Py_DECREF(ascii);
523 if (should_break) {
524 break;
525 }
526 }
527
528 /* Save off the frame's lineno, and use the forced one, if provided. */
529 orig_lineno = frame->f_lineno;
530 if (lineno > 0) {
531 frame->f_lineno = lineno;
532 }
533
534 /* Invoke the C function, and return ourselves. */
535 if (CTracer_trace(self, frame, what, arg) == RET_OK) {
536 Py_INCREF(self);
537 ret = (PyObject *)self;
538 }
539
540 /* Clean up. */
541 frame->f_lineno = orig_lineno;
542
543 done:
544 return ret;
545 }
546
547 static PyObject *
548 CTracer_start(CTracer *self, PyObject *args_unused)
549 {
550 PyEval_SetTrace((Py_tracefunc)CTracer_trace, (PyObject*)self);
551 self->started = 1;
552 self->tracing_arcs = self->arcs && PyObject_IsTrue(self->arcs);
553 self->last_line = -1;
554
555 /* start() returns a trace function usable with sys.settrace() */
556 Py_INCREF(self);
557 return (PyObject *)self;
558 }
559
560 static PyObject *
561 CTracer_stop(CTracer *self, PyObject *args_unused)
562 {
563 if (self->started) {
564 PyEval_SetTrace(NULL, NULL);
565 self->started = 0;
566 }
567
568 return Py_BuildValue("");
569 }
570
571 static PyObject *
572 CTracer_get_stats(CTracer *self)
573 {
574 #if COLLECT_STATS
575 return Py_BuildValue(
576 "{sI,sI,sI,sI,sI,sI,sI,sI,si,sI}",
577 "calls", self->stats.calls,
578 "lines", self->stats.lines,
579 "returns", self->stats.returns,
580 "exceptions", self->stats.exceptions,
581 "others", self->stats.others,
582 "new_files", self->stats.new_files,
583 "missed_returns", self->stats.missed_returns,
584 "stack_reallocs", self->stats.stack_reallocs,
585 "stack_alloc", self->data_stack_alloc,
586 "errors", self->stats.errors
587 );
588 #else
589 return Py_BuildValue("");
590 #endif /* COLLECT_STATS */
591 }
592
593 static PyMemberDef
594 CTracer_members[] = {
595 { "should_trace", T_OBJECT, offsetof(CTracer, should_trace), 0,
596 PyDoc_STR("Function indicating whether to trace a file.") },
597
598 { "warn", T_OBJECT, offsetof(CTracer, warn), 0,
599 PyDoc_STR("Function for issuing warnings.") },
600
601 { "data", T_OBJECT, offsetof(CTracer, data), 0,
602 PyDoc_STR("The raw dictionary of trace data.") },
603
604 { "should_trace_cache", T_OBJECT, offsetof(CTracer, should_trace_cache), 0,
605 PyDoc_STR("Dictionary caching should_trace results.") },
606
607 { "arcs", T_OBJECT, offsetof(CTracer, arcs), 0,
608 PyDoc_STR("Should we trace arcs, or just lines?") },
609
610 { NULL }
611 };
612
613 static PyMethodDef
614 CTracer_methods[] = {
615 { "start", (PyCFunction) CTracer_start, METH_VARARGS,
616 PyDoc_STR("Start the tracer") },
617
618 { "stop", (PyCFunction) CTracer_stop, METH_VARARGS,
619 PyDoc_STR("Stop the tracer") },
620
621 { "get_stats", (PyCFunction) CTracer_get_stats, METH_VARARGS,
622 PyDoc_STR("Get statistics about the tracing") },
623
624 { NULL }
625 };
626
627 static PyTypeObject
628 CTracerType = {
629 MyType_HEAD_INIT
630 "coverage.CTracer", /*tp_name*/
631 sizeof(CTracer), /*tp_basicsize*/
632 0, /*tp_itemsize*/
633 (destructor)CTracer_dealloc, /*tp_dealloc*/
634 0, /*tp_print*/
635 0, /*tp_getattr*/
636 0, /*tp_setattr*/
637 0, /*tp_compare*/
638 0, /*tp_repr*/
639 0, /*tp_as_number*/
640 0, /*tp_as_sequence*/
641 0, /*tp_as_mapping*/
642 0, /*tp_hash */
643 (ternaryfunc)CTracer_call, /*tp_call*/
644 0, /*tp_str*/
645 0, /*tp_getattro*/
646 0, /*tp_setattro*/
647 0, /*tp_as_buffer*/
648 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /*tp_flags*/
649 "CTracer objects", /* tp_doc */
650 0, /* tp_traverse */
651 0, /* tp_clear */
652 0, /* tp_richcompare */
653 0, /* tp_weaklistoffset */
654 0, /* tp_iter */
655 0, /* tp_iternext */
656 CTracer_methods, /* tp_methods */
657 CTracer_members, /* tp_members */
658 0, /* tp_getset */
659 0, /* tp_base */
660 0, /* tp_dict */
661 0, /* tp_descr_get */
662 0, /* tp_descr_set */
663 0, /* tp_dictoffset */
664 (initproc)CTracer_init, /* tp_init */
665 0, /* tp_alloc */
666 0, /* tp_new */
667 };
668
669 /* Module definition */
670
671 #define MODULE_DOC PyDoc_STR("Fast coverage tracer.")
672
673 #if PY_MAJOR_VERSION >= 3
674
675 static PyModuleDef
676 moduledef = {
677 PyModuleDef_HEAD_INIT,
678 "coverage.tracer",
679 MODULE_DOC,
680 -1,
681 NULL, /* methods */
682 NULL,
683 NULL, /* traverse */
684 NULL, /* clear */
685 NULL
686 };
687
688
689 PyObject *
690 PyInit_tracer(void)
691 {
692 PyObject * mod = PyModule_Create(&moduledef);
693 if (mod == NULL) {
694 return NULL;
695 }
696
697 CTracerType.tp_new = PyType_GenericNew;
698 if (PyType_Ready(&CTracerType) < 0) {
699 Py_DECREF(mod);
700 return NULL;
701 }
702
703 Py_INCREF(&CTracerType);
704 PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
705
706 return mod;
707 }
708
709 #else
710
711 void
712 inittracer(void)
713 {
714 PyObject * mod;
715
716 mod = Py_InitModule3("coverage.tracer", NULL, MODULE_DOC);
717 if (mod == NULL) {
718 return;
719 }
720
721 CTracerType.tp_new = PyType_GenericNew;
722 if (PyType_Ready(&CTracerType) < 0) {
723 return;
724 }
725
726 Py_INCREF(&CTracerType);
727 PyModule_AddObject(mod, "CTracer", (PyObject *)&CTracerType);
728 }
729
730 #endif /* Py3k */
OLDNEW
« no previous file with comments | « third_party/pycoverage/coverage/templite.py ('k') | third_party/pycoverage/coverage/version.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698