{"id":13570067,"url":"https://github.com/rocky/python-xdis","last_synced_at":"2025-05-14T16:05:46.511Z","repository":{"id":37406021,"uuid":"59214586","full_name":"rocky/python-xdis","owner":"rocky","description":"Python cross-version bytecode library and disassembler","archived":false,"fork":false,"pushed_at":"2025-01-31T20:09:28.000Z","size":8711,"stargazers_count":313,"open_issues_count":8,"forks_count":96,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-04-06T18:08:41.139Z","etag":null,"topics":["bytecode","cross-platform","disassembler","python-library"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rocky.png","metadata":{"files":{"readme":"README.rst","changelog":"ChangeLog-spell-corrected.diff","contributing":null,"funding":".github/FUNDING.yml","license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["rocky"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":"rocky","issuehunt":null,"otechie":null,"custom":null}},"created_at":"2016-05-19T14:34:09.000Z","updated_at":"2025-04-04T06:46:42.000Z","dependencies_parsed_at":"2023-10-14T18:36:34.201Z","dependency_job_id":"e1cbe63b-7d27-470a-909e-15f69ae822d5","html_url":"https://github.com/rocky/python-xdis","commit_stats":{"total_commits":1429,"total_committers":28,"mean_commits":"51.035714285714285","dds":0.2925122463261022,"last_synced_commit":"79f745f6ee181fce7dd91c2b2533c4f153f58225"},"previous_names":[],"tags_count":196,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rocky%2Fpython-xdis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rocky%2Fpython-xdis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rocky%2Fpython-xdis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rocky%2Fpython-xdis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rocky","download_url":"https://codeload.github.com/rocky/python-xdis/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248775189,"owners_count":21159565,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bytecode","cross-platform","disassembler","python-library"],"created_at":"2024-08-01T14:00:47.878Z","updated_at":"2025-04-13T20:19:00.246Z","avatar_url":"https://github.com/rocky.png","language":"Python","readme":"|CircleCI| |PyPI Installs| |Latest Version| |Supported Python Versions|\n\n|packagestatus|\n\nxdis\n====\n\nA Cross-Python bytecode disassembler, bytecode/wordcode and magic-number manipulation library/package.\n\n\n.. contents:: Table of Contents\n    :depth: 3\n\n\nIntroduction\n------------\n\nThe Python dis_ module allows you to disassemble bytecode from the same\nversion of Python that you are running on. But what about bytecode from\ndifferent versions?\n\nThat's what this package is for. It can \"marshal load\" Python\nbytecodes from different versions of Python. The command-line routine\n*pydisasm* will show disassembly output using the most modern Python\ndisassembly conventions in a variety of user-specified formats.  Some\nof these formats like ``extended`` and ``extended-format`` are the most\nadvanced of any Python disassembler I know of because they can show\nexpression-tree on operators. See the `Disassembler\nExample`_ below.\n\nAlso, if you need to modify and write bytecode, the routines here can\nbe of help. There are routines to pack and unpack the read-only tuples\nin Python's Code type. For interoperability between the changes over\nthe years to Python CodeType, provide our own versions of the Code\nType to allow interoperability, and we provide routines to reduce the\ntedium in writing a bytecode file.\n\nThis package also has an extensive knowledge of Python bytecode magic\nnumbers, including PyPy and others, and how to translate from\n``sys.sys_info`` major, minor, and release numbers to the corresponding\nmagic value.\n\nSo if you want to write a cross-version assembler, bytecode-level\nanalyzer, or optimizer this package may also be useful. In addition to\nthe kinds of instruction categorization that ``dis`` offers, we have\nadditional categories for things that would be useful in such a\nbytecode assembler, optimizer, or decompiler.\n\nThe programs here accept bytecodes from Python version 1.0 to\n3.13. The code requires Python 2.4 or later and has been tested on\nPython running lots of Python versions.\n\nWhen installing, except for the most recent versions of Python, use\nthe Python egg or wheel that matches that version, e.g. ``xdis-6.0.2-py3.3.egg``, ``xdis-6.0.2-py33-none-any.whl``.\nOf course for versions that pre-date wheel's, like Python 2.6, you will have to use eggs.\n\nTo install older versions for from source in git use the branch\n``python-2.4-to-2.7`` for Python versions from 2.4 to 2.7,\n``python-3.1-to-3.2`` for Python versions from 3.1 to 3.2,\n``python-3.3-to-3.5`` for Python versions from 3.3 to 3.5. The master\n``python-3.6-to-3.10`` for Python versions from 3.6 to 3.10 . The master\nbranch handles Python 3.11 and later.\n\nInstallation\n------------\n\nThe standard Python routine:\n\n::\n\n   $ pip install -e .  # or pip install -e .[dev] to include testing package\n\nA GNU makefile is also provided so ``make install`` (possibly as root or\nsudo) will do the steps above.\n\nDisassembler Example\n--------------------\n\nThe cross-version disassembler that is packaged here, can produce\nassembly listing that are superior to those typically found in\nPython's dis module. Here is an example::\n\n    pydisasm -S -F extended bytecode_3.8/pydisasm-example.pyc\n    # pydisasm version 6.1.1.dev0\n    # Python bytecode 3.8.0 (3413)\n    # Disassembled from Python 3.11.8 (main, Feb 14 2024, 04:47:01) [GCC 13.2.0]\n    # Timestamp in code: 1693155156 (2023-08-27 12:52:36)\n    # Source code size mod 2**32: 320 bytes\n    # Method Name:       \u003cmodule\u003e\n    # Filename:          simple_source/pydisasm-example.py\n    # Argument count:    0\n    # Position-only argument count: 0\n    # Keyword-only arguments: 0\n    # Number of locals:  0\n    # Stack size:        3\n    # Flags:             0x00000040 (NOFREE)\n    # First Line:        4\n    # Constants:\n    #    0: 0\n    #    1: None\n    #    2: ('version_info',)\n    #    3: 1\n    #    4: (2, 4)\n    #    5: 'Is small power of two'\n    # Names:\n    #    0: sys\n    #    1: version_info\n    #    2: print\n    #    3: version\n    #    4: len\n    #    5: major\n    #    6: power_of_two\n                 # import sys\n      4:           0 LOAD_CONST           (0) ; TOS = 0\n                   2 LOAD_CONST           (None) ; TOS = None\n                   4 IMPORT_NAME          (sys) ; TOS = import_module(sys)\n                   6 STORE_NAME           (sys) ; sys = import_module(sys)\n\n                 # from sys import version_info\n      5:           8 LOAD_CONST           (0) ; TOS = 0\n                  10 LOAD_CONST           (('version_info',)) ; TOS = ('version_info',)\n                  12 IMPORT_NAME          (sys) ; TOS = import_module(sys)\n                  14 IMPORT_FROM          (version_info) ; TOS = from sys import version_info\n                  16 STORE_NAME           (version_info) ; version_info = from sys import version_info\n                  18 POP_TOP\n\n                 # print(sys.version)\n      7:          20 LOAD_NAME            (print) ; TOS = print\n                  22 LOAD_NAME            (sys) ; TOS = sys\n                  24 LOAD_ATTR            (version) ; TOS = sys.version\n                  26 CALL_FUNCTION        (1 positional argument) ; TOS = print(sys.version)\n                  28 POP_TOP\n\n                 # print(len(version_info))\n      8:          30 LOAD_NAME            (print) ; TOS = print\n                  32 LOAD_NAME            (len) ; TOS = len\n                  34 LOAD_NAME            (version_info) ; TOS = version_info\n                  36 CALL_FUNCTION        (1 positional argument) ; TOS = len(version_info)\n                  38 CALL_FUNCTION        (1 positional argument) ; TOS = print(len(version_info))\n                  40 POP_TOP\n\n                 # major = sys.version_info[0]\n      9:          42 LOAD_NAME            (sys) ; TOS = sys\n                  44 LOAD_ATTR            (version_info) ; TOS = sys.version_info\n                  46 LOAD_CONST           (0) ; TOS = 0\n                  48 BINARY_SUBSCR        TOS = sys.version_info[0]\n                  50 STORE_NAME           (major) ; major = sys.version_info[0]\n\n                 # power_of_two = major \u0026 (major - 1)\n     10:          52 LOAD_NAME            (major) ; TOS = major\n                  54 LOAD_NAME            (major) ; TOS = major\n                  56 LOAD_CONST           (1) ; TOS = 1\n                  58 BINARY_SUBTRACT      TOS = major - (1)\n                  60 BINARY_AND           TOS = major \u0026 (major - (1))\n                  62 STORE_NAME           (power_of_two) ; power_of_two = major \u0026 (major - (1))\n\n                 # if power_of_two in (2, 4):\n     11:          64 LOAD_NAME            (power_of_two) ; TOS = power_of_two\n                  66 LOAD_CONST           ((2, 4)) ; TOS = (2, 4)\n                  68 COMPARE_OP           (in) ; TOS = power_of_two in ((2, 4))\n                  70 POP_JUMP_IF_FALSE    (to 80)\n\n                 # print(\"Is small power of two\")\n     12:          72 LOAD_NAME            (print) ; TOS = print\n                  74 LOAD_CONST           (\"Is small power of two\") ; TOS = \"Is small power of two\"\n                  76 CALL_FUNCTION        (1 positional argument) ; TOS = print(\"Is small power of two\")\n                  78 POP_TOP\n             \u003e\u003e   80 LOAD_CONST           (None) ; TOS = None\n                  82 RETURN_VALUE         return None\n\nNote in the above that some operand interpretation is done on items that are in the stack.\nFor example in ::\n\n              24 LOAD_ATTR            (version) | sys.version\n\nfrom the instruction see that ``sys.version`` is the resolved attribute that is loaded.\n\nSimilarly in::\n\n              68 COMPARE_OP           (in) | power_of_two in (2, 4)\n\nwe see that we can resolve the two arguments of the ``in`` operation.\nFinally in some ``CALL_FUNCTIONS`` we can figure out the name of the function and arguments passed to it.\n\n\n\nTesting\n-------\n\n::\n\n   $ make check\n\nA GNU makefile has been added to smooth over setting running the right\ncommand, and running tests from fastest to slowest.\n\nIf you have remake_ installed, you can see the list of all tasks\nincluding tests via ``remake --tasks``.\n\n\nUsage\n-----\n\nRun\n\n::\n\n     $ ./bin/pydisasm -h\n\nfor usage help.\n\n\nAs a drop-in replacement for dis\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n`xdis` also provides some support as a drop in replacement for the\nthe Python library `dis \u003chttps://docs.python.org/3/library/dis.html\u003e`_\nmodule. This is may be desirable when you want to use the improved API\nfrom Python 3.4 or later from an earlier Python version.\n\nFor example:\n\n\u003e\u003e\u003e # works in Python 2 and 3\n\u003e\u003e\u003e import xdis.std as dis\n\u003e\u003e\u003e [x.opname for x in dis.Bytecode('a = 10')]\n['LOAD_CONST', 'STORE_NAME', 'LOAD_CONST', 'RETURN_VALUE']\n\nThere may some small differences in output produced for formatted\ndisassembly or how we show compiler flags. We expect you'll\nfind the ``xdis`` output more informative though.\n\nSee Also\n--------\n\n* https://pypi.org/project/uncompyle6/ : Python Bytecode Deparsing\n* https://pypi.org/project/decompyle3/ : Python Bytecode Deparsing for Python 3.7 and 3.8\n* https://pypi.org/project/xasm/ : Python Bytecode Assembler\n* https://pypi.org/project/x-python/ : Python Bytecode Interpreter written in Python\n\n.. _trepan: https://pypi.python.org/pypi/trepan\n.. _debuggers: https://pypi.python.org/pypi/trepan3k\n.. _remake: http://bashdb.sf.net/remake\n.. |CircleCI| image:: https://circleci.com/gh/rocky/python-xdis.svg?style=svg\n    :target: https://circleci.com/gh/rocky/python-xdis\n.. |Supported Python Versions| image:: https://img.shields.io/pypi/pyversions/xdis.svg\n.. |Latest Version| image:: https://badge.fury.io/py/xdis.svg\n\t\t :target: https://badge.fury.io/py/xdis\n.. |PyPI Installs| image:: https://static.pepy.tech/badge/xdis\n.. |packagestatus| image:: https://repology.org/badge/vertical-allrepos/python:xdis.svg\n\t\t :target: https://repology.org/project/python:xdis/versions\n\t\t :alt: Packaging Status\n.. _dis: https://docs.python.org/3/library/dis.html\n","funding_links":["https://github.com/sponsors/rocky","https://liberapay.com/rocky"],"categories":["Bytecode"],"sub_categories":["Editors"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frocky%2Fpython-xdis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frocky%2Fpython-xdis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frocky%2Fpython-xdis/lists"}