[pypy-commit] pypy py3tests: Port test_pyframe.py to new-style apptest_pyframe.py
rlamy
pypy.commits at gmail.com
Fri Mar 23 09:01:11 EDT 2018
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: py3tests
Changeset: r94117:9f1ee75179ca
Date: 2018-03-23 12:44 +0100
http://bitbucket.org/pypy/pypy/changeset/9f1ee75179ca/
Log: Port test_pyframe.py to new-style apptest_pyframe.py
diff --git a/pypy/interpreter/test/apptest_coroutine.py b/pypy/interpreter/test/apptest_coroutine.py
--- a/pypy/interpreter/test/apptest_coroutine.py
+++ b/pypy/interpreter/test/apptest_coroutine.py
@@ -162,7 +162,7 @@
def test_runtime_warning():
- import gc, warnings
+ import gc, warnings # XXX: importing warnings is expensive untranslated
async def foobaz():
pass
with warnings.catch_warnings(record=True) as l:
diff --git a/pypy/interpreter/test/apptest_pyframe.py b/pypy/interpreter/test/apptest_pyframe.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/test/apptest_pyframe.py
@@ -0,0 +1,767 @@
+import pytest
+
+ at pytest.fixture
+def tempfile(tmpdir):
+ return str(tmpdir / 'tempfile1')
+
+def test_f_locals():
+ import sys
+ f = sys._getframe()
+ assert f.f_locals is locals()
+
+def test_f_globals():
+ import sys
+ f = sys._getframe()
+ assert f.f_globals is globals()
+ raises(AttributeError, "f.f_globals = globals()")
+
+def test_f_builtins():
+ import sys, builtins
+ f = sys._getframe()
+ assert f.f_builtins is builtins.__dict__
+
+def test_f_code():
+ def g():
+ import sys
+ f = sys._getframe()
+ return f.f_code
+ assert g() is g.__code__
+
+def test_f_trace_del():
+ import sys
+ f = sys._getframe()
+ del f.f_trace
+ assert f.f_trace is None
+
+def test_f_lineno():
+ def g():
+ import sys
+ f = sys._getframe()
+ x = f.f_lineno
+ y = f.f_lineno
+ z = f.f_lineno
+ return [x, y, z]
+ origin = g.__code__.co_firstlineno
+ assert g() == [origin+3, origin+4, origin+5]
+
+def test_f_lineno_set(tempfile):
+ 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
+
+ # obscure: call open beforehand, py3k's open invokes some app
+ # level code that confuses our tracing (likely due to the
+ # testing env, otherwise it's not a problem)
+ f = open(tempfile, 'w')
+ def function(f=f):
+ xyz
+ with f as f:
+ pass
+ return 3
+
+ import sys
+ sys.settrace(tracer)
+ function()
+ sys.settrace(None)
+ # assert did not crash
+
+def test_f_lineno_set_2(tempfile):
+ counter = [0]
+ errors = []
+
+ def tracer(f, event, *args):
+ if event == 'line':
+ counter[0] += 1
+ if counter[0] == 2:
+ try:
+ f.f_lineno += 2
+ except ValueError as e:
+ errors.append(e)
+ return tracer
+
+ # obscure: call open beforehand, py3k's open invokes some app
+ # level code that confuses our tracing (likely due to the
+ # testing env, otherwise it's not a problem)
+ f = open(tempfile, 'w')
+ def function():
+ try:
+ raise ValueError
+ except ValueError:
+ x = 42
+ return x
+
+ import sys
+ sys.settrace(tracer)
+ x = function()
+ sys.settrace(None)
+ assert x == 42
+ assert len(errors) == 1
+ assert str(errors[0]).startswith(
+ "can't jump into or out of an 'expect' or 'finally' block")
+
+def test_f_lineno_set_3():
+ def jump_in_nested_finally(output):
+ try:
+ output.append(2)
+ finally:
+ output.append(4)
+ try:
+ output.append(6)
+ finally:
+ output.append(8)
+ output.append(9)
+ output = []
+
+ def tracer(f, event, *args):
+ if event == 'line' and len(output) == 1:
+ f.f_lineno += 5
+ return tracer
+
+ import sys
+ sys.settrace(tracer)
+ jump_in_nested_finally(output)
+ sys.settrace(None)
+ assert output == [2, 9]
+
+def test_f_lineno_set_firstline():
+ seen = []
+ def tracer(f, event, *args):
+ seen.append((event, f.f_lineno))
+ if len(seen) == 5:
+ f.f_lineno = 1 # bug shown only when setting lineno to 1
+ return tracer
+
+ def g():
+ import sys
+ source = "x=1\ny=x+1\nz=y+1\nt=z+1\ns=t+1\n"
+ # compile first to ensure that no spurious events appear in the trace
+ code = compile(source, '<string>', 'exec')
+ sys.settrace(tracer)
+ exec(code, {})
+ sys.settrace(None)
+
+ g()
+ assert seen == [('call', 1),
+ ('line', 1),
+ ('line', 2),
+ ('line', 3),
+ ('line', 4),
+ ('line', 2),
+ ('line', 3),
+ ('line', 4),
+ ('line', 5),
+ ('return', 5)]
+
+def test_f_back():
+ import sys
+ def f():
+ assert sys._getframe().f_code.co_name == g()
+ def g():
+ return sys._getframe().f_back.f_code.co_name
+ f()
+
+def test_f_back_virtualref():
+ import sys
+ def f():
+ return g()
+ def g():
+ return sys._getframe()
+ frame = f()
+ assert frame.f_back.f_code.co_name == 'f'
+
+def test_virtualref_through_traceback():
+ import sys
+ def g():
+ try:
+ raise ValueError
+ except:
+ _, _, tb = sys.exc_info()
+ return tb
+ def f():
+ return g()
+ #
+ tb = f()
+ assert tb.tb_frame.f_code.co_name == 'g'
+ assert tb.tb_frame.f_back.f_code.co_name == 'f'
+
+def test_trace_basic():
+ import sys
+ l = []
+ class Tracer:
+ def __init__(self, i):
+ self.i = i
+ def trace(self, frame, event, arg):
+ l.append((self.i, frame.f_code.co_name, event, arg))
+ if frame.f_code.co_name == 'g2':
+ return None # don't trace g2
+ return Tracer(self.i+1).trace
+ def g3(n):
+ n -= 5
+ return n
+ def g2(n):
+ n += g3(2)
+ n += g3(7)
+ return n
+ def g(n):
+ n += g2(3)
+ return n
+ def f(n):
+ n = g(n)
+ return n * 7
+ sys.settrace(Tracer(0).trace)
+ x = f(4)
+ sys.settrace(None)
+ assert x == 42
+ print(l)
+ assert l == [(0, 'f', 'call', None),
+ (1, 'f', 'line', None),
+ (0, 'g', 'call', None),
+ (1, 'g', 'line', None),
+ (0, 'g2', 'call', None),
+ (0, 'g3', 'call', None),
+ (1, 'g3', 'line', None),
+ (2, 'g3', 'line', None),
+ (3, 'g3', 'return', -3),
+ (0, 'g3', 'call', None),
+ (1, 'g3', 'line', None),
+ (2, 'g3', 'line', None),
+ (3, 'g3', 'return', 2),
+ (2, 'g', 'line', None),
+ (3, 'g', 'return', 6),
+ (2, 'f', 'line', None),
+ (3, 'f', 'return', 42)]
+
+def test_trace_exc():
+ import sys
+ l = []
+ def ltrace(a,b,c):
+ if b == 'exception':
+ l.append(c)
+ return ltrace
+ def trace(a,b,c): return ltrace
+ def f():
+ try:
+ raise Exception
+ except:
+ pass
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ assert len(l) == 1
+ assert isinstance(l[0][1], Exception)
+
+def test_trace_ignore_hidden():
+ import sys
+ import _testing
+
+ l = []
+ def trace(a,b,c):
+ l.append((a,b,c))
+
+ def f():
+ h = _testing.Hidden()
+ r = h.meth()
+ return r
+
+ sys.settrace(trace)
+ res = f()
+ sys.settrace(None)
+ assert len(l) == 1
+ assert l[0][1] == 'call'
+ assert res == 'hidden' # sanity
+
+def test_trace_hidden_applevel_builtins():
+ import sys
+
+ l = []
+ def trace(a,b,c):
+ l.append((a,b,c))
+ return trace
+
+ def f():
+ sum([])
+ sum([])
+ sum([])
+ return "that's the return value"
+
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ # should get 1 "call", 3 "line" and 1 "return" events, and no call
+ # or return for the internal app-level implementation of sum
+ assert len(l) == 6
+ assert [what for (frame, what, arg) in l] == [
+ 'call', 'line', 'line', 'line', 'line', 'return']
+ assert l[-1][2] == "that's the return value"
+
+def test_trace_return_exc():
+ import sys
+ l = []
+ def trace(a,b,c):
+ if b in ('exception', 'return'):
+ l.append((b, c))
+ return trace
+
+ def g():
+ raise Exception
+ def f():
+ try:
+ g()
+ except:
+ pass
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ assert len(l) == 4
+ assert l[0][0] == 'exception'
+ assert isinstance(l[0][1][1], Exception)
+ assert l[1] == ('return', None)
+ assert l[2][0] == 'exception'
+ assert isinstance(l[2][1][1], Exception)
+ assert l[3] == ('return', None)
+
+def test_trace_raises_on_return():
+ import sys
+ def trace(frame, event, arg):
+ if event == 'return':
+ raise ValueError
+ else:
+ return trace
+
+ def f(): return 1
+
+ for i in range(sys.getrecursionlimit() + 1):
+ sys.settrace(trace)
+ try:
+ f()
+ except ValueError:
+ pass
+
+def test_trace_try_finally():
+ import sys
+ l = []
+ def trace(frame, event, arg):
+ if event == 'exception':
+ l.append(arg)
+ return trace
+
+ def g():
+ try:
+ raise Exception
+ finally:
+ pass
+
+ def f():
+ try:
+ g()
+ except:
+ pass
+
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ assert len(l) == 2
+ assert issubclass(l[0][0], Exception)
+ assert issubclass(l[1][0], Exception)
+
+def test_trace_generator_finalisation():
+ import sys
+ l = []
+ got_exc = []
+ def trace(frame, event, arg):
+ l.append((frame.f_lineno, event))
+ if event == 'exception':
+ got_exc.append(arg)
+ return trace
+
+ d = {}
+ exec("""if 1:
+ def g():
+ try:
+ yield True
+ finally:
+ pass
+
+ def f():
+ try:
+ gen = g()
+ next(gen)
+ gen.close()
+ except:
+ pass
+ """, d)
+ f = d['f']
+
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ assert len(got_exc) == 1
+ assert issubclass(got_exc[0][0], GeneratorExit)
+ assert l == [(8, 'call'),
+ (9, 'line'),
+ (10, 'line'),
+ (11, 'line'),
+ (2, 'call'),
+ (3, 'line'),
+ (4, 'line'),
+ (4, 'return'),
+ (12, 'line'),
+ (4, 'call'),
+ (4, 'exception'),
+ (6, 'line'),
+ (6, 'return'),
+ (12, 'return')]
+
+def test_dont_trace_on_reraise():
+ import sys
+ l = []
+ def ltrace(a,b,c):
+ if b == 'exception':
+ l.append(c)
+ return ltrace
+ def trace(a,b,c): return ltrace
+ def f():
+ try:
+ 1/0
+ except:
+ try:
+ raise
+ except:
+ pass
+ sys.settrace(trace)
+ f()
+ sys.settrace(None)
+ assert len(l) == 1
+ assert issubclass(l[0][0], Exception)
+
+def test_trace_changes_locals():
+ import sys
+ def trace(frame, what, arg):
+ frame.f_locals['x'] = 42
+ return trace
+ def f(x):
+ return x
+ sys.settrace(trace)
+ res = f(1)
+ sys.settrace(None)
+ assert res == 42
+
+def test_trace_onliner_if():
+ import sys
+ l = []
+ def trace(frame, event, arg):
+ l.append((frame.f_lineno, event))
+ return trace
+ def onliners():
+ if True: False
+ else: True
+ return 0
+ sys.settrace(trace)
+ onliners()
+ sys.settrace(None)
+ firstlineno = onliners.__code__.co_firstlineno
+ assert l == [(firstlineno + 0, 'call'),
+ (firstlineno + 1, 'line'),
+ (firstlineno + 3, 'line'),
+ (firstlineno + 3, 'return')]
+
+def test_set_unset_f_trace():
+ import sys
+ seen = []
+ def trace1(frame, what, arg):
+ seen.append((1, frame, frame.f_lineno, what, arg))
+ return trace1
+ def trace2(frame, what, arg):
+ seen.append((2, frame, frame.f_lineno, what, arg))
+ return trace2
+ def set_the_trace(f):
+ f.f_trace = trace1
+ sys.settrace(trace2)
+ len(seen) # take one line: should not be traced
+ f = sys._getframe()
+ set_the_trace(f)
+ len(seen) # take one line: should not be traced
+ len(seen) # take one line: should not be traced
+ sys.settrace(None) # and this line should be the last line traced
+ len(seen) # take one line
+ del f.f_trace
+ len(seen) # take one line
+ firstline = set_the_trace.__code__.co_firstlineno
+ assert seen == [(1, f, firstline + 6, 'line', None),
+ (1, f, firstline + 7, 'line', None),
+ (1, f, firstline + 8, 'line', None)]
+
+def test_locals2fast_freevar_bug():
+ import sys
+ def f(n):
+ class A(object):
+ def g(self):
+ return n
+ n = 42
+ return A()
+ res = f(10).g()
+ assert res == 10
+ #
+ def trace(*args):
+ return trace
+ sys.settrace(trace)
+ res = f(10).g()
+ sys.settrace(None)
+ assert res == 10
+
+def test_preserve_exc_state_in_generators():
+ import sys
+ def yield_raise():
+ try:
+ raise KeyError("caught")
+ except KeyError:
+ yield sys.exc_info()[0]
+ yield sys.exc_info()[0]
+
+ it = yield_raise()
+ assert next(it) is KeyError
+ assert next(it) is KeyError
+
+def test_frame_clear():
+ import sys, gc, weakref
+ #
+ raises(RuntimeError, sys._getframe().clear)
+ def g():
+ yield 5
+ raises(RuntimeError, sys._getframe().clear)
+ yield 6
+ assert list(g()) == [5, 6]
+ #
+ class A:
+ pass
+ a1 = A(); a1ref = weakref.ref(a1)
+ a2 = A(); a2ref = weakref.ref(a2)
+ seen = []
+ def f():
+ local_a1 = a1
+ for loc in [5, 6, a2]:
+ try:
+ yield sys._getframe()
+ finally:
+ seen.append(42)
+ seen.append(43)
+ gen = f()
+ frame = next(gen)
+ a1 = a2 = None
+ gc.collect(); gc.collect()
+ assert a1ref() is not None
+ assert a2ref() is not None
+ assert seen == []
+ frame.clear()
+ assert seen == [42]
+ gc.collect(); gc.collect()
+ assert a1ref() is None, "locals not cleared"
+ assert a2ref() is None, "stack not cleared"
+ #
+ raises(StopIteration, next, gen)
+
+def test_frame_clear_really():
+ import sys
+ def f(x):
+ return sys._getframe()
+ frame = f(42)
+ assert frame.f_locals['x'] == 42
+ frame.clear()
+ assert frame.f_locals == {}
+
+def test_throw_trace_bug():
+ import sys
+ def f():
+ yield 5
+ gen = f()
+ assert next(gen) == 5
+ seen = []
+ def trace_func(frame, event, *args):
+ seen.append(event)
+ return trace_func
+ sys.settrace(trace_func)
+ try:
+ gen.throw(ValueError)
+ except ValueError:
+ pass
+ sys.settrace(None)
+ assert seen == ['call', 'exception', 'return']
+
+def test_generator_trace_stopiteration():
+ import sys
+ def f():
+ yield 5
+ gen = f()
+ assert next(gen) == 5
+ seen = []
+ frames = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ frames.append(frame)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g()
+ sys.settrace(None)
+ print('seen:', seen)
+ # on Python 3 we get an extra 'exception' when 'for' catches
+ # StopIteration (but not always! mess)
+ assert seen == ['call', 'line', 'call', 'return', 'exception', 'return']
+ assert frames[-2].f_code.co_name == 'g'
+
+def test_nongenerator_trace_stopiteration():
+ import sys
+ gen = iter([5])
+ assert next(gen) == 5
+ seen = []
+ frames = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ frames.append(frame)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g()
+ sys.settrace(None)
+ print('seen:', seen)
+ # hack: don't report the StopIteration for some "simple"
+ # iterators.
+ assert seen == ['call', 'line', 'return']
+ assert frames[-2].f_code.co_name == 'g'
+
+def test_yieldfrom_trace_stopiteration():
+ import sys
+ def f2():
+ yield 5
+ def f():
+ yield from f2()
+ gen = f()
+ assert next(gen) == 5
+ seen = []
+ frames = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ frames.append(frame)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g() # invokes next_yield_from() from resume_execute_frame()
+ sys.settrace(None)
+ print('seen:', seen)
+ assert seen == ['call', 'line', 'call', 'call', 'return',
+ 'exception', 'return', 'exception', 'return']
+ assert frames[-4].f_code.co_name == 'f'
+ assert frames[-2].f_code.co_name == 'g'
+
+def test_yieldfrom_trace_stopiteration_2():
+ import sys
+ def f2():
+ if False:
+ yield 5
+ def f():
+ yield from f2()
+ gen = f()
+ seen = []
+ frames = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ frames.append(frame)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g() # invokes next_yield_from() from YIELD_FROM()
+ sys.settrace(None)
+ print('seen:', seen)
+ assert seen == ['call', 'line', 'call', 'line', 'call', 'line',
+ 'return', 'exception', 'return', 'exception', 'return']
+ assert frames[-4].f_code.co_name == 'f'
+ assert frames[-2].f_code.co_name == 'g'
+
+def test_yieldfrom_trace_stopiteration_3():
+ import sys
+ def f():
+ yield from []
+ gen = f()
+ seen = []
+ frames = []
+ def trace_func(frame, event, *args):
+ print('TRACE:', frame, event, args)
+ seen.append(event)
+ frames.append(frame)
+ return trace_func
+ def g():
+ for x in gen:
+ never_entered
+ sys.settrace(trace_func)
+ g() # invokes next_yield_from() from YIELD_FROM()
+ sys.settrace(None)
+ print('seen:', seen)
+ assert seen == ['call', 'line', 'call', 'line',
+ 'return', 'exception', 'return']
+ assert frames[-4].f_code.co_name == 'f'
+
+def test_local_trace_function_returning_None_ignored():
+ # 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"]
+
+def test_clear_locals():
+ def make_frames():
+ def outer():
+ x = 5
+ y = 6
+ def inner():
+ z = x + 2
+ 1/0
+ t = 9
+ return inner()
+ try:
+ outer()
+ except ZeroDivisionError as e:
+ tb = e.__traceback__
+ frames = []
+ while tb:
+ frames.append(tb.tb_frame)
+ tb = tb.tb_next
+ return frames
+
+ f, outer, inner = make_frames()
+ outer.clear()
+ inner.clear()
+ assert not outer.f_locals
+ assert not inner.f_locals
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
@@ -9,8 +9,6 @@
def setup_class(cls):
space = cls.space
- cls.w_udir = cls.space.wrap(str(udir.udir))
- cls.w_tempfile1 = cls.space.wrap(str(udir.udir.join('tempfile1')))
if not option.runappdirect:
w_call_further = cls.space.appexec([], """():
def call_further(f):
@@ -25,175 +23,6 @@
# test for the presence of the attributes, not functionality
- def test_f_locals(self):
- import sys
- f = sys._getframe()
- assert f.f_locals is locals()
-
- def test_f_globals(self):
- import sys
- f = sys._getframe()
- assert f.f_globals is globals()
- raises(AttributeError, "f.f_globals = globals()")
-
- def test_f_builtins(self):
- import sys, builtins
- f = sys._getframe()
- assert f.f_builtins is builtins.__dict__
-
- def test_f_code(self):
- def g():
- import sys
- f = sys._getframe()
- return f.f_code
- assert g() is g.__code__
-
- def test_f_trace_del(self):
- import sys
- f = sys._getframe()
- del f.f_trace
- assert f.f_trace is None
-
- def test_f_lineno(self):
- def g():
- import sys
- f = sys._getframe()
- x = f.f_lineno
- y = f.f_lineno
- z = f.f_lineno
- return [x, y, z]
- origin = g.__code__.co_firstlineno
- assert g() == [origin+3, origin+4, origin+5]
-
- 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
-
- # obscure: call open beforehand, py3k's open invokes some app
- # level code that confuses our tracing (likely due to the
- # testing env, otherwise it's not a problem)
- f = open(self.tempfile1, 'w')
- def function(f=f):
- xyz
- with f as f:
- pass
- return 3
-
- import sys
- sys.settrace(tracer)
- function()
- sys.settrace(None)
- # assert did not crash
-
- def test_f_lineno_set_2(self):
- counter = [0]
- errors = []
-
- def tracer(f, event, *args):
- if event == 'line':
- counter[0] += 1
- if counter[0] == 2:
- try:
- f.f_lineno += 2
- except ValueError as e:
- errors.append(e)
- return tracer
-
- # obscure: call open beforehand, py3k's open invokes some app
- # level code that confuses our tracing (likely due to the
- # testing env, otherwise it's not a problem)
- f = open(self.tempfile1, 'w')
- def function():
- try:
- raise ValueError
- except ValueError:
- x = 42
- return x
-
- import sys
- sys.settrace(tracer)
- x = function()
- sys.settrace(None)
- assert x == 42
- assert len(errors) == 1
- assert str(errors[0]).startswith(
- "can't jump into or out of an 'expect' or 'finally' block")
-
- def test_f_lineno_set_3(self):
- def jump_in_nested_finally(output):
- try:
- output.append(2)
- finally:
- output.append(4)
- try:
- output.append(6)
- finally:
- output.append(8)
- output.append(9)
- output = []
-
- def tracer(f, event, *args):
- if event == 'line' and len(output) == 1:
- f.f_lineno += 5
- return tracer
-
- import sys
- sys.settrace(tracer)
- jump_in_nested_finally(output)
- sys.settrace(None)
- assert output == [2, 9]
-
- def test_f_lineno_set_firstline(self):
- r"""
- seen = []
- def tracer(f, event, *args):
- seen.append((event, f.f_lineno))
- if len(seen) == 5:
- f.f_lineno = 1 # bug shown only when setting lineno to 1
- return tracer
-
- def g():
- import sys
- sys.settrace(tracer)
- exec("x=1\ny=x+1\nz=y+1\nt=z+1\ns=t+1\n", {})
- sys.settrace(None)
-
- g()
- assert seen == [('call', 1),
- ('line', 1),
- ('line', 2),
- ('line', 3),
- ('line', 4),
- ('line', 2),
- ('line', 3),
- ('line', 4),
- ('line', 5),
- ('return', 5)]
- """
-
- def test_f_back(self):
- import sys
- def f():
- assert sys._getframe().f_code.co_name == g()
- def g():
- return sys._getframe().f_back.f_code.co_name
- f()
-
- def test_f_back_virtualref(self):
- import sys
- def f():
- return g()
- def g():
- return sys._getframe()
- frame = f()
- assert frame.f_back.f_code.co_name == 'f'
-
def test_f_back_hidden(self):
if not hasattr(self, 'call_further'):
skip("not for runappdirect testing")
@@ -210,304 +39,6 @@
assert f1bis is f1
assert f0.f_back is f1
- def test_virtualref_through_traceback(self):
- import sys
- def g():
- try:
- raise ValueError
- except:
- _, _, tb = sys.exc_info()
- return tb
- def f():
- return g()
- #
- tb = f()
- assert tb.tb_frame.f_code.co_name == 'g'
- assert tb.tb_frame.f_back.f_code.co_name == 'f'
-
- def test_trace_basic(self):
- import sys
- l = []
- class Tracer:
- def __init__(self, i):
- self.i = i
- def trace(self, frame, event, arg):
- l.append((self.i, frame.f_code.co_name, event, arg))
- if frame.f_code.co_name == 'g2':
- return None # don't trace g2
- return Tracer(self.i+1).trace
- def g3(n):
- n -= 5
- return n
- def g2(n):
- n += g3(2)
- n += g3(7)
- return n
- def g(n):
- n += g2(3)
- return n
- def f(n):
- n = g(n)
- return n * 7
- sys.settrace(Tracer(0).trace)
- x = f(4)
- sys.settrace(None)
- assert x == 42
- print(l)
- assert l == [(0, 'f', 'call', None),
- (1, 'f', 'line', None),
- (0, 'g', 'call', None),
- (1, 'g', 'line', None),
- (0, 'g2', 'call', None),
- (0, 'g3', 'call', None),
- (1, 'g3', 'line', None),
- (2, 'g3', 'line', None),
- (3, 'g3', 'return', -3),
- (0, 'g3', 'call', None),
- (1, 'g3', 'line', None),
- (2, 'g3', 'line', None),
- (3, 'g3', 'return', 2),
- (2, 'g', 'line', None),
- (3, 'g', 'return', 6),
- (2, 'f', 'line', None),
- (3, 'f', 'return', 42)]
-
- def test_trace_exc(self):
- import sys
- l = []
- def ltrace(a,b,c):
- if b == 'exception':
- l.append(c)
- return ltrace
- def trace(a,b,c): return ltrace
- def f():
- try:
- raise Exception
- except:
- pass
- sys.settrace(trace)
- f()
- sys.settrace(None)
- assert len(l) == 1
- assert isinstance(l[0][1], Exception)
-
- def test_trace_ignore_hidden(self):
- import sys
- import _testing
-
- l = []
- def trace(a,b,c):
- l.append((a,b,c))
-
- def f():
- h = _testing.Hidden()
- r = h.meth()
- return r
-
- sys.settrace(trace)
- res = f()
- sys.settrace(None)
- assert len(l) == 1
- assert l[0][1] == 'call'
- assert res == 'hidden' # sanity
-
- def test_trace_hidden_applevel_builtins(self):
- import sys
-
- l = []
- def trace(a,b,c):
- l.append((a,b,c))
- return trace
-
- def f():
- sum([])
- sum([])
- sum([])
- return "that's the return value"
-
- sys.settrace(trace)
- f()
- sys.settrace(None)
- # should get 1 "call", 3 "line" and 1 "return" events, and no call
- # or return for the internal app-level implementation of sum
- assert len(l) == 6
- assert [what for (frame, what, arg) in l] == [
- 'call', 'line', 'line', 'line', 'line', 'return']
- assert l[-1][2] == "that's the return value"
-
- def test_trace_return_exc(self):
- import sys
- l = []
- def trace(a,b,c):
- if b in ('exception', 'return'):
- l.append((b, c))
- return trace
-
- def g():
- raise Exception
- def f():
- try:
- g()
- except:
- pass
- sys.settrace(trace)
- f()
- sys.settrace(None)
- assert len(l) == 4
- assert l[0][0] == 'exception'
- assert isinstance(l[0][1][1], Exception)
- assert l[1] == ('return', None)
- assert l[2][0] == 'exception'
- assert isinstance(l[2][1][1], Exception)
- assert l[3] == ('return', None)
-
- def test_trace_raises_on_return(self):
- import sys
- def trace(frame, event, arg):
- if event == 'return':
- raise ValueError
- else:
- return trace
-
- def f(): return 1
-
- for i in range(sys.getrecursionlimit() + 1):
- sys.settrace(trace)
- try:
- f()
- except ValueError:
- pass
-
- def test_trace_try_finally(self):
- import sys
- l = []
- def trace(frame, event, arg):
- if event == 'exception':
- l.append(arg)
- return trace
-
- def g():
- try:
- raise Exception
- finally:
- pass
-
- def f():
- try:
- g()
- except:
- pass
-
- sys.settrace(trace)
- f()
- sys.settrace(None)
- assert len(l) == 2
- assert issubclass(l[0][0], Exception)
- assert issubclass(l[1][0], Exception)
-
- def test_trace_generator_finalisation(self):
- '''
- import sys
- l = []
- got_exc = []
- def trace(frame, event, arg):
- l.append((frame.f_lineno, event))
- if event == 'exception':
- got_exc.append(arg)
- return trace
-
- d = {}
- exec("""if 1:
- def g():
- try:
- yield True
- finally:
- pass
-
- def f():
- try:
- gen = g()
- next(gen)
- gen.close()
- except:
- pass
- """, d)
- f = d['f']
-
- sys.settrace(trace)
- f()
- sys.settrace(None)
- assert len(got_exc) == 1
- assert issubclass(got_exc[0][0], GeneratorExit)
- assert l == [(8, 'call'),
- (9, 'line'),
- (10, 'line'),
- (11, 'line'),
- (2, 'call'),
- (3, 'line'),
- (4, 'line'),
- (4, 'return'),
- (12, 'line'),
- (4, 'call'),
- (4, 'exception'),
- (6, 'line'),
- (6, 'return'),
- (12, 'return')]
- '''
-
- def test_dont_trace_on_reraise(self):
- import sys
- l = []
- def ltrace(a,b,c):
- if b == 'exception':
- l.append(c)
- return ltrace
- def trace(a,b,c): return ltrace
- def f():
- try:
- 1/0
- except:
- try:
- raise
- except:
- pass
- sys.settrace(trace)
- f()
- sys.settrace(None)
- assert len(l) == 1
- assert issubclass(l[0][0], Exception)
-
- def test_trace_changes_locals(self):
- import sys
- def trace(frame, what, arg):
- frame.f_locals['x'] = 42
- return trace
- def f(x):
- return x
- sys.settrace(trace)
- res = f(1)
- sys.settrace(None)
- assert res == 42
-
- def test_trace_onliner_if(self):
- import sys
- l = []
- def trace(frame, event, arg):
- l.append((frame.f_lineno, event))
- return trace
- def onliners():
- if True: False
- else: True
- return 0
- sys.settrace(trace)
- onliners()
- sys.settrace(None)
- firstlineno = onliners.__code__.co_firstlineno
- assert l == [(firstlineno + 0, 'call'),
- (firstlineno + 1, 'line'),
- (firstlineno + 3, 'line'),
- (firstlineno + 3, 'return')]
-
def test_fast2locals_called_lazily(self):
import sys
class FrameHolder:
@@ -526,302 +57,3 @@
assert res == 2
if hasattr(self, "check_no_w_locals"): # not appdirect
assert self.check_no_w_locals(fh.frame)
-
- def test_set_unset_f_trace(self):
- import sys
- seen = []
- def trace1(frame, what, arg):
- seen.append((1, frame, frame.f_lineno, what, arg))
- return trace1
- def trace2(frame, what, arg):
- seen.append((2, frame, frame.f_lineno, what, arg))
- return trace2
- def set_the_trace(f):
- f.f_trace = trace1
- sys.settrace(trace2)
- len(seen) # take one line: should not be traced
- f = sys._getframe()
- set_the_trace(f)
- len(seen) # take one line: should not be traced
- len(seen) # take one line: should not be traced
- sys.settrace(None) # and this line should be the last line traced
- len(seen) # take one line
- del f.f_trace
- len(seen) # take one line
- firstline = set_the_trace.__code__.co_firstlineno
- assert seen == [(1, f, firstline + 6, 'line', None),
- (1, f, firstline + 7, 'line', None),
- (1, f, firstline + 8, 'line', None)]
-
- def test_locals2fast_freevar_bug(self):
- import sys
- def f(n):
- class A(object):
- def g(self):
- return n
- n = 42
- return A()
- res = f(10).g()
- assert res == 10
- #
- def trace(*args):
- return trace
- sys.settrace(trace)
- res = f(10).g()
- sys.settrace(None)
- assert res == 10
-
- def test_preserve_exc_state_in_generators(self):
- import sys
- def yield_raise():
- try:
- raise KeyError("caught")
- except KeyError:
- yield sys.exc_info()[0]
- yield sys.exc_info()[0]
-
- it = yield_raise()
- assert next(it) is KeyError
- assert next(it) is KeyError
-
- def test_frame_clear(self):
- import sys, gc, weakref
- #
- raises(RuntimeError, sys._getframe().clear)
- def g():
- yield 5
- raises(RuntimeError, sys._getframe().clear)
- yield 6
- assert list(g()) == [5, 6]
- #
- class A:
- pass
- a1 = A(); a1ref = weakref.ref(a1)
- a2 = A(); a2ref = weakref.ref(a2)
- seen = []
- def f():
- local_a1 = a1
- for loc in [5, 6, a2]:
- try:
- yield sys._getframe()
- finally:
- seen.append(42)
- seen.append(43)
- gen = f()
- frame = next(gen)
- a1 = a2 = None
- gc.collect(); gc.collect()
- assert a1ref() is not None
- assert a2ref() is not None
- assert seen == []
- frame.clear()
- assert seen == [42]
- gc.collect(); gc.collect()
- assert a1ref() is None, "locals not cleared"
- assert a2ref() is None, "stack not cleared"
- #
- raises(StopIteration, next, gen)
-
- def test_frame_clear_really(self):
- import sys
- def f(x):
- return sys._getframe()
- frame = f(42)
- assert frame.f_locals['x'] == 42
- frame.clear()
- assert frame.f_locals == {}
-
- def test_throw_trace_bug(self):
- import sys
- def f():
- yield 5
- gen = f()
- assert next(gen) == 5
- seen = []
- def trace_func(frame, event, *args):
- seen.append(event)
- return trace_func
- sys.settrace(trace_func)
- try:
- gen.throw(ValueError)
- except ValueError:
- pass
- sys.settrace(None)
- assert seen == ['call', 'exception', 'return']
-
- def test_generator_trace_stopiteration(self):
- import sys
- def f():
- yield 5
- gen = f()
- assert next(gen) == 5
- seen = []
- frames = []
- def trace_func(frame, event, *args):
- print('TRACE:', frame, event, args)
- seen.append(event)
- frames.append(frame)
- return trace_func
- def g():
- for x in gen:
- never_entered
- sys.settrace(trace_func)
- g()
- sys.settrace(None)
- print('seen:', seen)
- # on Python 3 we get an extra 'exception' when 'for' catches
- # StopIteration (but not always! mess)
- assert seen == ['call', 'line', 'call', 'return', 'exception', 'return']
- assert frames[-2].f_code.co_name == 'g'
-
- def test_nongenerator_trace_stopiteration(self):
- import sys
- gen = iter([5])
- assert next(gen) == 5
- seen = []
- frames = []
- def trace_func(frame, event, *args):
- print('TRACE:', frame, event, args)
- seen.append(event)
- frames.append(frame)
- return trace_func
- def g():
- for x in gen:
- never_entered
- sys.settrace(trace_func)
- g()
- sys.settrace(None)
- print('seen:', seen)
- # hack: don't report the StopIteration for some "simple"
- # iterators.
- assert seen == ['call', 'line', 'return']
- assert frames[-2].f_code.co_name == 'g'
-
- def test_yieldfrom_trace_stopiteration(self): """
- import sys
- def f2():
- yield 5
- def f():
- yield from f2()
- gen = f()
- assert next(gen) == 5
- seen = []
- frames = []
- def trace_func(frame, event, *args):
- print('TRACE:', frame, event, args)
- seen.append(event)
- frames.append(frame)
- return trace_func
- def g():
- for x in gen:
- never_entered
- sys.settrace(trace_func)
- g() # invokes next_yield_from() from resume_execute_frame()
- sys.settrace(None)
- print('seen:', seen)
- assert seen == ['call', 'line', 'call', 'call', 'return',
- 'exception', 'return', 'exception', 'return']
- assert frames[-4].f_code.co_name == 'f'
- assert frames[-2].f_code.co_name == 'g'
- """
-
- def test_yieldfrom_trace_stopiteration_2(self): """
- import sys
- def f2():
- if False:
- yield 5
- def f():
- yield from f2()
- gen = f()
- seen = []
- frames = []
- def trace_func(frame, event, *args):
- print('TRACE:', frame, event, args)
- seen.append(event)
- frames.append(frame)
- return trace_func
- def g():
- for x in gen:
- never_entered
- sys.settrace(trace_func)
- g() # invokes next_yield_from() from YIELD_FROM()
- sys.settrace(None)
- print('seen:', seen)
- assert seen == ['call', 'line', 'call', 'line', 'call', 'line',
- 'return', 'exception', 'return', 'exception', 'return']
- assert frames[-4].f_code.co_name == 'f'
- assert frames[-2].f_code.co_name == 'g'
- """
-
- def test_yieldfrom_trace_stopiteration_3(self): """
- import sys
- def f():
- yield from []
- gen = f()
- seen = []
- frames = []
- def trace_func(frame, event, *args):
- print('TRACE:', frame, event, args)
- seen.append(event)
- frames.append(frame)
- return trace_func
- def g():
- for x in gen:
- never_entered
- sys.settrace(trace_func)
- g() # invokes next_yield_from() from YIELD_FROM()
- sys.settrace(None)
- print('seen:', seen)
- assert seen == ['call', 'line', 'call', 'line',
- 'return', 'exception', 'return']
- assert frames[-4].f_code.co_name == 'f'
- """
-
- 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"]
-
- def test_clear_locals(self):
- def make_frames():
- def outer():
- x = 5
- y = 6
- def inner():
- z = x + 2
- 1/0
- t = 9
- return inner()
- try:
- outer()
- except ZeroDivisionError as e:
- tb = e.__traceback__
- frames = []
- while tb:
- frames.append(tb.tb_frame)
- tb = tb.tb_next
- return frames
-
- f, outer, inner = make_frames()
- outer.clear()
- inner.clear()
- assert not outer.f_locals
- assert not inner.f_locals
More information about the pypy-commit
mailing list