Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Include/internal/pycore_magic_number.h
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ Known values:
Python 3.14a5 3615 (CALL_FUNCTION_EX always take a kwargs argument)
Python 3.14a5 3616 (Remove BINARY_SUBSCR and family. Make them BINARY_OPs)
Python 3.14a6 3617 (Branch monitoring for async for loops)
Python 3.14a6 3618 (Add oparg to END_ASYNC_FOR)

Python 3.15 will start with 3650

Expand All @@ -282,7 +283,7 @@ PC/launcher.c must also be updated.

*/

#define PYC_MAGIC_NUMBER 3617
#define PYC_MAGIC_NUMBER 3618
/* This is equivalent to converting PYC_MAGIC_NUMBER to 2 bytes
(little-endian) and then appending b'\r\n'. */
#define PYC_MAGIC_NUMBER_TOKEN \
Expand Down
4 changes: 2 additions & 2 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 59 additions & 59 deletions Include/opcode_ids.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

118 changes: 59 additions & 59 deletions Lib/_opcode_metadata.py

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions Lib/dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
STORE_FAST_STORE_FAST = opmap['STORE_FAST_STORE_FAST']
IS_OP = opmap['IS_OP']
CONTAINS_OP = opmap['CONTAINS_OP']
END_ASYNC_FOR = opmap['END_ASYNC_FOR']

CACHE = opmap["CACHE"]

Expand Down Expand Up @@ -605,7 +606,8 @@ def get_argval_argrepr(self, op, arg, offset):
argval = self.offset_from_jump_arg(op, arg, offset)
lbl = self.get_label_for_offset(argval)
assert lbl is not None
argrepr = f"to L{lbl}"
preposition = "from" if deop == END_ASYNC_FOR else "to"
argrepr = f"{preposition} L{lbl}"
elif deop in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST):
arg1 = arg >> 4
arg2 = arg & 15
Expand Down Expand Up @@ -745,7 +747,8 @@ def _parse_exception_table(code):

def _is_backward_jump(op):
return opname[op] in ('JUMP_BACKWARD',
'JUMP_BACKWARD_NO_INTERRUPT')
'JUMP_BACKWARD_NO_INTERRUPT',
'END_ASYNC_FOR') # Not really a jump, but it has a "target"

def _get_instructions_bytes(code, linestarts=None, line_offset=0, co_positions=None,
original_code=None, arg_resolver=None):
Expand Down
9 changes: 9 additions & 0 deletions Lib/test/test_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,15 @@ def with_extended_args(x):
get_line_branches(with_extended_args),
[(1,2,8)])

async def afunc():
async for letter in async_iter1:
2
3

self.assertEqual(
get_line_branches(afunc),
[(1,1,3)])

if check_impl_detail(cpython=True) and ctypes is not None:
py = ctypes.pythonapi
freefunc = ctypes.CFUNCTYPE(None,ctypes.c_voidp)
Expand Down
17 changes: 17 additions & 0 deletions Lib/test/test_dis.py
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,23 @@ def test__try_compile_no_context_exc_on_error(self):
except Exception as e:
self.assertIsNone(e.__context__)

def test_async_for_presentation(self):

async def afunc():
async for letter in async_iter1:
l2
l3

disassembly = self.get_disassembly(afunc)
for line in disassembly.split("\n"):
if "END_ASYNC_FOR" in line:
break
else:
self.fail("No END_ASYNC_FOR in disassembly of async for")
self.assertNotIn("to", line)
self.assertIn("from", line)


@staticmethod
def code_quicken(f):
_testinternalcapi = import_helper.import_module("_testinternalcapi")
Expand Down
Loading
Loading