[pypy-commit] pypy default: sys.settrace(f) when we see a 'call' can return a different

arigo pypy.commits at gmail.com
Wed Jan 18 06:44:18 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r89654:f47609af5171
Date: 2017-01-18 12:43 +0100
http://bitbucket.org/pypy/pypy/changeset/f47609af5171/

Log:	sys.settrace(f) when we see a 'call' can return a different function
	g() or None. But such a function g() cannot return None: if it does
	then g() will continue to be called. See
	http://bugs.python.org/issue11992

diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -336,7 +336,9 @@
                 try:
                     w_result = space.call_function(w_callback, space.wrap(frame), space.wrap(event), w_arg)
                     if space.is_w(w_result, space.w_None):
-                        d.w_f_trace = None
+                        # bug-to-bug compatibility with CPython
+                        # http://bugs.python.org/issue11992
+                        pass   #d.w_f_trace = None
                     else:
                         d.w_f_trace = w_result
                 except:
diff --git a/pypy/interpreter/test/test_pyframe.py b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -67,8 +67,12 @@
 
     def test_f_lineno_set(self):
         def tracer(f, *args):
+            def y(f, *args):
+                return y
             def x(f, *args):
                 f.f_lineno += 1
+                return y  # "return None" should have the same effect, but see
+                          # test_local_trace_function_returning_None_ignored
             return x
 
         open    # force fetching of this name now
@@ -602,3 +606,26 @@
         # on Python 3 we get an extra 'exception' when 'for' catches
         # StopIteration
         assert seen == ['call', 'line', 'call', 'return', 'return']
+
+    def test_local_trace_function_returning_None_ignored(self):
+        # behave the same as CPython does, and in contradiction with
+        # the documentation.
+        def tracer(f, event, arg):
+            assert event == 'call'
+            return local_tracer
+
+        seen = []
+        def local_tracer(f, event, arg):
+            seen.append(event)
+            return None     # but 'local_tracer' will be called again
+
+        def function():
+            a = 1
+            a = 2
+            a = 3
+
+        import sys
+        sys.settrace(tracer)
+        function()
+        sys.settrace(None)
+        assert seen == ["line", "line", "line", "return"]


More information about the pypy-commit mailing list