Skip to content

Commit 35f1856

Browse files
iritkatrielmiss-islington
authored andcommitted
pythongh-93691: fix too broad source locations of with-statement instructions (pythonGH-120125)
(cherry picked from commit eca3f77) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
1 parent d47d7e1 commit 35f1856

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
@@ -5913,7 +5913,7 @@ compiler_async_with(struct compiler *c, stmt_ty s, int pos)
59135913

59145914
/* Evaluate EXPR */
59155915
VISIT(c, expr, item->context_expr);
5916-
5916+
loc = LOC(item->context_expr);
59175917
ADDOP(c, loc, BEFORE_ASYNC_WITH);
59185918
ADDOP_I(c, loc, GET_AWAITABLE, 1);
59195919
ADDOP_LOAD_CONST(c, loc, Py_None);
@@ -6011,7 +6011,7 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
60116011
/* Evaluate EXPR */
60126012
VISIT(c, expr, item->context_expr);
60136013
/* Will push bound __exit__ */
6014-
location loc = LOC(s);
6014+
location loc = LOC(item->context_expr);
60156015
ADDOP(c, loc, BEFORE_WITH);
60166016
ADDOP_JUMP(c, loc, SETUP_WITH, final);
60176017

@@ -6044,7 +6044,6 @@ compiler_with(struct compiler *c, stmt_ty s, int pos)
60446044
/* For successful outcome:
60456045
* call __exit__(None, None, None)
60466046
*/
6047-
loc = LOC(s);
60486047
RETURN_IF_ERROR(compiler_call_exit_with_nones(c, loc));
60496048
ADDOP(c, loc, POP_TOP);
60506049
ADDOP_JUMP(c, loc, JUMP, exit);

0 commit comments

Comments
 (0)