pypy/interpreter/astcompiler/test/apptest_exceptiongroup.py::test_with_try_except_as_reraise
def test_with_try_except_as_reraise():
"""with + try/except T as name where the handler raises: the new exception
must propagate through the with block's __exit__ without crashing.
Mirrors import_helper.import_module: with CM(): try: ... except E as msg: raise Other"""
class CM:
def __init__(self): self.exited = False; self.exc_type = None
def __enter__(self): return self
def __exit__(self, tp, val, tb):
self.exited = True
self.exc_type = tp
return False # do not suppress
cm = CM()
# normal_return=True exercises the normal-exit path so POP_BLOCK fires,
# mirroring import_helper.import_module which also has a normal return.
def inner(cm, raise_in_handler):
with cm:
try:
if raise_in_handler:
raise ValueError("original")
return "ok"
except ValueError as e:
raise TypeError("new")
print("=== dis(inner) ===")
> dis.dis(inner)
interpreter/astcompiler/test/apptest_exceptiongroup.py:31:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
x = <code object inner, file "/build_dir/own-linux-x86-64/build/pypy/interpreter/astcompiler/test/apptest_exceptiongroup.py", line 21>
def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False):
"""Disassemble classes, methods, functions, and other compiled objects.
With no argument, disassemble the last traceback.
Compiled objects currently include generator objects, async generator
objects, and coroutine objects, all of which store their code object
in a special attribute.
"""
if x is None:
distb(file=file, show_caches=show_caches, adaptive=adaptive)
return
# Extract functions from methods.
if hasattr(x, '__func__'):
x = x.__func__
# Extract compiled code objects from...
if hasattr(x, '__code__'): # ...a function, or
x = x.__code__
elif hasattr(x, 'gi_code'): #...a generator object, or
x = x.gi_code
elif hasattr(x, 'ag_code'): #...an asynchronous generator object, or
x = x.ag_code
elif hasattr(x, 'cr_code'): #...a coroutine.
x = x.cr_code
# Perform the disassembly.
if hasattr(x, '__dict__'): # Class or module
items = sorted(x.__dict__.items())
for name, x1 in items:
if isinstance(x1, _have_code):
print("Disassembly of %s:" % name, file=file)
try:
dis(x1, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive)
except TypeError as msg:
print("Sorry:", msg, file=file)
print(file=file)
elif hasattr(x, 'co_code'): # Code object
> _disassemble_recursive(x, file=file, depth=depth, show_caches=show_caches, adaptive=adaptive)
../lib-python/3/dis.py:114:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
co = <code object inner, file "/build_dir/own-linux-x86-64/build/pypy/interpreter/astcompiler/test/apptest_exceptiongroup.py", line 21>
def _disassemble_recursive(co, *, file=None, depth=None, show_caches=False, adaptive=False):
> disassemble(co, file=file, show_caches=show_caches, adaptive=adaptive)
../lib-python/3/dis.py:555:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
co = <code object inner, file "/build_dir/own-linux-x86-64/build/pypy/interpreter/astcompiler/test/apptest_exceptiongroup.py", line 21>
lasti = W_IntObject(-1)
def disassemble(co, lasti=-1, *, file=None, show_caches=False, adaptive=False):
"""Disassemble a code object."""
linestarts = dict(findlinestarts(co))
exception_entries = _parse_exception_table(co)
> _disassemble_bytes(_get_code_array(co, adaptive),
../lib-python/3/dis.py:548:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
code = W_BytesObject('|\x005\x00\x01\x00\t\x00|\x01r\nt\x00d\x01\x83\x01\x82\x01\t\x0...0w\x01#\x001\x00s*w\x02&\x03Y\x00w\x01\x01\x00Y\x00\x01\x00\x01\x00d\x00S\x00')
lasti = W_IntObject(-1), varname_from_oparg = bound method _varname_from_oparg
names = W_TupleObject(W_UnicodeObject('ValueError'), W_UnicodeObject('TypeError'))
co_consts = W_TupleObject(<pypy.objspace.std.noneobject.W_NoneObject object at 0x7efffe5b9850>, W_UnicodeObject('original'), W_UnicodeObject('ok'), W_UnicodeObject('new'))
linestarts = W_DictObject(<pypy.objspace.std.dictmultiobject.IntDictStrategy object at 0x7efffda17150>)
def _disassemble_bytes(code, lasti=-1, varname_from_oparg=None,
names=None, co_consts=None, linestarts=None,
*, file=None, line_offset=0, exception_entries=(),
co_positions=None, show_caches=False):
# Omit the line number column entirely if we have no line number info
show_lineno = bool(linestarts)
if show_lineno:
maxlineno = max(linestarts.values()) + line_offset
if maxlineno >= 1000:
lineno_width = len(str(maxlineno))
else:
lineno_width = 3
else:
lineno_width = 0
maxoffset = len(code) - 2
if maxoffset >= 10000:
offset_width = len(str(maxoffset))
else:
offset_width = 4
> for instr in _get_instructions_bytes(code, varname_from_oparg, names,
../lib-python/3/dis.py:586:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
code = W_BytesObject('|\x005\x00\x01\x00\t\x00|\x01r\nt\x00d\x01\x83\x01\x82\x01\t\x0...0w\x01#\x001\x00s*w\x02&\x03Y\x00w\x01\x01\x00Y\x00\x01\x00\x01\x00d\x00S\x00')
varname_from_oparg = bound method _varname_from_oparg
names = W_TupleObject(W_UnicodeObject('ValueError'), W_UnicodeObject('TypeError'))
co_consts = W_TupleObject(<pypy.objspace.std.noneobject.W_NoneObject object at 0x7efffe5b9850>, W_UnicodeObject('original'), W_UnicodeObject('ok'), W_UnicodeObject('new'))
linestarts = W_DictObject(<pypy.objspace.std.dictmultiobject.IntDictStrategy object at 0x7efffda17150>)
line_offset = W_IntObject(0)
exception_entries = W_ListObject(<pypy.objspace.std.listobject.ObjectListStrategy object at 0x7eff...ct(84), W_IntObject(86), W_IntObject(78), W_IntObject(3), W_BoolObject(True))])
co_positions = <pypy.objspace.std.iterobject.W_FastListIterObject object at 0x7efffa3a2150>
show_caches = W_BoolObject(False)
def _get_instructions_bytes(code, varname_from_oparg=None,
names=None, co_consts=None,
linestarts=None, line_offset=0,
exception_entries=(), co_positions=None,
show_caches=False):
"""Iterate over the instructions in a bytecode string.
Generates a sequence of Instruction namedtuples giving the details of each
opcode. Additional information about the code's runtime environment
(e.g. variable names, co_consts) can be specified using optional
arguments.
"""
co_positions = co_positions or iter(())
get_name = None if names is None else names.__getitem__
labels = set(findlabels(code))
for start, end, target, _, _ in exception_entries:
for i in range(start, end):
labels.add(target)
starts_line = None
for offset, op, arg in _unpack_opargs(code):
if linestarts is not None:
starts_line = linestarts.get(offset, None)
if starts_line is not None:
starts_line += line_offset
is_jump_target = offset in labels
argval = None
argrepr = ''
positions = Positions(*next(co_positions, ()))
deop = _deoptop(op)
caches = _inline_cache_entries[deop]
if arg is not None:
# Set argval to the dereferenced value of the argument when
# available, and argrepr to the string representation of argval.
# _disassemble_bytes needs the string repr of the
# raw name index for LOAD_GLOBAL, LOAD_CONST, etc.
argval = arg
if deop in hasconst:
argval, argrepr = _get_const_info(deop, arg, co_consts)
elif deop in hasname:
if deop == LOAD_GLOBAL:
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL + " + argrepr
elif deop == LOAD_ATTR:
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
elif deop == LOAD_SUPER_ATTR:
argval, argrepr = _get_name_info(arg//4, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:
argval = arg*2
argrepr = "to " + repr(argval)
elif deop in hasjrel:
signed_arg = -arg if _is_backward_jump(deop) else arg
argval = offset + 2 + signed_arg*2
argval += 2 * caches
argrepr = "to " + repr(argval)
elif deop in haslocal or deop in hasfree:
argval, argrepr = _get_name_info(arg, varname_from_oparg)
elif deop in hascompare:
argval = cmp_op[arg>>4]
argrepr = argval
elif deop == FORMAT_VALUE:
argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
argval = (argval, bool(arg & 0x4))
if argval[1]:
if argrepr:
argrepr += ', '
argrepr += 'with format'
elif deop == MAKE_FUNCTION:
argrepr = ', '.join(s for i, s in enumerate(MAKE_FUNCTION_FLAGS)
if arg & (1<<i))
> elif deop == BINARY_OP:
E (application-level) NameError: name 'BINARY_OP' is not defined
../lib-python/3/dis.py:512: NameError
---------- Captured stdout call ----------
=== dis(inner) ===
22 0 LOAD_FAST 0 (cm)
2 BEFORE_WITH
4 POP_TOP
23 6 NOP
24 8 LOAD_FAST 1 (raise_in_handler)
10 POP_JUMP_IF_FALSE 10 (to 20)
25 12 LOAD_GLOBAL 0 (ValueError)
22 22 LOAD_CONST 0 (None)
24 DUP_TOP
26 DUP_TOP
builder: own-linux-x86-64 build #10877+
test: pypy/interpreter/astcompiler/test/apptest_exceptiongroup.py::test_with_try_except_as_reraise