Skip to content

Commit e9cefff

Browse files
iritkatrielestyxx
authored andcommitted
pythongh-93691: fix too broad source locations of with-statement instructions (python#120125)
1 parent 49a3b51 commit e9cefff

File tree

3 files changed

+47
-3
lines changed

3 files changed

+47
-3
lines changed

Lib/test/test_with.py

+44
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
__email__ = "mbland at acm dot org"
66

77
import sys
8+
import traceback
89
import unittest
910
from collections import deque
1011
from contextlib import _GeneratorContextManager, contextmanager, nullcontext
@@ -749,5 +750,48 @@ def testEnterReturnsTuple(self):
749750
self.assertEqual(10, b1)
750751
self.assertEqual(20, b2)
751752

753+
def testExceptionLocation(self):
754+
# The location of an exception raised from
755+
# __init__, __enter__ or __exit__ of a context
756+
# manager should be just the context manager expression,
757+
# pinpointing the precise context manager in case there
758+
# is more than one.
759+
760+
def init_raises():
761+
try:
762+
with self.Dummy(), self.InitRaises() as cm, self.Dummy() as d:
763+
pass
764+
except Exception as e:
765+
return e
766+
767+
def enter_raises():
768+
try:
769+
with self.EnterRaises(), self.Dummy() as d:
770+
pass
771+
except Exception as e:
772+
return e
773+
774+
def exit_raises():
775+
try:
776+
with self.ExitRaises(), self.Dummy() as d:
777+
pass
778+
except Exception as e:
779+
return e
780+
781+
for func, expected in [(init_raises, "self.InitRaises()"),
782+
(enter_raises, "self.EnterRaises()"),
783+
(exit_raises, "self.ExitRaises()"),
784+
]:
785+
with self.subTest(func):
786+
exc = func()
787+
f = traceback.extract_tb(exc.__traceback__)[0]
788+
indent = 16
789+
co = func.__code__
790+
self.assertEqual(f.lineno, co.co_firstlineno + 2)
791+
self.assertEqual(f.end_lineno, co.co_firstlineno + 2)
792+
self.assertEqual(f.line[f.colno - indent : f.end_colno - indent],
793+
expected)
794+
795+
752796
if __name__ == '__main__':
753797
unittest.main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix source locations of instructions generated for with statements.

Python/compile.c

+2-3
Original file line numberDiff line numberDiff line change
@@ -5900,7 +5900,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
59005900

59015901
/* Evaluate EXPR */
59025902
VISIT(c, expr, item->context_expr);
5903-
5903+
loc = LOC(item->context_expr);
59045904
ADDOP(c, loc, BEFORE_ASYNC_WITH);
59055905
ADDOP_I(c, loc, GET_AWAITABLE, 1);
59065906
ADDOP_LOAD_CONST(c, loc, Py_None);
@@ -5998,7 +5998,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
59985998
/* Evaluate EXPR */
59995999
VISIT(c, expr, item->context_expr);
60006000
/* Will push bound __exit__ */
6001-
location loc = LOC(s);
6001+
location loc = LOC(item->context_expr);
60026002
ADDOP(c, loc, BEFORE_WITH);
60036003
ADDOP_JUMP(c, loc, SETUP_WITH, final);
60046004

@@ -6031,7 +6031,6 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
60316031
/* For successful outcome:
60326032
* call __exit__(None, None, None)
60336033
*/
6034-
loc = LOC(s);
60356034
RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc));
60366035
ADDOP(c, loc, POP_TOP);
60376036
ADDOP_JUMP(c, loc, JUMP, exit);

0 commit comments

Comments
 (0)