unreleased: Version 0.14.0

New features:

  • 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.


  • 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.10) PR #106


  • Make the install process PEP517 compliant PR #97

  • Drop support for Python 3.6 and 3.7 PR #100

04/10/2021: Version 0.13.0

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


  • 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

02/02/2021: Version 0.12.0

New features:

  • All calculations of stacksize now check for stack underflow to avoid segfault at runtime PR #69


  • Fix recursion limitations when compiling bytecode with numerous basic blocks. PR #57

  • Fix handling of line offsets. Issue #67, PR #71

API changes:

2020-03-02: Version 0.11.0

New features:

  • The infer_flags() can now be used to forcibly mark a function as asynchronous or not.


  • Fix a design flaw in the flag inference mechanism that could very easily lead to invalid flags configuration PR #56

2020-02-02: Version 0.10.0

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

2019-12-01: Version 0.9.0

New features:

  • Add support for released version of Python 3.8 and update documentation.

2019-02-18: Version 0.8.0

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


  • Avoid throwing OverflowError when applying stack_effect on valid Instr objects. PR #43, PR #44

2018-04-15: Version 0.7.0

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).


  • 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.

2018-03-24: Version 0.6

  • Add stack depth computation based on control flow graph analysis

  • Add higher level flags handling using IntFlags enum and inference function

  • Add an instructions argument to ConcreteBytecode, and validate its value

  • Do not delete EXTENDED_ARG instructions that have no arg

2017-01-05: Version 0.5

  • 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.

2016-04-12: Version 0.4

Peephole optimizer:

  • Reenable optimization on JUMP_IF_TRUE_OR_POP jumping to POP_JUMP_IF_FALSE <target>.

2016-03-02: Version 0.3

New features:

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 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


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.

2016-02-29: Version 0.2

  • 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:

  • 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 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

2016-02-26: Version 0.1

  • Rewrite completely the API!

2016-02-23: Release 0.0

  • First public release