Skip to content

Commit

Permalink
pythongh-93691: fix too broad source locations of with-statement inst…
Browse files Browse the repository at this point in the history
…ructions (python#120125)
  • Loading branch information
iritkatriel authored and noahbkim committed Jul 11, 2024
1 parent a614b59 commit fa240f6
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 3 deletions.
44 changes: 44 additions & 0 deletions Lib/test/test_with.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
__email__ = "mbland at acm dot org"

import sys
import traceback
import unittest
from collections import deque
from contextlib import _GeneratorContextManager, contextmanager, nullcontext
Expand Down Expand Up @@ -749,5 +750,48 @@ def testEnterReturnsTuple(self):
self.assertEqual(10, b1)
self.assertEqual(20, b2)

def testExceptionLocation(self):
# The location of an exception raised from
# __init__, __enter__ or __exit__ of a context
# manager should be just the context manager expression,
# pinpointing the precise context manager in case there
# is more than one.

def init_raises():
try:
with self.Dummy(), self.InitRaises() as cm, self.Dummy() as d:
pass
except Exception as e:
return e

def enter_raises():
try:
with self.EnterRaises(), self.Dummy() as d:
pass
except Exception as e:
return e

def exit_raises():
try:
with self.ExitRaises(), self.Dummy() as d:
pass
except Exception as e:
return e

for func, expected in [(init_raises, "self.InitRaises()"),
(enter_raises, "self.EnterRaises()"),
(exit_raises, "self.ExitRaises()"),
]:
with self.subTest(func):
exc = func()
f = traceback.extract_tb(exc.__traceback__)[0]
indent = 16
co = func.__code__
self.assertEqual(f.lineno, co.co_firstlineno + 2)
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
expected)


if __name__ == '__main__':
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix source locations of instructions generated for with statements.
5 changes: 2 additions & 3 deletions Python/compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -5900,7 +5900,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)

/* Evaluate EXPR */
VISIT(c, expr, item->context_expr);

loc = LOC(item->context_expr);
ADDOP(c, loc, BEFORE_ASYNC_WITH);
ADDOP_I(c, loc, GET_AWAITABLE, 1);
ADDOP_LOAD_CONST(c, loc, Py_None);
Expand Down Expand Up @@ -5998,7 +5998,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
/* Evaluate EXPR */
VISIT(c, expr, item->context_expr);
/* Will push bound __exit__ */
location loc = LOC(s);
location loc = LOC(item->context_expr);
ADDOP(c, loc, BEFORE_WITH);
ADDOP_JUMP(c, loc, SETUP_WITH, final);

Expand Down Expand Up @@ -6031,7 +6031,6 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
/* For successful outcome:
* call __exit__(None, None, None)
*/
loc = LOC(s);
RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc));
ADDOP(c, loc, POP_TOP);
ADDOP_JUMP(c, loc, JUMP, exit);
Expand Down

0 comments on commit fa240f6

Please sign in to comment.