Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ce6a070

Browse files
ZackerySpytzserhiy-storchaka
authored andcommitted
bpo-34880: Add the LOAD_ASSERTION_ERROR opcode. (GH-15073)
Fix assert statement misbehavior if AssertionError is shadowed.
1 parent 8371799 commit ce6a070

File tree

14 files changed

+2663
-2626
lines changed

14 files changed

+2663
-2626
lines changed

Doc/library/dis.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,14 @@ iterations of the loop.
752752
from the block stack.
753753

754754

755+
.. opcode:: LOAD_ASSERTION_ERROR
756+
757+
Pushes :exc:`AssertionError` onto the stack. Used by the :keyword:`assert`
758+
statement.
759+
760+
.. versionadded:: 3.9
761+
762+
755763
.. opcode:: LOAD_BUILD_CLASS
756764

757765
Pushes :func:`builtins.__build_class__` onto the stack. It is later called

Doc/whatsnew/3.9.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,3 +226,12 @@ Changes in the Python API
226226

227227
* The :mod:`venv` activation scripts no longer special-case when
228228
``__VENV_PROMPT__`` is set to ``""``.
229+
230+
231+
CPython bytecode changes
232+
------------------------
233+
234+
* The :opcode:`LOAD_ASSERTION_ERROR` opcode was added for handling the
235+
:keyword:`assert` statement. Previously, the assert statement would not work
236+
correctly if the :exc:`AssertionError` exception was being shadowed.
237+
(Contributed by Zackery Spytz in :issue:`34880`.)

Include/opcode.h

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/importlib/_bootstrap_external.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ def _write_atomic(path, data, mode=0o666):
271271
# Python 3.8b2 3412 (Swap the position of positional args and positional
272272
# only args in ast.arguments #37593)
273273
# Python 3.8b4 3413 (Fix "break" and "continue" in "finally" #37830)
274+
# Python 3.9a0 3420 (add LOAD_ASSERTION_ERROR #34880)
274275
#
275276
# MAGIC must change whenever the bytecode emitted by the compiler may no
276277
# longer be understood by older implementations of the eval loop (usually
@@ -279,7 +280,7 @@ def _write_atomic(path, data, mode=0o666):
279280
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
280281
# in PC/launcher.c must also be updated.
281282

282-
MAGIC_NUMBER = (3413).to_bytes(2, 'little') + b'\r\n'
283+
MAGIC_NUMBER = (3420).to_bytes(2, 'little') + b'\r\n'
283284
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
284285

285286
_PYCACHE = '__pycache__'

Lib/opcode.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ def jabs_op(name, op):
109109
def_op('LOAD_BUILD_CLASS', 71)
110110
def_op('YIELD_FROM', 72)
111111
def_op('GET_AWAITABLE', 73)
112-
112+
def_op('LOAD_ASSERTION_ERROR', 74)
113113
def_op('INPLACE_LSHIFT', 75)
114114
def_op('INPLACE_RSHIFT', 76)
115115
def_op('INPLACE_AND', 77)

Lib/test/test_dis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def bug1333982(x=[]):
147147
dis_bug1333982 = """\
148148
%3d 0 LOAD_CONST 1 (0)
149149
2 POP_JUMP_IF_TRUE 26
150-
4 LOAD_GLOBAL 0 (AssertionError)
150+
4 LOAD_ASSERTION_ERROR
151151
6 LOAD_CONST 2 (<code object <listcomp> at 0x..., file "%s", line %d>)
152152
8 LOAD_CONST 3 ('bug1333982.<locals>.<listcomp>')
153153
10 MAKE_FUNCTION 0

Lib/test/test_exceptions.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,22 @@ def g():
12851285
next(i)
12861286
next(i)
12871287

1288+
@unittest.skipUnless(__debug__, "Won't work if __debug__ is False")
1289+
def test_assert_shadowing(self):
1290+
# Shadowing AssertionError would cause the assert statement to
1291+
# misbehave.
1292+
global AssertionError
1293+
AssertionError = TypeError
1294+
try:
1295+
assert False, 'hello'
1296+
except BaseException as e:
1297+
del AssertionError
1298+
self.assertIsInstance(e, AssertionError)
1299+
self.assertEqual(str(e), 'hello')
1300+
else:
1301+
del AssertionError
1302+
self.fail('Expected exception')
1303+
12881304

12891305
class ImportErrorTests(unittest.TestCase):
12901306

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
The :keyword:`assert` statement now works properly if the
2+
:exc:`AssertionError` exception is being shadowed.
3+
Patch by Zackery Spytz.

Python/ceval.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2242,6 +2242,13 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
22422242
}
22432243
}
22442244

2245+
case TARGET(LOAD_ASSERTION_ERROR): {
2246+
PyObject *value = PyExc_AssertionError;
2247+
Py_INCREF(value);
2248+
PUSH(value);
2249+
FAST_DISPATCH();
2250+
}
2251+
22452252
case TARGET(LOAD_BUILD_CLASS): {
22462253
_Py_IDENTIFIER(__build_class__);
22472254

Python/compile.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1129,6 +1129,8 @@ stack_effect(int opcode, int oparg, int jump)
11291129
return (oparg & FVS_MASK) == FVS_HAVE_SPEC ? -1 : 0;
11301130
case LOAD_METHOD:
11311131
return 1;
1132+
case LOAD_ASSERTION_ERROR:
1133+
return 1;
11321134
default:
11331135
return PY_INVALID_STACK_EFFECT;
11341136
}
@@ -3253,16 +3255,10 @@ compiler_from_import(struct compiler *c, stmt_ty s)
32533255
static int
32543256
compiler_assert(struct compiler *c, stmt_ty s)
32553257
{
3256-
static PyObject *assertion_error = NULL;
32573258
basicblock *end;
32583259

32593260
if (c->c_optimize)
32603261
return 1;
3261-
if (assertion_error == NULL) {
3262-
assertion_error = PyUnicode_InternFromString("AssertionError");
3263-
if (assertion_error == NULL)
3264-
return 0;
3265-
}
32663262
if (s->v.Assert.test->kind == Tuple_kind &&
32673263
asdl_seq_LEN(s->v.Assert.test->v.Tuple.elts) > 0)
32683264
{
@@ -3277,7 +3273,7 @@ compiler_assert(struct compiler *c, stmt_ty s)
32773273
return 0;
32783274
if (!compiler_jump_if(c, s->v.Assert.test, end, 1))
32793275
return 0;
3280-
ADDOP_O(c, LOAD_GLOBAL, assertion_error, names);
3276+
ADDOP(c, LOAD_ASSERTION_ERROR);
32813277
if (s->v.Assert.msg) {
32823278
VISIT(c, expr, s->v.Assert.msg);
32833279
ADDOP_I(c, CALL_FUNCTION, 1);

0 commit comments

Comments
 (0)