diff options
-rw-r--r-- | CHANGES.txt | 7 | ||||
-rw-r--r-- | coverage/tracer.c | 7 | ||||
-rw-r--r-- | test/farm/run/run_timid.py | 5 | ||||
-rw-r--r-- | test/farm/run/src/showtrace.py | 9 | ||||
-rw-r--r-- | test/test_oddball.py | 17 |
5 files changed, 37 insertions, 8 deletions
diff --git a/CHANGES.txt b/CHANGES.txt index 45dc1dc5..3c84dafc 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -34,6 +34,10 @@ Version 3.5 coverage.py will issue a warning, at least alerting you to the problem. Closes `issue 93`_. Thanks to Marius Gedminas for the idea. +- The C-based trace function now behaves properly when saved and restored + with ``sys.gettrace()`` and ``sys.settrace()``. This fixes `issue 125`_ + and `issue 123`_. Thanks, Devin Jeanpierre. + - Source files are now opened with Python 3.2's ``tokenize.open()`` where possible, to get the best handling of Python source files with encodings. Closes `issue 107`, thanks, Brett Cannon. @@ -58,7 +62,8 @@ Version 3.5 .. _issue 107: https://bitbucket.org/ned/coveragepy/issue/107/codeparser-not-opening-source-files-with .. _issue 115: https://bitbucket.org/ned/coveragepy/issue/115/fail-gracefully-when-reporting-on-file .. _issue 121: https://bitbucket.org/ned/coveragepy/issue/121/filename-patterns-are-applied-stupidly - +.. _issue 123: https://bitbucket.org/ned/coveragepy/issue/123/pyeval_settrace-used-in-way-that-breaks +.. _issue 125: https://bitbucket.org/ned/coveragepy/issue/125/coverage-removes-decoratortoolss-tracing Version 3.4 --- 19 September 2010 --------------------------------- diff --git a/coverage/tracer.c b/coverage/tracer.c index 2faabb62..1017c9d4 100644 --- a/coverage/tracer.c +++ b/coverage/tracer.c @@ -365,6 +365,9 @@ Tracer_trace(Tracer *self, PyFrameObject *frame, int what, PyObject *arg_unused) } } self->cur_file_data = file_data; + /* Make the frame right in case settrace(gettrace()) happens. */ + Py_INCREF(self); + frame->f_trace = (PyObject*)self; SHOWLOG(self->depth, frame->f_lineno, filename, "traced"); } else { @@ -497,12 +500,12 @@ done: } /* - * Python has two ways to set the trace function: sys.settrace(fn), which + * Python has two ways to set the trace function: sys.settrace(fn), which * takes a Python callable, and PyEval_SetTrace(func, obj), which takes * a C function and a Python object. The way these work together is that * sys.settrace(pyfn) calls PyEval_SetTrace(builtin_func, pyfn), using the * Python callable as the object in PyEval_SetTrace. So sys.gettrace() - * simply returns the Python object used as the second argument to + * simply returns the Python object used as the second argument to * PyEval_SetTrace. So sys.gettrace() will return our self parameter, which * means it must be callable to be used in sys.settrace(). * diff --git a/test/farm/run/run_timid.py b/test/farm/run/run_timid.py index 3810e6db..19651a1c 100644 --- a/test/farm/run/run_timid.py +++ b/test/farm/run/run_timid.py @@ -20,9 +20,8 @@ contains("out/showtraceout.txt", "timid PyTracer") if os.environ.get('COVERAGE_TEST_TRACER', 'c') == 'c': # If the C trace function is being tested, then regular running should have - # the C function (shown as None in f_trace since it isn't a Python - # function). - contains("out/showtraceout.txt", "regular None") + # the C function, which registers itself as f_trace. + contains("out/showtraceout.txt", "regular Tracer") else: # If the Python trace function is being tested, then regular running will # also show the Python function. diff --git a/test/farm/run/src/showtrace.py b/test/farm/run/src/showtrace.py index c3b4356c..e97412e0 100644 --- a/test/farm/run/src/showtrace.py +++ b/test/farm/run/src/showtrace.py @@ -4,7 +4,7 @@ import sys # Show what the trace function is. If a C-based function is used, then f_trace -# is None. +# may be None. trace_fn = sys._getframe(0).f_trace if trace_fn is None: trace_name = "None" @@ -13,6 +13,11 @@ else: try: trace_name = trace_fn.im_class.__name__ except AttributeError: - trace_name = trace_fn.__self__.__class__.__name__ + try: + trace_name = trace_fn.__self__.__class__.__name__ + except AttributeError: + # A C-based function could also manifest as an f_trace value + # which doesn't have im_class or __self__. + trace_name = trace_fn.__class__.__name__ print("%s %s" % (sys.argv[1], trace_name)) diff --git a/test/test_oddball.py b/test/test_oddball.py index 9b65a986..859648fa 100644 --- a/test/test_oddball.py +++ b/test/test_oddball.py @@ -365,3 +365,20 @@ if hasattr(sys, 'gettrace'): a = bar(8) ''', [1,2,3,4,5,6,7,8], "") + + def test_multi_layers(self): + self.check_coverage('''\ + import sys + def level1(): + a = 3 + level2() + b = 5 + def level2(): + c = 7 + sys.settrace(sys.gettrace()) + d = 9 + e = 10 + level1() + f = 12 + ''', + [1,2,3,4,5,6,7,8,9,10,11,12], "") |