Intro#

python-code-data is a Python package which provides a way to convert a Python “code object” into data that can be introspected and changed. It provides a higher level API than manipulating code objects directly, but faithfully maintains the full semantics of the code object for Python 3.7-3.10.

  • Tested to make sure the CodeData object is isomorphic to the original code object on all installed modules and using generative testing with Hypothesis (using hypothesmith to generate Python code).

  • Decodes flags and bytecode into a human readable form.

  • Hashable, just like the original code object.

  • Provides a CLI to introspect Python objects from the command line, with colored pretty printing courtesy of Rich.

  • Able to encode to/from JSON faithfully

It is meant to be used by anyone trying to understand Python code to build some sort of compiler, for tools like Numba.

First install the package, alongside rich for pretty printing:

pip install python-code-data[rich]

Then try inspecting some code objects:

# 1. Install rich hooks for prettier printing
from rich import pretty
pretty.install()


# 2. Get a code object
def fn(x):
    y = x + 1
    return y


# 3. Convert it to a dataclass!
from code_data import CodeData

CodeData.from_code(fn.__code__)
CodeData(
    (
        (
            Instruction('LOAD_FAST', Varname('x'), line_number=8),
            Instruction(
                'LOAD_CONST',
                Constant(1, _index_override=1),
                line_number=8
            ),
            Instruction('BINARY_ADD', line_number=8),
            Instruction(
                'STORE_FAST',
                Varname('y', _index_override=1),
                line_number=8
            ),
            Instruction(
                'LOAD_FAST',
                Varname('y', _index_override=1),
                line_number=9
            ),
            Instruction('RETURN_VALUE', line_number=9)
        ),
    ),
    filename='/tmp/ipykernel_725/489739762.py',
    first_line_number=7,
    name='fn',
    stacksize=2,
    type=Function(Args(positional_or_keyword=('x',))),
    _additional_args=(Constant(None, _index_override=0),)
)