summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2024-09-02 14:53:39 (GMT)
committerGitHub <noreply@github.com>2024-09-02 14:53:39 (GMT)
commit494181e44db809204f55eaebc88a255acb09a18f (patch)
tree328eae3eef4e77450bebabf780f64b217ae94ded
parent3b3a1a8e7ebbd824778d16fad457a3fa15a9f7e4 (diff)
downloadcpython-494181e44db809204f55eaebc88a255acb09a18f.zip
cpython-494181e44db809204f55eaebc88a255acb09a18f.tar.gz
cpython-494181e44db809204f55eaebc88a255acb09a18f.tar.bz2
[3.13] gh-93691: fix too broad source locations of with-statement instructions (GH-120125) (#123604)
gh-93691: fix too broad source locations of with-statement instructions (GH-120125) (cherry picked from commit eca3f7762c23b22a73a5e0b09520748c88aab4a0) Co-authored-by: Irit Katriel <1055913+iritkatriel@users.noreply.github.com>
-rw-r--r--Lib/test/test_with.py44
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst1
-rw-r--r--Python/compile.c5
3 files changed, 47 insertions, 3 deletions
diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py
index d819023..e8c4ddf 100644
--- a/Lib/test/test_with.py
+++ b/Lib/test/test_with.py
@@ -5,6 +5,7 @@ __author__ = "Mike Bland"
__email__ = "mbland at acm dot org"
import sys
+import traceback
import unittest
from collections import deque
from contextlib import _GeneratorContextManager, contextmanager, nullcontext
@@ -749,5 +750,48 @@ class NestedWith(unittest.TestCase):
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()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst b/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst
new file mode 100644
index 0000000..c06d5a2
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2024-06-05-18-29-18.gh-issue-93691.6OautB.rst
@@ -0,0 +1 @@
+Fix source locations of instructions generated for with statements.
diff --git a/Python/compile.c b/Python/compile.c
index c331271..ed6923e 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -6036,7 +6036,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);
@@ -6134,7 +6134,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);
@@ -6167,7 +6167,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);