NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #491 most downloaded on PyPI
Python module to generate and modify bytecode
Last release 1 months ago
21 Aug 2026
Release timing varies
gaps range from 6 weeks to 1.2 years
Nearly every release is documented
notes for 25 of 26 stable releases
Nothing withdrawn
no release was ever pulled
11 years old
26 releases · first in 2016
build(deps): bump codecov/codecov-action from 6 to 7 by @dependabot [bot] in #206
Full Changelog: 0.18.1...0.19.0
One column per quarter.
Add support for Python 3.15 (tested against Python 3.15 rc) PR #192
fix: match correct try block markers in CFG by @P403n1x87 in #205
Full Changelog: 0.18.0...0.18.1
Bugfixes:
Fix an AssertionError in stack-size computation when a single exception region is split into multiple TryBegin instances sharing one handler (as produced by bytecode-rewriting tools that wrap a whole function body in a single handler). TryBegin/TryEnd are now matched on the handler block rather than on TryBegin identity.
build(deps): bump actions/setup-python from 5 to 6 by @dependabot [bot] in #171
Full Changelog: 0.17.0...0.18.0
drop support for Python 3.9 and 3.10 PR #180
Replace string literal type annotations with postponed evaluation using from __future__ import annotations PR #191
multiple performance improvements PRs #172, #193, #196, #194, #197, #198, #199, #200, #201, #202, #203
Breaking changes:
BasicBlock, Bytecode, and ConcreteBytecode now validate inserted instructions at insertion time (append, extend, insert, __setitem__) rather than during iteration. Code that relied on catching ValueError from list(block) or for instr in block: must wrap the insertion call instead. PR #199
Bugfixes:
Fix handling of END_ASYNC_FOR which is a backward jump PR #179
cfg: fix stack depth of TryBegin when splitting across blocks. by @arusuki in #163
next_block attribute of the new block in ControlFlowGraph.split_block by @BergLucas in #170Full Changelog: 0.16.2...0.17.0
New features:
Add support for Python 3.14 PR #166
Support for Python 3.14, comes with a number of changes reflecting changes in CPython bytecode itself:
introduced an enum for BINARY_OP argument which now supports subscribe. When disassembling the enum is always used, when creating bytecode from scratch integer values are coerced into the right enum member.
support BUILD_TEMPLATE, BUILD_INTERPOLATION, LOAD_SMALL_INT, LOAD_FAST_BORROW and LOAD_FAST_BORROW_LOAD_FAST_BORROW
LOAD_COMMON_CONSTANT, LOAD_SPECIAL whose argument is described using dedicated enums CommonConstant, SpecialMethod
CONVERT_VALUE (FORMAT_VALUE in Python < 3.13) now use the FormatValue enum. When disassembling the enum is always used, when creating bytecode from scratch integer values are coerced into the right enum member.
Bugfixes:
properly set the next_block attribute of the new block created by ControlFlowGraph.split_block. PR #170
cfg: fix dead block detection by accounting for fall-through edges by @arusuki in #161
Bugfixes:
fix ControlFlowGraph dead block detection by accounting for fall-through edges. PR #161
Minor fixes following linter recommendations by @MatthieuDartiailh in #154
Full Changelog: 0.16.0...0.16.1
Use ruff for linting and formatting by @MatthieuDartiailh in #134
Full Changelog: 0.15.1...0.16.0
New features:
Add support for Python 3.13 PR #146
Support for Python 3.13, comes with a number of changes reflecting changes in CPython bytecode itself:
handle the ability of comparison to cast with new enum variants: LT_CAST, LE_CAST, etc
allow LOAD_FAST to access free and cell vars
Bugfixes:
Properly handle TryEnd with no matching TryBegin in stack size computation on the CFG PR #149
Ensure that empty or small (one-instruction) try blocks are handled without problems when compiling and de-compiling abstract code for CPython 3.11 and later. PR #145
Disallow creating an instruction targeting a pseudo/instrumented opcode PR #133
Bugfixes:
Disallow creating an instruction targeting a pseudo/instrumented opcode PR #133
Fixes encoding of 0 as a varint PR #132
Correct spelling of "INTRINSIC" in several places; this affected some ops in Python 3.12. PR #131
Add support for Python 3.12 PR #122
New features:
Add support for Python 3.12 PR #122
Support for Python 3.12, comes with a number of changes reflecting changes in CPython bytecode itself:
handle the ability of LOAD_ATTR to replace LOAD_METHOD As a consequence the argument is now a tuple[bool, str]
similarly LOAD_SUPER_ATTR which uses the 2 lowest bits as flag takes a tuple[bool, bool, str] as argument
POP_JUMP_IF_* instructions are undirected in Python 3.12
YIELD_VALUE now takes an argument
Support for CALL_INTRINSIC_1/2 led to the addition of 2 new enums to represent the argument
allow to convert a CFG, for which stack sizes have not been computed, to Bytecode even in the presence of mergeable TryBegin/TryEnd PR #120
Bugfixes:
allow to convert a CFG, for which stack sizes have not been computed, to Bytecode even in the presence of mergeable TryBegin/TryEnd PR #120
remove spurious TryEnd leftover when going from CFG to Bytecode PR #120
allow to disassemble code containing EXTENDED_ARG targeting a NOP PR #117
Bugfixes:
allow to disassemble code containing EXTENDED_ARG targeting a NOP PR #117
Removed the peephole optimizer PR #107
New features:
Removed the peephole optimizer PR #107
Basically changes in Python 3.11 made it hard to port and the maintenance cost exceeded the perceived use. It could be re-added if there is a demand for it.
Add support for Python 3.11 PR #107
Support for Python 3.11, comes with a number of changes reflecting changes in CPython bytecode itself:
support for the exception table in ConcreteBytecode
support for pseudo-instruction TryBegin and TryEnd describing the exception table in Bytecode and ControlflowGraph
new keyword arguments in conversion method related to computations required for the exception table
handling of CACHE opcode at the ConcreteBytecode level
handling of the ability of LOAD_GLOBAL to push NULL (the argument is now a tuple[bool, str])
support for end_lineno and column offsets in instructions
support for co_qualname (as qualname on bytecode objects)
and a number of internal changes related to changes in the internal bytecode representation.
Add type annotations and make types stricter PR # 105 In particular, ConcreteInstr does not inherit from Instr anymore and one cannot use ConcreteInstr in Bytecode object. This is saner than before.
Bugfixes:
Removed EXC_MATCH from the Compare enumeration starting with Python 3.9. The new JUMP_IF_NOT_EXC_MATCH opcode should be used instead.
Removed IN, NOT_IN, IS, NOT_IS from the Compare enumeration starting with Python 3.9. The new CONTAINS_OP and IS_OP opcodes should be used instead.
Add proper pre and post stack effects to all opcodes (up to Python 3.11) PR #106 #107
Maintenance:
Make the install process PEP517 compliant PR #97
Drop support for Python 3.6 and 3.7 PR #100
Add support for Python 3.10 new encoding of line number. This support is minimal in the sense that we still systematically assign a line number while
New features:
Add support for Python 3.10 new encoding of line number. This support is minimal in the sense that we still systematically assign a line number while the new format allow bytecode with absolutely no line number. PR #72
Bugfixes:
Fix handling of RERAISE (introduced in 3.9) when creating a ControlFlowGraph, previously it was not considered final. PR #72
Fix line table assembly in Python 3.10. PR #85
All calculations of stacksize now check for stack underflow to avoid segfault at runtime PR #69
New features:
All calculations of stacksize now check for stack underflow to avoid segfault at runtime PR #69
Bugfixes:
Fix recursion limitations when compiling bytecode with numerous basic blocks. PR #57
Fix handling of line offsets. Issue #67, PR #71
API changes:
Forbid an Instr to hold an EXTENDED_ARG op_code PR #65
Forbid the use of ConcreteInstr in Bytecode and ControlFlowGraph PR #65 This is motivated by the extra complexity that handling possible EXTENDED_ARG instruction in those representation would bring (stack computation, etc)
Always remove EXTENDED_ARG when converting ConcreteBytecode to Bytecode PR #65 This is equivalent to say that the ConcreteBytecode converted to Bytecode was generated by ConcreteBytecode.from_code with extended_args=False
Instr now has a new method Instr.pre_and_post_stack_effect for checking the prerequisite stack size of an operation PR #69
_compute_stack_size now uses Instr.pre_and_post_stack_effect to compute the stack size to reject code that will lead to runtime segfault caused by stack underflow PR #69
The infer_flags can now be used to forcibly mark a function as asynchronous or not.
New features:
The infer_flags can now be used to forcibly mark a function as asynchronous or not.
Bugfixes:
Fix a design flaw in the flag inference mechanism that could very easily lead to invalid flags configuration PR #56
Slices and copy of Bytecode, ConcreteBytecode and BasicBlock are now of the same type as the original container. PR #52
New features:
Slices and copy of Bytecode, ConcreteBytecode and BasicBlock are now of the same type as the original container. PR #52
Bytecode, ConcreteBytecode, BasicBlock and ControlFlowGraph have a new legalize method validating their content and removing SetLineno. PR #52
Modify the implementation of const_key to avoid manual synchronizations with _PyCode_ConstantKey in CPython codebase and allow the use of arbitrary Python objects as constants of nested code objects. #54
API changes:
Add Compare enum to public API. PR #53
Add support for released version of Python 3.8 and update documentation.
New features:
Add support for released version of Python 3.8 and update documentation.
Add support for Python 3.7 PR #29
New features:
Add support for Python 3.7 PR #29
Add preliminary support for Python 3.8-dev PR #41
Allow to use any Python object as constants to enable aggressive optimizations PR #34
API changes:
stack_effect is now a method of Instr and not as property anymore. PR #29
Bugfixes:
Avoid throwing OverflowError when applying stack_effect on valid Instr objects. PR #43, PR #44
Add compute_jumps_passes optional argument to Bytecode.to_code and to Bytecode.to_concrete_bytecode to control the number of passes performed to compu
New features:
Add compute_jumps_passes optional argument to Bytecode.to_code and to Bytecode.to_concrete_bytecode to control the number of passes performed to compute jump targets. In theory the required number is only bounded by the size of the code, but usually the algorithm converges quickly (< 10 iterations).
Bugfixes:
proper handling of EXTENDED_ARG without arguments PR #28:
EXTENDED_ARG are once again removed but their presence is recorded to avoid having issues with offsets in jumps. Similarly when round tripping code through ConcreteBytecode the EXTENDED_ARG without args are preserved while if going through Bytecode they are removed.
Nothing published for this version
Add the new bytecode format of Python 3.6.
Add the new bytecode format of Python 3.6.
Remove the BaseInstr class which became useless. It was replaced with the Instr class.
Documentation: Add a comparison with byteplay and codetransformer.
Remove the BaseIntr class: Instr becomes the new base class.
Fix PEP 8 issues and check PEP 8 on Travis CI.
Reenable optimization on JUMP_IF_TRUE_OR_POP jumping to POP_JUMP_IF_FALSE .
Peephole optimizer:
Reenable optimization on JUMP_IF_TRUE_OR_POP jumping to POP_JUMP_IF_FALSE <target>.
Add ControlFlowGraph.get_block_index method
New features:
Add ControlFlowGraph.get_block_index method
API changes:
Rename Block class to BasicBlock
Rename BytecodeBlocks class to ControlFlowGraph
Rename BaseInstr.op to BaseInstr.opcode
Rename BaseBytecode.kw_only_argcount attribute to BaseBytecode.kwonlyargcount, name closer to the Python code object attribute (co_kwonlyargcount)
Instr constructor and its ~BaseInstr.set method now validates the argument type
Add Compare enum, used for COMPARE_OP argument of Instr
Remove lineno parameter from the BaseInstr.set method
Add CellVar and FreeVar classes: instructions having a cell or free variable now require a CellVar or FreeVar instance rather than a simple string (str). This change is required to handle correctly code with duplicated variable names in cell and free variables.
ControlFlowGraph: remove undocumented to_concrete_bytecode() and to_code() methods
Bugfixes:
Fix support of SetLineno
Peephole optimizer:
Better code for LOAD_CONST x n + BUILD_LIST + UNPACK_SEQUENCE: rewrite LOAD_CONST in the reverse order instead of using ROT_TWO and ROT_THREE. This optimization supports more than 3 items.
Remove JUMP_ABSOLUTE pointing to the following code. It can occur after dead code was removed.
Remove NOP instructions
Bugfix: catch IndexError when trying to get the next instruction.
Again, the API is deeply reworked.
Again, the API is deeply reworked.
The project has now a documentation: bytecode documentation
Fix bug #1: support jumps larger than 2^16.
Add a new bytecode.peephole_opt module: a peephole optimizer, code based on peephole optimizer of CPython 3.6 which is implemented in C
Add dump_bytecode function to ease debug.
Instr:
Add Instr.is_final method
Add Instr.copy and ConcreteInstr.copy methods
Instr now uses variable name instead of integer for cell and free variables.
Rename Instr.is_jump to Instr.has_jump
ConcreteInstr is now mutable
Redesign the BytecodeBlocks class:
Block have no more label attribute: jump targets are now directly blocks
Rename BytecodeBlocks.add_label() method to BytecodeBlocks.split_block
Labels are not more allowed in blocks
BytecodeBlocks.from_bytecode now splits blocks after final instructions (Instr.is_final) and after conditional jumps (Instr.is_cond_jump). It helps the peephole optimizer to respect the control flow and to remove dead code.
Rework API to convert bytecode classes:
BytecodeBlocks: Remove to_concrete_bytecode() and to_code() methods. Now you first have to convert blocks to bytecode using ~BytecodeBlocks.to_bytecode.
Remove Bytecode.to_bytecode_blocks() method, replaced with BytecodeBlocks.from_bytecode
Remove ConcreteBytecode.to_concrete_bytecode() and Bytecode.to_bytecode() methods which did nothing (return self)
Fix ConcreteBytecode for code with no constant (empty list of constants)
Fix argnames in ConcreteBytecode.to_bytecode: use CO_VARARGS and CO_VARKEYWORDS flags to count the number of arguments
Fix const_key() to compare correctly constants equal but of different types and special cases like -0.0 and +0.0
- Rewrite completely the API!
Rewrite completely the API!
- First public release
First public release
Your coding agent can read these notes before it upgrades. Set up the MCP server →