Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 28 additions & 15 deletions Lib/test/test_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,18 +145,27 @@ class C:

class FrameAttrsTest(unittest.TestCase):

def make_frames(self):
def outer():
x = 5
y = 6
def inner():
z = x + 2
1/0
t = 9
return inner()
@staticmethod
def outer():
x = 5
y = 6
def inner():
z = x + 2
1/0
t = 9
return inner()

@staticmethod
def generator():
def foo():
yield
assert False
list(foo())

def make_frames(self, func):
try:
outer()
except ZeroDivisionError as e:
func()
except (ZeroDivisionError, AssertionError) as e:
tb = e.__traceback__
frames = []
while tb:
Expand All @@ -165,7 +174,7 @@ def inner():
return frames

def test_locals(self):
f, outer, inner = self.make_frames()
f, outer, inner = self.make_frames(self.outer)
outer_locals = outer.f_locals
self.assertIsInstance(outer_locals.pop('inner'), types.FunctionType)
self.assertEqual(outer_locals, {'x': 5, 'y': 6})
Expand All @@ -174,15 +183,15 @@ def test_locals(self):

def test_clear_locals(self):
# Test f_locals after clear() (issue #21897)
f, outer, inner = self.make_frames()
f, outer, inner = self.make_frames(self.outer)
outer.clear()
inner.clear()
self.assertEqual(outer.f_locals, {})
self.assertEqual(inner.f_locals, {})

def test_locals_clear_locals(self):
# Test f_locals before and after clear() (to exercise caching)
f, outer, inner = self.make_frames()
f, outer, inner = self.make_frames(self.outer)
outer.f_locals
inner.f_locals
outer.clear()
Expand All @@ -191,10 +200,14 @@ def test_locals_clear_locals(self):
self.assertEqual(inner.f_locals, {})

def test_f_lineno_del_segfault(self):
f, _, _ = self.make_frames()
f, _, _ = self.make_frames(self.outer)
with self.assertRaises(AttributeError):
del f.f_lineno

def test_generator_lineno(self):
f, _, generator = self.make_frames(self.generator)
self.assertEqual(generator.f_lineno, generator.f_code.co_firstlineno + 2)


class ReprTest(unittest.TestCase):
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Set ``lineno`` in generator instructions when generating bytecode.
7 changes: 6 additions & 1 deletion Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -7434,6 +7434,11 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
return -1;
}

int lineno = -1;
if (entryblock->b_iused > 0) {
lineno = entryblock->b_instr[0].i_lineno;
}

/* Set up cells for any variable that escapes, to be put in a closure. */
const int ncellvars = (int)PyDict_GET_SIZE(c->u->u_cellvars);
if (ncellvars) {
Expand Down Expand Up @@ -7485,7 +7490,7 @@ insert_prefix_instructions(struct compiler *c, basicblock *entryblock,
struct instr gen_start = {
.i_opcode = GEN_START,
.i_oparg = kind,
.i_lineno = -1,
.i_lineno = lineno,
.i_target = NULL,
};
if (insert_instruction(entryblock, 0, &gen_start) < 0) {
Expand Down
Loading