{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "38e656cb",
   "metadata": {},
   "source": [
    "# Example: Modifying Existing Bytecode\n",
    "\n",
    "In this example, we will compile some code, modify the bytecode, and then turn it back into Python code to execute.\n",
    "\n",
    "We can make a code object from a string using `compile`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d6b5b0f9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "110\n"
     ]
    }
   ],
   "source": [
    "x = True\n",
    "source_code = \"print(10 + (100 if x else 10))\"\n",
    "code = compile(source_code, \"\", \"exec\")\n",
    "exec(code)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "85231cf0",
   "metadata": {},
   "source": [
    "If we look at the code object, we can see that it does have the bytecode, but its represented as byte string, which isn't very helpful:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "f2203180",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<code object <module> at 0x7f022741c500, file \"\", line 1>\n",
      "b'e\\x00d\\x00e\\x01r\\x06d\\x01n\\x01d\\x00\\x17\\x00\\x83\\x01\\x01\\x00d\\x02S\\x00'\n"
     ]
    }
   ],
   "source": [
    "print(code)\n",
    "print(code.co_code)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d19a9433",
   "metadata": {},
   "source": [
    "We could use Python's built in `dis` module to introspect the code object. This is helpful to look at it, but won't let us change it:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e10855a1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "  1           0 LOAD_NAME                0 (print)\n",
      "              2 LOAD_CONST               0 (10)\n",
      "              4 LOAD_NAME                1 (x)\n",
      "              6 POP_JUMP_IF_FALSE        6 (to 12)\n",
      "              8 LOAD_CONST               1 (100)\n",
      "             10 JUMP_FORWARD             1 (to 14)\n",
      "        >>   12 LOAD_CONST               0 (10)\n",
      "        >>   14 BINARY_ADD\n",
      "             16 CALL_FUNCTION            1\n",
      "             18 POP_TOP\n",
      "             20 LOAD_CONST               2 (None)\n",
      "             22 RETURN_VALUE\n"
     ]
    }
   ],
   "source": [
    "import dis\n",
    "dis.dis(code)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e15bccf",
   "metadata": {},
   "source": [
    "So instead, lets turn it into ✨data✨:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "30db19a3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "CodeData(blocks=((Instruction(name='LOAD_NAME', arg=Name(name='print', _index_override=0), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='LOAD_CONST', arg=Constant(constant=10, _index_override=0), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='LOAD_NAME', arg=Name(name='x', _index_override=1), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='POP_JUMP_IF_FALSE', arg=Jump(target=1, relative=False), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='LOAD_CONST', arg=Constant(constant=100, _index_override=1), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='JUMP_FORWARD', arg=Jump(target=2, relative=True), _n_args_override=None, line_number=1, _line_offsets_override=())), (Instruction(name='LOAD_CONST', arg=Constant(constant=10, _index_override=0), _n_args_override=None, line_number=1, _line_offsets_override=()),), (Instruction(name='BINARY_ADD', arg=NoArg(_arg=0), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='CALL_FUNCTION', arg=1, _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='POP_TOP', arg=NoArg(_arg=0), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='LOAD_CONST', arg=Constant(constant=None, _index_override=2), _n_args_override=None, line_number=1, _line_offsets_override=()), Instruction(name='RETURN_VALUE', arg=NoArg(_arg=0), _n_args_override=None, line_number=1, _line_offsets_override=()))), filename='', first_line_number=1, name='<module>', stacksize=3, type=None, freevars=(), future_annotations=False, _nested=False, _additional_line=None, _additional_args=())"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from code_data import CodeData\n",
    "\n",
    "code_data = CodeData.from_code(code)\n",
    "code_data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13b2e66b",
   "metadata": {},
   "source": [
    "This is still a bit hard to see, so let's install Rich's pretty print helper:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "b72ea861",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">\n",
       "<span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">CodeData</span><span style=\"font-weight: bold\">(</span>\n",
       "    <span style=\"font-weight: bold\">(</span>\n",
       "        <span style=\"font-weight: bold\">(</span>\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_NAME'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Name</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'print'</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_CONST'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Constant</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_NAME'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Name</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'x'</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'POP_JUMP_IF_FALSE'</span>, <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Jump</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_CONST'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Constant</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">100</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'JUMP_FORWARD'</span>, <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Jump</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span>, <span style=\"color: #808000; text-decoration-color: #808000\">relative</span>=<span style=\"color: #00ff00; text-decoration-color: #00ff00; font-style: italic\">True</span><span style=\"font-weight: bold\">)</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>\n",
       "        <span style=\"font-weight: bold\">)</span>,\n",
       "        <span style=\"font-weight: bold\">(</span>\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_CONST'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Constant</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">10</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">0</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "        <span style=\"font-weight: bold\">)</span>,\n",
       "        <span style=\"font-weight: bold\">(</span>\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'BINARY_ADD'</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'CALL_FUNCTION'</span>, <span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'POP_TOP'</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span>\n",
       "                <span style=\"color: #008000; text-decoration-color: #008000\">'LOAD_CONST'</span>,\n",
       "                <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Constant</span><span style=\"font-weight: bold\">(</span><span style=\"color: #800080; text-decoration-color: #800080; font-style: italic\">None</span>, <span style=\"color: #808000; text-decoration-color: #808000\">_index_override</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">2</span><span style=\"font-weight: bold\">)</span>,\n",
       "                <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>\n",
       "            <span style=\"font-weight: bold\">)</span>,\n",
       "            <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">Instruction</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'RETURN_VALUE'</span>, <span style=\"color: #808000; text-decoration-color: #808000\">line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span><span style=\"font-weight: bold\">)</span>\n",
       "        <span style=\"font-weight: bold\">)</span>\n",
       "    <span style=\"font-weight: bold\">)</span>,\n",
       "    <span style=\"color: #808000; text-decoration-color: #808000\">filename</span>=<span style=\"color: #008000; text-decoration-color: #008000\">''</span>,\n",
       "    <span style=\"color: #808000; text-decoration-color: #808000\">first_line_number</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">1</span>,\n",
       "    <span style=\"color: #808000; text-decoration-color: #808000\">name</span>=<span style=\"color: #008000; text-decoration-color: #008000\">'&lt;module&gt;'</span>,\n",
       "    <span style=\"color: #808000; text-decoration-color: #808000\">stacksize</span>=<span style=\"color: #008080; text-decoration-color: #008080; font-weight: bold\">3</span>\n",
       "<span style=\"font-weight: bold\">)</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\n",
       "\u001b[1mCodeData\u001b[0m\u001b[1m(\u001b[0m\n",
       "    \u001b[1m(\u001b[0m\n",
       "        \u001b[1m(\u001b[0m\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_NAME',\n",
       "                \u001b[1mName\u001b[0m\u001b[1m(\u001b[0m'print', _index_override=\u001b[1m0\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_CONST',\n",
       "                \u001b[1mConstant\u001b[0m\u001b[1m(\u001b[0m\u001b[1m10\u001b[0m, _index_override=\u001b[1m0\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_NAME',\n",
       "                \u001b[1mName\u001b[0m\u001b[1m(\u001b[0m'x', _index_override=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'POP_JUMP_IF_FALSE', \u001b[1mJump\u001b[0m\u001b[1m(\u001b[0m\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m, line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_CONST',\n",
       "                \u001b[1mConstant\u001b[0m\u001b[1m(\u001b[0m\u001b[1m100\u001b[0m, _index_override=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'JUMP_FORWARD', \u001b[1mJump\u001b[0m\u001b[1m(\u001b[0m\u001b[1m2\u001b[0m, relative=\u001b[3mTrue\u001b[0m\u001b[1m)\u001b[0m, line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m\n",
       "        \u001b[1m)\u001b[0m,\n",
       "        \u001b[1m(\u001b[0m\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_CONST',\n",
       "                \u001b[1mConstant\u001b[0m\u001b[1m(\u001b[0m\u001b[1m10\u001b[0m, _index_override=\u001b[1m0\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "        \u001b[1m)\u001b[0m,\n",
       "        \u001b[1m(\u001b[0m\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'BINARY_ADD', line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'CALL_FUNCTION', \u001b[1m1\u001b[0m, line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'POP_TOP', line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m\n",
       "                'LOAD_CONST',\n",
       "                \u001b[1mConstant\u001b[0m\u001b[1m(\u001b[0m\u001b[3mNone\u001b[0m, _index_override=\u001b[1m2\u001b[0m\u001b[1m)\u001b[0m,\n",
       "                line_number=\u001b[1m1\u001b[0m\n",
       "            \u001b[1m)\u001b[0m,\n",
       "            \u001b[1mInstruction\u001b[0m\u001b[1m(\u001b[0m'RETURN_VALUE', line_number=\u001b[1m1\u001b[0m\u001b[1m)\u001b[0m\n",
       "        \u001b[1m)\u001b[0m\n",
       "    \u001b[1m)\u001b[0m,\n",
       "    filename='',\n",
       "    first_line_number=\u001b[1m1\u001b[0m,\n",
       "    name='<module>',\n",
       "    stacksize=\u001b[1m3\u001b[0m\n",
       "\u001b[1m)\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from rich import pretty\n",
    "pretty.install()\n",
    "code_data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d607824",
   "metadata": {},
   "source": [
    "That's better!\n",
    "\n",
    "We can see now that we have two blocks, each with a list of instructions.\n",
    "\n",
    "Let's try to change the additions to subtractions!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "61834257",
   "metadata": {},
   "outputs": [],
   "source": [
    "from dataclasses import replace\n",
    "\n",
    "new_code_data = replace(\n",
    "    code_data,\n",
    "    blocks=tuple(tuple(\n",
    "        replace(instruction, name=\"BINARY_SUBTRACT\") if instruction.name == \"BINARY_ADD\" else instruction\n",
    "        for instruction in block\n",
    "    ) for block in code_data.blocks)\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6b291cb3",
   "metadata": {},
   "source": [
    "Now we can turn this back into code and exec it!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "c4270732",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "-90\n"
     ]
    }
   ],
   "source": [
    "new_code = new_code_data.to_code()\n",
    "exec(new_code)"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "cell_metadata_filter": "-all",
   "formats": "md:myst",
   "text_representation": {
    "extension": ".md",
    "format_name": "myst",
    "format_version": 0.13,
    "jupytext_version": "1.11.5"
   }
  },
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  },
  "source_map": [
   14,
   22,
   27,
   31,
   34,
   38,
   41,
   45,
   50,
   54,
   58,
   66,
   76,
   80
  ]
 },
 "nbformat": 4,
 "nbformat_minor": 5
}