codetransformer

Bytecode transformers for CPython inspired by the ast module’s NodeTransformer.

codetransformer is a library that provides utilities for working with CPython bytecode at runtime. Among other things, it provides:

The existence of codetransformer is motivated by the desire to override parts of the python language that cannot be easily hooked via more standard means. Examples of program transformations made possible using code transformers include:

Contents:

Working with Code Objects

The Code type is the foundational abstraction in codetransformer. It provides high-level APIs for working with logically-grouped sets of instructions and for converting to and from CPython’s native code type.

Constructing Code Objects

The most common way constructing a Code object is to use the from_pycode() classmethod, which accepts a CPython code object.

There are two common ways of building raw code objects:

  • CPython functions have a __code__ attribute, which contains the bytecode executed by the function.
  • The compile() builtin can compile a string of Python source code into a code object.

Using from_pycode(), we can build a Code object and inspect its contents:

>>> from codetransformer import Code
>>> def add2(x):
...     return x + 2
...
>>> co = Code.from_pycode(add.__code__)
>>> co.instrs
(LOAD_FAST('x'), LOAD_CONST(2), BINARY_ADD, RETURN_VALUE)
>>> co.argnames
('x',)
>>> c.consts
(2,)

We can convert our Code object back into its raw form via the to_bytecode() method:

>>> co.to_pycode()
<code object add2 at 0x7f6ba05f2030, file "<stdin>", line 1>

Building Transformers

Once we have the ability to convert to and from an abstract code representation, we gain the ability to perform transformations on that abtract representation.

Let’s say that we want to replace the addition operation in our add2 function with a multiplication. We could try to mutate our Code object directly before converting back to Python bytecode, but there are many subtle invariants [1] between the instructions and the other pieces of metadata that must be maintained to ensure that the generated output can be executed correctly.

Rather than encourage users to mutate Code objects in place, codetransformer provides the CodeTransformer class, which allows users to declaratively describe operations to perform on sequences of instructions.

Implemented as a CodeTransformer, our “replace additions with multiplications” operation looks like this:

from codetransformer import CodeTransformer, pattern
from codetransformer.instructions import BINARY_ADD, BINARY_MULTIPLY


class add2mul(CodeTransformer):
    @pattern(BINARY_ADD)
    def _add2mul(self, add_instr):
        yield BINARY_MULTIPLY().steal(add_instr)

The important piece here is the _add2mul method, which has been decorated with a pattern. Patterns provide an API for describing sequences of instructions to match against for replacement and/or modification. The CodeTransformer base class looks at methods with registered patterns and compares them against the instructions of the Code object under transformation. For each matching sequence of instructions, the decorated method is called with all matching instructions *-unpacked into the method. The method’s job is to take the input instructions and return an iterable of new instructions to serve as replacements. It is often convenient to implement transformer methods as generator functions, as we’ve done here.

In this example, we’ve supplied the simplest possible pattern: a single instruction type to match. [2] Our transformer method will be called on every BINARY_ADD instruction in the target code object, and it will yield a BINARY_MULTIPLY as replacement each time.

Applying Transformers

To apply a CodeTransformer to a function, we construct an instance of the transformer and call it on the function we want to modify. The result is a new function whose instructions have been rewritten applying our transformer’s methods to matched sequences of the input function’s instructions. The original function is not mutated in place.

Example:

>>> transformer = add2mul()
>>> mul2 = transformer(add2) # mult2 is a brand-new function
>>> mul2(5)
10

When we don’t care about having access to the pre-transformed version of a function, it’s convenient and idiomatic to apply transformers as decorators:

>>> @add2mul()
... def mul2(x):
...     return x + 2
...
>>> mul2(5)
10
[1]For example, if we add a new constant, we have to ensure that we correctly maintain the indices of existing constants in the generated code’s co_consts, and if we replace an instruction that was the target of a jump, we have to make sure that the jump instruction resolves correctly to our new instruction.
[2]Many more complex patterns are possible. See the docs for codetransformer.patterns.pattern for more examples.

Pattern API

Most bytecode transformations are best expressed by identifying a pattern in the bytecode and emitting some replacement. codetransformer makes it easy to express and work on these patterns by defining a small dsl for use in CodeTransformer classes.

Matchables

A pattern is expressed by a sequence of matchables paired with the startcode. A matchable is anything that we can compare a sequence of bytecode to.

Instructions

The most atomic matchable is any Instruction class. These classes each can be used to define a pattern that matches instances of that instruction. For example, the pattern:

LOAD_CONST

will match a single LOAD_CONST instance.

All matchables support the following operations:

or

Matchables can be or’d together to create a new matchable that matches either the lhs or the rhs. For example:

LOAD_CONST | LOAD_FAST

will match a either a single LOAD_CONST or a LOAD_FAST.

not

Matchables may be negated to create a new matchable that matches anything the original did not match. For example:

~LOAD_CONST

will match any instruction except an instance of LOAD_CONST.

matchrange

It is possible to create a matchable from another such that it matches the same pattern repeated multiple times. For example:

LOAD_CONST[3]

will match exactly three LOAD_CONST instances in a row. This will not match on any less than three and will match on the first three if there are more than three LOAD_CONST instructions in a row.

This can be specified with an upper bound also like:

LOAD_CONST[3, 5]

This matches between three and five LOAD_CONST instructions. This is greedy meaning that if four or five LOAD_CONST instructions exist it will consume as many as possible up to five.

var

var is a modifier that matches zero or more instances of another matchable. For example:

LOAD_CONST[var]

will match as many LOAD_CONST instructions appear in a row or an empty instruction set.

plus

plus is a modifier that matches one or more instances of another matchable. For example:

LOAD_CONST[plus]

will match as many LOAD_CONST instructions appear in a row as long as there is at least one.

option

option is a modifier that matches zero or one instance of another matchable. For example:

LOAD_CONST[option]

will match either an empty instruction set or exactly one LOAD_CONST.

matchany

matchany is a special matchable that matches any single instruction. ... is an alias for matchany.

seq

seq is a matchable that matches a sequence of other matchables. For example:

seq(LOAD_CONST, ..., ~LOAD_CONST)

will match a single LOAD_CONST followed by any instruction followed by any instruction that is not a LOAD_CONST. This example show how we can compose all of our matchable together to build more complex matchables.

pattern

In order to use our DSL we need a way to register transformations to these matchables. To do this we may decorate methods of a CodeTransformer with pattern. This registers the function to the pattern. For example:

class MyTransformer(CodeTransformer):
    @pattern(LOAD_CONST, ..., ~LOAD_CONST)
    def _f(self, load_const, any, not_load_const):
        ...

The argument list of a pattern is implicitly made into a seq. When using MyTransformer to transform some bytecode _f will be called only when we see a LOAD_CONST followed by any instruction followed by any instruction that is not a LOAD_CONST. This function will be passed these three instruction objects positionally and should yield the instructions to replace them with.

Resolution Order

Patterns are checked in the order they are defined in the class body. This is because some patterns may overlap with eachother. For example, given the two classes:

class OrderOne(CodeTransformer):
    @pattern(LOAD_CONST)
    def _load_const(self, instr):
        print('LOAD_CONST')
        yield instr

    @pattern(...)
    def _any(self, instr):
        print('...')
        yield instr


class OrderTwo(CodeTransformer):
    @pattern(...)
    def _any(self, instr):
        print('...')
        yield instr

    @pattern(LOAD_CONST)
    def _load_const(self, instr):
        print('LOAD_CONST')
        yield instr

and the following bytecode sequence:

LOAD_CONST POP_TOP LOAD_CONST RETURN_VALUE

When running with OrderOne we would see:

LOAD_CONST
...
LOAD_CONST
...

but when running with OrderTwo:

...
...
...
...

This is because we will always match on the ... pattern where OrderOne will check against LOAD_CONST before falling back to the matchany.

Contextual Patterns

Sometimes a pattern should only be matched given that some condition has been met. An example of this is that you want to modify comprehensions. In order to be sure that you are only modifying the bodies of the comprehensions we must only match when we know we are in one. pattern accepts a keyword only argument startcodes which is a set of contexts where this pattern should apply. By default this is DEFAULT_STARTCODE which is the default state. A startcode may be anything hashable; however it is best to use strings or integer constants to make it easy to debug.

The begin() method enters a new startcode. For example:

class FindDictComprehensions(CodeTransformer):
    @pattern(BUILD_MAP, matchany[var], MAP_ADD)
    def _start_comprehension(self, *instrs):
        print('starting dict comprehension')
        self.begin('in_comprehension')
        yield from instrs

    @pattern(RETURN_VALUE, startcodes=('in_comprehension',))
    def _return_from_comprehension(self, instr):
        print('returning from comprehension')
        yield instr

    @pattern(RETURN_VALUE)
    def _return_default(self, instr):
        print('returning from non-comprehension')
        yield instr

This transformer will find dictionary comprehensions and enter a new startcode. Inside this startcode we will handle RETURN_VALUE instructions differently.

>>> @FindDictComprehensions()
... def f():
...     pass
...
returning from non-comprehension

>>> @FindDictComprehensions()
... def g():
...     {a: b for a, b in it}
...
starting dict comprehension
returning from comprehension
returning from non-comprehension

It is important to remember that when we recurse into a nested code object (like a comprehension) that we do not inherit the startcode from our parent. Instead it always starts at DEFAULT_STARTCODE.

Interactive Conveniences

When developing projects using codetransformer, it’s often helpful to be able to quickly and easily visualize the AST and/or disassembly generated by CPython for a given source text.

The codetransformer.utils.pretty module provides utilities for viewing AST trees and the disassembly of nested code objects:

a(text[, mode, indent, file]) Interactive convenience for displaying the AST of a code string.
d(obj[, mode, file]) Interactive convenience for displaying the disassembly of a function, module, or code string.
display(text[, mode, file]) Show text, rendered as AST and as Bytecode.
extract_code(obj, compile_mode) Generic function for converting objects into instances of CodeType.

For users of IPython, codetransformer provides an IPython extension that adds %%ast and %%dis magics.

 In [1]: %load_ext codetransformer
 In [2]: %%dis
    ...: def foo(a, b):
    ...:     return a + b
    ...:
 <module>
 --------
   1           0 LOAD_CONST               0 (<code object foo at 0x7f4c428a9b70, file "<show>", line 1>)
               3 LOAD_CONST               1 ('foo')
               6 MAKE_FUNCTION            0
               9 STORE_NAME               0 (foo)
              12 LOAD_CONST               2 (None)
              15 RETURN_VAL

 <module>.foo
 ------------
   2           0 LOAD_FAST                0 (a)
               3 LOAD_FAST                1 (b)
               6 BINARY_ADD
               7 RETURN_VAL


In [3]: %%ast
    ...: def foo(a, b):
    ...:     return a + b
    ...:
 Module(
   body=[
     FunctionDef(
       name='foo',
       args=arguments(
         args=[
           arg(
             arg='a',
             annotation=None,
           ),
           arg(
             arg='b',
             annotation=None,
           ),
         ],
         vararg=None,
         kwonlyargs=[],
         kw_defaults=[],
         kwarg=None,
         defaults=[],
       ),
       body=[
         Return(
           value=BinOp(
             left=Name(id='a', ctx=Load()),
             op=Add(),
             right=Name(id='b', ctx=Load()),
           ),
         ),
       ],
       decorator_list=[],
       returns=None,
     ),
   ],
 )

API Reference

codetransformer.transformers

class codetransformer.transformers.asconstants(*builtin_names, **kwargs)[source]

A code transformer that inlines names as constants.

  • Positional arguments are interpreted as names of builtins (e.g. len, print) to freeze as constants in the decorated function’s namespace.
  • Keyword arguments provide additional custom names to freeze as constants.
  • If invoked with no positional or keyword arguments, asconstants inlines all names in builtins.
Parameters:
  • *builtin_names – Names of builtins to freeze as constants.
  • **kwargs – Additional key-value pairs to bind as constants.

Examples

Freezing Builtins:

>>> from codetransformer.transformers import asconstants
>>>
>>> @asconstants('len')
... def with_asconstants(x):
...     return len(x) * 2
...
>>> def without_asconstants(x):
...     return len(x) * 2
...
>>> len = lambda x: 0
>>> with_asconstants([1, 2, 3])
6
>>> without_asconstants([1, 2, 3])
0

Adding Custom Constants:

>>> @asconstants(a=1)
... def f():
...     return a
...
>>> f()
1
>>> a = 5
>>> f()
1
class codetransformer.transformers.interpolated_strings(*, transform_bytes=True, transform_str=False)[source]

A transformer that interpolates local variables into string literals.

Parameters:
  • transform_bytes (bool, optional) – Whether to transform bytes literals to interpolated unicode strings. Default is True.
  • transform_str (bool, optional) – Whether to interpolate values into unicode strings. Default is False.

Example

>>> @interpolated_strings()  
... def foo(a, b):
...     c = a + b
...     return b"{a} + {b} = {c}"
...
>>> foo(1, 2)  
'1 + 2 = 3'
bytes_instrs

Yield instructions to call TOS.decode(‘utf-8’).format(**locals()).

str_instrs

Yield instructions to call TOS.format(**locals()).

transform_stringlike(const)[source]

Yield instructions to process a str or bytes constant.

types

Tuple containing types transformed by this transformer.

class codetransformer.transformers.overloaded_complexes(xform)

Transformer that applies a callable to each complex constant in the transformed code object.

Parameters:xform (callable) – A callable to be applied to complex literals.

See also

codetransformer.transformers.literals.overloaded_strs

class codetransformer.transformers.overloaded_floats(xform)

Transformer that applies a callable to each float constant in the transformed code object.

Parameters:xform (callable) – A callable to be applied to float literals.

See also

codetransformer.transformers.literals.overloaded_strs

class codetransformer.transformers.overloaded_ints(xform)

Transformer that applies a callable to each int constant in the transformed code object.

Parameters:xform (callable) – A callable to be applied to int literals.

See also

codetransformer.transformers.literals.overloaded_strs

class codetransformer.transformers.overloaded_lists(xform)

A CodeTransformer for overloading BUILD_LIST instructions.

class codetransformer.transformers.overloaded_sets(xform)

A CodeTransformer for overloading BUILD_SET instructions.

class codetransformer.transformers.overloaded_slices(xform)

A CodeTransformer for overloading BUILD_SLICE instructions.

class codetransformer.transformers.overloaded_strs(xform)

A transformer that overloads string literals.

Rewrites all constants of the form:

"some string"

as:

xform("some string")
Parameters:xform (callable) – Function to call on all string literals in the transformer target.

Examples

>>> @overloaded_strs(lambda x: "ayy lmao ")
... def prepend_foo(s):
...     return "foo" + s
...
>>> prepend_foo("bar")
'ayy lmao bar'
class codetransformer.transformers.overloaded_tuples(xform)

A CodeTransformer for overloading BUILD_TUPLE instructions.

class codetransformer.transformers.pattern_matched_exceptions(matcher=<function match>)[source]

Allows usage of arbitrary expressions and matching functions in except blocks.

When an exception is raised in an except block in a function decorated with pattern_matched_exceptions, a matching function will be called with the block’s expression and the three values returned by sys.exc_info(). If the matching function returns True, we enter the corresponding except-block, otherwise we continue to the next block, or re-raise if there are no more blocks to check

Parameters:matcher (function, optional) –

A function accepting an expression and the values of sys.exc_info, returning True if the exception info “matches” the expression.

The default behavior is to emulate standard python when the match expression is a subtype of Exception, and to compare exc.type and exc.args when the match expression is an instance of Exception.

Example

>>> @pattern_matched_exceptions()
... def foo():
...     try:
...         raise ValueError('bar')
...     except ValueError('buzz'):
...         return 'buzz'
...     except ValueError('bar'):
...         return 'bar'
>>> foo()
'bar'
class codetransformer.transformers.precomputed_slices[source]

An optimizing transformer that precomputes and inlines slice literals.

Example

>>> from dis import dis
>>> def first_five(l):
...     return l[:5]
...
>>> dis(first_five)  
  2           0 LOAD_FAST                0 (l)
              3 LOAD_CONST               0 (None)
              6 LOAD_CONST               1 (5)
              9 BUILD_SLICE              2
             12 BINARY_SUBSCR
             13 RETURN_VALUE
>>> dis(precomputed_slices()(first_five))  
  2           0 LOAD_FAST                0 (l)
              3 LOAD_CONST               0 (slice(None, 5, None))
              6 BINARY_SUBSCR
              7 RETURN_VALUE
codetransformer.transformers.islice_literals[source]

Transformer that turns slice indexing into an islice object.

Examples

>>> from codetransformer.transformers.literals import islice_literals
>>> @islice_literals
... def f():
...     return map(str, (1, 2, 3, 4))[:2]
...
>>> f()
<itertools.islice at ...>
>>> tuple(f())
('1', '2')
codetransformer.transformers.bytearray_literals

A transformer that converts bytes literals to bytearray.

codetransformer.transformers.decimal_literals

A transformer that converts float literals to Decimal.

codetransformer.code

class codetransformer.code.Code(instrs, argnames=(), *, cellvars=(), freevars=(), name='<code>', filename='<code>', firstlineno=1, lnotab=None, flags=None)[source]

A higher abstraction over python’s CodeType.

See Include/code.h for more information.

Parameters:
  • instrs (iterable of Instruction) – A sequence of codetransformer Instruction objects.
  • argnames (iterable of str, optional) – The names of the arguments to the code object.
  • name (str, optional) – The name of this code object.
  • filename (str, optional) – The file that this code object came from.
  • firstlineno (int, optional) – The first line number of the code in this code object.
  • lnotab (dict[Instruction -> int], optional) – The mapping from instruction to the line that it starts.
  • flags (dict[str -> bool], optional) – Any flags to set. This updates the default flag set.
Variables:
argcount

The number of arguments this code object accepts.

This does not include varargs (*args).

argnames

The names of the arguments to this code object.

The format is: [args] [vararg] [kwonlyargs] [varkwarg] where each group is optional.

bytecode_offset(instr)[source]

Returns the offset of instr in the bytecode representation.

Parameters:instr (Instruction) – The instruction the check the index of.
Returns:idx – The index of instr in this code object in the sparse instructions.
Return type:int
cellvars

The names of the variables closed over by inner code objects.

constructs_new_locals

Does this code object construct new locals?

This is True for things like functions where executing the code needs a new locals dict each time; however, something like a module does not normally need new locals.

consts

The constants referenced in this code object.

dis(file=None)[source]

Print self via the stdlib dis module.

Parameters:file (file-like, optional) – A file-like object into which we should print. Defaults to sys.stdout.
filename

The filename of this code object.

firstlineno

The first source line from self.filename that this code object represents.

flags

The flags of this code object represented as a mapping from flag name to boolean status.

Notes

This is a copy of the underlying flags. Mutations will not affect the code object.

freevars

The names of the variables this code object has closed over.

classmethod from_pycode(co)[source]

Create a Code object from a python code object.

Parameters:co (CodeType) – The python code object.
Returns:code – The codetransformer Code object.
Return type:Code
classmethod from_pyfunc(f)[source]

Create a Code object from a python function object.

Parameters:f (function) – The function from which to construct a code object.
Returns:code – A Code object representing f.__code__.
Return type:Code
index(instr)[source]

Returns the index of instr.

Parameters:instr (Instruction) – The instruction the check the index of.
Returns:idx – The index of instr in this code object.
Return type:int
instrs

The instructions in this code object.

is_coroutine

Is this a coroutine defined with async def?

This is 3.5 and greater.

is_generator

Is this a generator?

is_iterable_coroutine

Is this an async generator defined with types.coroutine?

This is 3.5 and greater.

is_nested

Is this a nested code object?

kwonlyargcount

The number of keyword only arguments this code object accepts.

This does not include varkwargs (**kwargs).

lnotab

The mapping of line number to the first instruction on that line.

name

The name of this code object.

names

The names referenced in this code object.

Names come from instructions like LOAD_GLOBAL or STORE_ATTR where the name of the global or attribute is needed at runtime.

py_flags

The flags of this code object represented as a bitmask.

py_lnotab

The encoded lnotab that python uses to compute when lines start.

Note

See Objects/lnotab_notes.txt in the cpython source for more details.

sparse_instrs

The instructions where the index of an instruction is the bytecode offset of that instruction.

None indicates that no instruction is at that offset.

stacksize

The maximum amount of stack space used by this code object.

to_pycode()[source]

Create a python code object from the more abstract codetransfomer.Code object.

Returns:co – The python code object.
Return type:CodeType
varnames

The names of all of the local variables in this code object.

class codetransformer.code.Flag[source]

An enum describing the bitmask of flags that can be set on a code object.

CO_COROUTINE = <Flag.CO_COROUTINE: 128>
CO_FUTURE_ABSOLUTE_IMPORT = <Flag.CO_FUTURE_ABSOLUTE_IMPORT: 16384>
CO_FUTURE_BARRY_AS_BDFL = <Flag.CO_FUTURE_BARRY_AS_BDFL: 262144>
CO_FUTURE_DIVISION = <Flag.CO_FUTURE_DIVISION: 8192>
CO_FUTURE_GENERATOR_STOP = <Flag.CO_FUTURE_GENERATOR_STOP: 524288>
CO_FUTURE_PRINT_FUNCTION = <Flag.CO_FUTURE_PRINT_FUNCTION: 65536>
CO_FUTURE_UNICODE_LITERALS = <Flag.CO_FUTURE_UNICODE_LITERALS: 131072>
CO_FUTURE_WITH_STATEMENT = <Flag.CO_FUTURE_WITH_STATEMENT: 32768>
CO_GENERATOR = <Flag.CO_GENERATOR: 32>
CO_ITERABLE_COROUTINE = <Flag.CO_ITERABLE_COROUTINE: 256>
CO_NESTED = <Flag.CO_NESTED: 16>
CO_NEWLOCALS = <Flag.CO_NEWLOCALS: 2>
CO_NOFREE = <Flag.CO_NOFREE: 64>
CO_OPTIMIZED = <Flag.CO_OPTIMIZED: 1>
CO_VARARGS = <Flag.CO_VARARGS: 4>
CO_VARKEYWORDS = <Flag.CO_VARKEYWORDS: 8>
max = 1040895
classmethod pack(*, CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS, CO_NESTED, CO_GENERATOR, CO_NOFREE, CO_COROUTINE, CO_ITERABLE_COROUTINE, CO_FUTURE_DIVISION, CO_FUTURE_ABSOLUTE_IMPORT, CO_FUTURE_WITH_STATEMENT, CO_FUTURE_PRINT_FUNCTION, CO_FUTURE_UNICODE_LITERALS, CO_FUTURE_BARRY_AS_BDFL, CO_FUTURE_GENERATOR_STOP)[source]

Pack a flags into a bitmask.

I hope you like kwonly args.

Parameters:
  • CO_OPTIMIZED (bool) –
  • CO_NEWLOCALS (bool) –
  • CO_VARARGS (bool) –
  • CO_VARKEYWORDS (bool) –
  • CO_NESTED (bool) –
  • CO_GENERATOR (bool) –
  • CO_NOFREE (bool) –
  • CO_COROUTINE (bool) –
  • CO_ITERABLE_COROUTINE (bool) –
  • CO_FUTURE_DIVISION (bool) –
  • CO_FUTURE_ABSOLUTE_IMPORT (bool) –
  • CO_FUTURE_WITH_STATEMENT (bool) –
  • CO_FUTURE_PRINT_FUNCTION (bool) –
  • CO_FUTURE_UNICODE_LITERALS (bool) –
  • CO_FUTURE_BARRY_AS_BDFL (bool) –
  • CO_FUTURE_GENERATOR_STOP (bool) –
Returns:

mask

Return type:

int

classmethod unpack(mask)[source]

Unpack a bitmask into a map of flag to bool.

Parameters:mask (int) – A bitmask
Returns:mapping – The mapping of flag name to flag status.
Return type:OrderedDict[str -> bool]

codetransformer.core

class codetransformer.core.CodeTransformer[source]

A code object transformer, similar to the NodeTransformer from the ast module.

Variables:code
begin(startcode)[source]

Begin a new startcode.

Parameters:startcode (any) – The startcode to begin.
code

The code object we are currently manipulating.

context

Lookup the current transformation context.

Raises:NoContext – Raised when there is no active transformation context.
startcode

The startcode we are currently in.

transform(code, *, name=None, filename=None)[source]

Transform a codetransformer.Code object applying the transforms.

Parameters:
  • code (Code) – The code object to transform.
  • name (str, optional) – The new name for this code object.
  • filename (str, optional) – The new filename for this code object.
Returns:

new_code – The transformed code object.

Return type:

Code

transform_cellvars(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any
transform_consts(consts)[source]

transformer for the co_consts field.

Override this method to transform the co_consts of the code object.

Parameters:consts (tuple) – The co_consts
Returns:new_consts – The new constants.
Return type:tuple
transform_defaults(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any
transform_freevars(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any
transform_name(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any
transform_names(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any
transform_varnames(obj)

Identity function.

Parameters:obj (any) – The object to return
Returns:obj – The input unchanged
Return type:any

codetransformer.instructions

For details on particular instructions, see the dis stdlib module docs.

class codetransformer.instructions.Instruction(arg=no_default)[source]

Base class for all instruction types.

Parameters:arg (any, optional) – The argument for the instruction. This should be the actual value of the argument, for example, if this is a LOAD_CONST, use the constant value, not the index that would appear in the bytecode.
absjmp
equiv(instr)[source]

Check equivalence of instructions. This checks against the types and the arguments of the instructions

Parameters:instr (Instruction) – The instruction to check against.
Returns:is_equiv – If the instructions are equivalent.
Return type:bool

Notes

This is a separate concept from instruction identity. Two separate instructions can be equivalent without being the same exact instance. This means that two equivalent instructions can be at different points in the bytecode or be targeted by different jumps.

classmethod from_opcode(opcode, arg=no_default)[source]

Create an instruction from an opcode and raw argument.

Parameters:
  • opcode (int) – Opcode for the instruction to create.
  • arg (int, optional) – The argument for the instruction.
Returns:

intsr – An instance of the instruction named by opcode.

Return type:

Instruction

have_arg
opcode
opname
reljmp
stack_effect

The net effect of executing this instruction on the interpreter stack.

Instructions that pop values off the stack have negative stack effect equal to the number of popped values.

Instructions that push values onto the stack have positive stack effect equal to the number of popped values.

Examples

  • LOAD_{FAST,NAME,GLOBAL,DEREF} push one value onto the stack. They have a stack_effect of 1.
  • POP_JUMP_IF_{TRUE,FALSE} always pop one value off the stack. They have a stack effect of -1.
  • BINARY_* instructions pop two instructions off the stack, apply a binary operator, and push the resulting value onto the stack. They have a stack effect of -1 (-2 values consumed + 1 value pushed).
steal(instr)[source]

Steal the jump index off of instr.

This makes anything that would have jumped to instr jump to this Instruction instead.

Parameters:instr (Instruction) – The instruction to steal the jump sources from.
Returns:self – The instruction that owns this method.
Return type:Instruction

Notes

This mutates self and instr inplace.

class codetransformer.instructions.BEFORE_ASYNC_WITH(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 52
opname = 'BEFORE_ASYNC_WITH'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_ADD(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 23
opname = 'BINARY_ADD'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_AND(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 64
opname = 'BINARY_AND'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_FLOOR_DIVIDE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 26
opname = 'BINARY_FLOOR_DIVIDE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_LSHIFT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 62
opname = 'BINARY_LSHIFT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_MATRIX_MULTIPLY(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 16
opname = 'BINARY_MATRIX_MULTIPLY'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_MODULO(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 22
opname = 'BINARY_MODULO'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_MULTIPLY(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 20
opname = 'BINARY_MULTIPLY'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_OR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 66
opname = 'BINARY_OR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_POWER(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 19
opname = 'BINARY_POWER'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_RSHIFT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 63
opname = 'BINARY_RSHIFT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_SUBSCR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 25
opname = 'BINARY_SUBSCR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_SUBTRACT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 24
opname = 'BINARY_SUBTRACT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_TRUE_DIVIDE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 27
opname = 'BINARY_TRUE_DIVIDE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BINARY_XOR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 65
opname = 'BINARY_XOR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BREAK_LOOP(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 80
opname = 'BREAK_LOOP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_LIST(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 103
opname = 'BUILD_LIST'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_LIST_UNPACK(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 149
opname = 'BUILD_LIST_UNPACK'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_MAP(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 105
opname = 'BUILD_MAP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_MAP_UNPACK(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 150
opname = 'BUILD_MAP_UNPACK'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_MAP_UNPACK_WITH_CALL(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 151
opname = 'BUILD_MAP_UNPACK_WITH_CALL'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_SET(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 104
opname = 'BUILD_SET'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_SET_UNPACK(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 153
opname = 'BUILD_SET_UNPACK'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_SLICE(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 133
opname = 'BUILD_SLICE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_TUPLE(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 102
opname = 'BUILD_TUPLE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.BUILD_TUPLE_UNPACK(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 152
opname = 'BUILD_TUPLE_UNPACK'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.CALL_FUNCTION(packed=no_default, *, positional=0, keyword=0)
absjmp = False
have_arg = True
is_jmp = False
opcode = 131
opname = 'CALL_FUNCTION'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.CALL_FUNCTION_KW(packed=no_default, *, positional=0, keyword=0)
absjmp = False
have_arg = True
is_jmp = False
opcode = 141
opname = 'CALL_FUNCTION_KW'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.CALL_FUNCTION_VAR(packed=no_default, *, positional=0, keyword=0)
absjmp = False
have_arg = True
is_jmp = False
opcode = 140
opname = 'CALL_FUNCTION_VAR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.CALL_FUNCTION_VAR_KW(packed=no_default, *, positional=0, keyword=0)
absjmp = False
have_arg = True
is_jmp = False
opcode = 142
opname = 'CALL_FUNCTION_VAR_KW'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.COMPARE_OP(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 107
opname = 'COMPARE_OP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.CONTINUE_LOOP(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 119
opname = 'CONTINUE_LOOP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.DELETE_ATTR(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 96
opname = 'DELETE_ATTR'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.DELETE_DEREF(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 138
opname = 'DELETE_DEREF'
reljmp = False
uses_free = True
uses_name = False
uses_varname = False
vartype
class codetransformer.instructions.DELETE_FAST(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 126
opname = 'DELETE_FAST'
reljmp = False
uses_free = False
uses_name = False
uses_varname = True
class codetransformer.instructions.DELETE_GLOBAL(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 98
opname = 'DELETE_GLOBAL'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.DELETE_NAME(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 91
opname = 'DELETE_NAME'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.DELETE_SUBSCR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 61
opname = 'DELETE_SUBSCR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.DUP_TOP(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 4
opname = 'DUP_TOP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.DUP_TOP_TWO(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 5
opname = 'DUP_TOP_TWO'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.END_FINALLY(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 88
opname = 'END_FINALLY'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.EXTENDED_ARG(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 144
opname = 'EXTENDED_ARG'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.FOR_ITER(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 93
opname = 'FOR_ITER'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.GET_AITER(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 50
opname = 'GET_AITER'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.GET_ANEXT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 51
opname = 'GET_ANEXT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.GET_AWAITABLE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 73
opname = 'GET_AWAITABLE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.GET_ITER(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 68
opname = 'GET_ITER'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.GET_YIELD_FROM_ITER(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 69
opname = 'GET_YIELD_FROM_ITER'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.IMPORT_FROM(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 109
opname = 'IMPORT_FROM'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.IMPORT_NAME(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 108
opname = 'IMPORT_NAME'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.IMPORT_STAR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 84
opname = 'IMPORT_STAR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_ADD(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 55
opname = 'INPLACE_ADD'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_AND(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 77
opname = 'INPLACE_AND'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_FLOOR_DIVIDE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 28
opname = 'INPLACE_FLOOR_DIVIDE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_LSHIFT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 75
opname = 'INPLACE_LSHIFT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_MATRIX_MULTIPLY(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 17
opname = 'INPLACE_MATRIX_MULTIPLY'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_MODULO(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 59
opname = 'INPLACE_MODULO'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_MULTIPLY(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 57
opname = 'INPLACE_MULTIPLY'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_OR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 79
opname = 'INPLACE_OR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_POWER(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 67
opname = 'INPLACE_POWER'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_RSHIFT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 76
opname = 'INPLACE_RSHIFT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_SUBTRACT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 56
opname = 'INPLACE_SUBTRACT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_TRUE_DIVIDE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 29
opname = 'INPLACE_TRUE_DIVIDE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.INPLACE_XOR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 78
opname = 'INPLACE_XOR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.JUMP_ABSOLUTE(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 113
opname = 'JUMP_ABSOLUTE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.JUMP_FORWARD(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 110
opname = 'JUMP_FORWARD'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.JUMP_IF_FALSE_OR_POP(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 111
opname = 'JUMP_IF_FALSE_OR_POP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.JUMP_IF_TRUE_OR_POP(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 112
opname = 'JUMP_IF_TRUE_OR_POP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.LIST_APPEND(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 145
opname = 'LIST_APPEND'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.LOAD_ATTR(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 106
opname = 'LOAD_ATTR'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.LOAD_BUILD_CLASS(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 71
opname = 'LOAD_BUILD_CLASS'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.LOAD_CLASSDEREF(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 148
opname = 'LOAD_CLASSDEREF'
reljmp = False
uses_free = True
uses_name = False
uses_varname = False
vartype
class codetransformer.instructions.LOAD_CLOSURE(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 135
opname = 'LOAD_CLOSURE'
reljmp = False
uses_free = True
uses_name = False
uses_varname = False
vartype
class codetransformer.instructions.LOAD_CONST(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 100
opname = 'LOAD_CONST'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.LOAD_DEREF(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 136
opname = 'LOAD_DEREF'
reljmp = False
uses_free = True
uses_name = False
uses_varname = False
vartype
class codetransformer.instructions.LOAD_FAST(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 124
opname = 'LOAD_FAST'
reljmp = False
uses_free = False
uses_name = False
uses_varname = True
class codetransformer.instructions.LOAD_GLOBAL(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 116
opname = 'LOAD_GLOBAL'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.LOAD_NAME(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 101
opname = 'LOAD_NAME'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.MAKE_CLOSURE(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 134
opname = 'MAKE_CLOSURE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.MAKE_FUNCTION(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 132
opname = 'MAKE_FUNCTION'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.MAP_ADD(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 147
opname = 'MAP_ADD'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.NOP(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 9
opname = 'NOP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.POP_BLOCK(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 87
opname = 'POP_BLOCK'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.POP_EXCEPT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 89
opname = 'POP_EXCEPT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.POP_JUMP_IF_FALSE(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 114
opname = 'POP_JUMP_IF_FALSE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.POP_JUMP_IF_TRUE(arg=no_default)
absjmp = True
have_arg = True
is_jmp = True
opcode = 115
opname = 'POP_JUMP_IF_TRUE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.POP_TOP(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 1
opname = 'POP_TOP'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.PRINT_EXPR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 70
opname = 'PRINT_EXPR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.RAISE_VARARGS(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 130
opname = 'RAISE_VARARGS'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.RETURN_VALUE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 83
opname = 'RETURN_VALUE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.ROT_THREE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 3
opname = 'ROT_THREE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.ROT_TWO(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 2
opname = 'ROT_TWO'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SETUP_ASYNC_WITH(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 154
opname = 'SETUP_ASYNC_WITH'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SETUP_EXCEPT(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 121
opname = 'SETUP_EXCEPT'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SETUP_FINALLY(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 122
opname = 'SETUP_FINALLY'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SETUP_LOOP(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 120
opname = 'SETUP_LOOP'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SETUP_WITH(arg=no_default)
absjmp = False
have_arg = True
is_jmp = True
opcode = 143
opname = 'SETUP_WITH'
reljmp = True
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.SET_ADD(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 146
opname = 'SET_ADD'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.STORE_ATTR(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 95
opname = 'STORE_ATTR'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.STORE_DEREF(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 137
opname = 'STORE_DEREF'
reljmp = False
uses_free = True
uses_name = False
uses_varname = False
vartype
class codetransformer.instructions.STORE_FAST(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 125
opname = 'STORE_FAST'
reljmp = False
uses_free = False
uses_name = False
uses_varname = True
class codetransformer.instructions.STORE_GLOBAL(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 97
opname = 'STORE_GLOBAL'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.STORE_NAME(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 90
opname = 'STORE_NAME'
reljmp = False
uses_free = False
uses_name = True
uses_varname = False
class codetransformer.instructions.STORE_SUBSCR(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 60
opname = 'STORE_SUBSCR'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNARY_INVERT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 15
opname = 'UNARY_INVERT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNARY_NEGATIVE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 11
opname = 'UNARY_NEGATIVE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNARY_NOT(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 12
opname = 'UNARY_NOT'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNARY_POSITIVE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 10
opname = 'UNARY_POSITIVE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNPACK_EX(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 94
opname = 'UNPACK_EX'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.UNPACK_SEQUENCE(arg=no_default)
absjmp = False
have_arg = True
is_jmp = False
opcode = 92
opname = 'UNPACK_SEQUENCE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.WITH_CLEANUP_FINISH(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 82
opname = 'WITH_CLEANUP_FINISH'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.WITH_CLEANUP_START(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 81
opname = 'WITH_CLEANUP_START'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.YIELD_FROM(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 72
opname = 'YIELD_FROM'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False
class codetransformer.instructions.YIELD_VALUE(arg=no_default)
absjmp = False
have_arg = False
is_jmp = False
opcode = 86
opname = 'YIELD_VALUE'
reljmp = False
uses_free = False
uses_name = False
uses_varname = False

codetransformer.patterns

class codetransformer.patterns.pattern(*matchables, startcodes=(0, ))[source]

A pattern of instructions that can be matched against.

This class is intended to be used as a decorator on methods of CodeTransformer subclasses. It is used to mark that a given method should be called on sequences of instructions that match the pattern described by the inputs.

Parameters:
  • *matchables (iterable of matchable) – The type of instructions to match against.
  • startcodes (container of any) – The startcodes where this pattern should be tried.

Examples

Match a single BINARY_ADD instruction:

pattern(BINARY_ADD)

Match a single BINARY_ADD followed by a RETURN_VALUE:

pattern(BINARY_ADD, RETURN_VALUE)

Match a single BINARY_ADD followed by any other single instruction:

pattern(BINARY_ADD, matchany)

Match a single BINARY_ADD followed by any number of instructions:

pattern(BINARY_ADD, matchany[var])
codetransformer.patterns.DEFAULT_STARTCODE = 0

The default startcode for patterns.

DSL Objects

codetransformer.patterns.matchany = ...[source]

Matchable that matches any instruction.

class codetransformer.patterns.seq(*matchables)[source]

A sequence of matchables to match in order.

Parameters:*matchables (iterable of matchable) – The matchables to match against.
codetransformer.patterns.var = *[source]

Modifier that matches zero or more of a pattern.

codetransformer.patterns.plus = +[source]

Modifier that matches one or more of a pattern.

codetransformer.patterns.option = ?[source]

Modifier that matches zero or one of a pattern.

codetransformer.utils

codetransformer.utils.pretty

Utilities for pretty-printing ASTs and code objects.

codetransformer.utils.pretty.a(text, mode='exec', indent=' ', file=None)[source]

Interactive convenience for displaying the AST of a code string.

Writes a pretty-formatted AST-tree to file.

Parameters:
  • text (str) – Text of Python code to render as AST.
  • mode ({'exec', 'eval'}, optional) – Mode for ast.parse. Default is ‘exec’.
  • indent (str, optional) – String to use for indenting nested expressions. Default is two spaces.
  • file (None or file-like object, optional) – File to use to print output. If the default of None is passed, we use sys.stdout.
codetransformer.utils.pretty.d(obj, mode='exec', file=None)[source]

Interactive convenience for displaying the disassembly of a function, module, or code string.

Compiles text and recursively traverses the result looking for code objects to render with dis.dis.

Parameters:
  • obj (str, CodeType, or object with __code__ attribute) – Object to disassemble. If obj is an instance of CodeType, we use it unchanged. If obj is a string, we compile it with mode and then disassemble. Otherwise, we look for a __code__ attribute on obj.
  • mode ({'exec', 'eval'}, optional) – Mode for compile. Default is ‘exec’.
  • file (None or file-like object, optional) – File to use to print output. If the default of None is passed, we use sys.stdout.
codetransformer.utils.pretty.display(text, mode='exec', file=None)[source]

Show text, rendered as AST and as Bytecode.

Parameters:
  • text (str) – Text of Python code to render.
  • mode ({'exec', 'eval'}, optional) – Mode for ast.parse and compile. Default is ‘exec’.
  • file (None or file-like object, optional) – File to use to print output. If the default of None is passed, we use sys.stdout.
codetransformer.utils.pretty.pformat_ast(node, include_attributes=False, indent=' ')[source]

Pretty-format an AST tree element

Parameters:
  • node (ast.AST) – Top-level node to render.
  • include_attributes (bool, optional) – Whether to include node attributes. Default False.
  • indent (str, optional.) – Indentation string for nested expressions. Default is two spaces.
codetransformer.utils.pretty.pprint_ast(node, include_attributes=False, indent=' ', file=None)[source]

Pretty-print an AST tree.

Parameters:
  • node (ast.AST) – Top-level node to render.
  • include_attributes (bool, optional) – Whether to include node attributes. Default False.
  • indent (str, optional.) – Indentation string for nested expressions. Default is two spaces.
  • file (None or file-like object, optional) – File to use to print output. If the default of None is passed, we use sys.stdout.

codetransformer.utils.immutable

Utilities for creating and working with immutable objects.

class codetransformer.utils.immutable.immutable[source]

A base class for immutable objects.

class codetransformer.utils.immutable.lazyval(func)[source]

A memoizing property.

Parameters:func (callable) – The function used to compute the value of the descriptor.
class codetransformer.utils.immutable.immutableattr(attr)[source]

An immutable attribute of a class.

Parameters:attr (any) – The attribute.

codetransformer.utils.functional

Utilities for functional programming.

codetransformer.utils.functional.ffill(iterable)[source]

Forward fill non None values in some iterable.

Parameters:iterable (iterable) – The iterable to forward fill.
Yields:e (any) – The last non None value or None if there has not been a non None value.
codetransformer.utils.functional.flatten(seq, *, recurse_types=(<class 'tuple'>, <class 'list'>, <class 'set'>, <class 'frozenset'>))[source]

Convert a (possibly nested) iterator into a flattened iterator.

Parameters:
  • seq (iterable) – The sequence to flatten.
  • optional (recurse_types,) – Types to recursively flatten. Defaults to (tuple, list, set, frozenset).
  • list(flatten((1, (2, 3), ((4,), 5)))) (>>>) –
  • 2, 3, 4, 5] ([1,) –
  • list(flatten(["abc", "def"], recurse_types=(str,))) (>>>) –
  • 'b', 'c', 'd', 'e', 'f'] (['a',) –
codetransformer.utils.functional.is_a(type_)[source]

More curryable version of isinstance.

codetransformer.utils.functional.not_a(type_)[source]

More curryable version of not isinstance.

codetransformer.utils.functional.reverse_dict(d)[source]

Reverse a dictionary, replacing the keys and values.

Parameters:d (dict) – The dict to reverse.
Returns:rd – The dict with the keys and values flipped.
Return type:dict

Examples

>>> d = {'a': 1, 'b': 2, 'c': 3}
>>> e = reverse_dict(d)
>>> e == {1: 'a', 2: 'b', 3: 'c'}
True
codetransformer.utils.functional.scanl(f, n, ns)[source]

Reduce ns by f starting with n yielding each intermediate value.

tuple(scanl(f, n, ns))[-1] == reduce(f, ns, n)

Parameters:
  • f (callable) – A binary function.
  • n (any) – The starting value.
  • ns (iterable of any) – The iterable to scan over.
Yields:

p (any) – The value of reduce(f, ns[:idx]) where idx is the current index.

Examples

>>> import operator as op
>>> tuple(scanl(op.add, 0, (1, 2, 3, 4)))
(0, 1, 3, 6, 10)

codetransformer.decompiler

Indices and tables