{"id":15061749,"url":"https://github.com/multiformats/py-multiaddr","last_synced_at":"2025-10-04T21:31:34.254Z","repository":{"id":57443887,"uuid":"53168118","full_name":"multiformats/py-multiaddr","owner":"multiformats","description":"multiaddr implementation in Python","archived":true,"fork":false,"pushed_at":"2023-05-09T09:14:52.000Z","size":201,"stargazers_count":33,"open_issues_count":0,"forks_count":23,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-09-25T23:24:05.880Z","etag":null,"topics":["ipfs","libp2p","multiformats","network","python"],"latest_commit_sha":null,"homepage":"https://multiformats.io/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/multiformats.png","metadata":{"files":{"readme":"README.rst","changelog":"HISTORY.rst","contributing":"CONTRIBUTING.rst","funding":null,"license":"LICENSE-APACHE2","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-03-04T21:58:00.000Z","updated_at":"2024-05-30T10:38:49.000Z","dependencies_parsed_at":"2024-06-18T16:58:21.980Z","dependency_job_id":null,"html_url":"https://github.com/multiformats/py-multiaddr","commit_stats":{"total_commits":203,"total_committers":15,"mean_commits":"13.533333333333333","dds":0.5369458128078818,"last_synced_commit":"e6f8d1b0b5fcab67f10fbc743e7b5c5ed6ab5280"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fpy-multiaddr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fpy-multiaddr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fpy-multiaddr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/multiformats%2Fpy-multiaddr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/multiformats","download_url":"https://codeload.github.com/multiformats/py-multiaddr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219876787,"owners_count":16554787,"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":["ipfs","libp2p","multiformats","network","python"],"created_at":"2024-09-24T23:24:36.670Z","updated_at":"2025-10-04T21:31:34.235Z","avatar_url":"https://github.com/multiformats.png","language":"Python","readme":"py-multiaddr\n==========================\n\n.. image:: https://img.shields.io/pypi/v/multiaddr.svg\n        :target: https://pypi.python.org/pypi/multiaddr\n\n.. image:: https://github.com/multiformats/py-multiaddr/actions/workflows/ci.yml/badge.svg\n        :target: https://github.com/multiformats/py-multiaddr/actions\n\n.. image:: https://codecov.io/github/multiformats/py-multiaddr/coverage.svg?branch=master\n        :target: https://codecov.io/github/multiformats/py-multiaddr?branch=master\n\n.. image:: https://readthedocs.org/projects/multiaddr/badge/?version=latest\n        :target: https://readthedocs.org/projects/multiaddr/?badge=latest\n        :alt: Documentation Status\n..\n\n    multiaddr_ implementation in Python\n\n.. _multiaddr: https://github.com/multiformats/multiaddr\n\n..\n\n\n.. contents:: :local:\n\nInstallation\n============\n\n.. code-block:: bash\n\n    pip install multiaddr\n\nRequirements\n------------\n\n- Python 3.10+\n- trio (for async DNS resolution)\n\nUsage\n=====\n\nSimple\n------\n\n.. code-block:: python\n\n    from multiaddr import Multiaddr\n\n    # construct from a string\n    m1 = Multiaddr(\"/ip4/127.0.0.1/udp/1234\")\n\n    # construct from bytes\n    #m2 = Multiaddr(bytes_addr=m1.to_bytes()) # deprecated\n    m2 = Multiaddr(m1.to_bytes())\n\n    assert str(m1) == \"/ip4/127.0.0.1/udp/1234\"\n    assert str(m1) == str(m2)\n    assert m1.to_bytes() == m2.to_bytes()\n    assert m1 == m2\n    assert m2 == m1\n    assert not (m1 != m2)\n    assert not (m2 != m1)\n\n\nProtocols\n---------\n\n.. code-block:: python\n\n    from multiaddr import Multiaddr\n\n    m1 = Multiaddr(\"/ip4/127.0.0.1/udp/1234\")\n\n    # get the multiaddr protocol description objects\n    m1.protocols()\n    # [Protocol(code=4, name='ip4', size=32), Protocol(code=17, name='udp', size=16)]\n\n\nEn/decapsulate\n--------------\n\n.. code-block:: python\n\n    from multiaddr import Multiaddr\n\n    m1 = Multiaddr(\"/ip4/127.0.0.1/udp/1234\")\n    m1.encapsulate(Multiaddr(\"/sctp/5678\"))\n    # \u003cMultiaddr /ip4/127.0.0.1/udp/1234/sctp/5678\u003e\n    m1.decapsulate(Multiaddr(\"/udp\"))\n    # \u003cMultiaddr /ip4/127.0.0.1\u003e\n\n    # Decapsulate by protocol code\n    m2 = Multiaddr(\"/ip4/192.168.1.1/tcp/8080/udp/1234\")\n    m2.decapsulate_code(6)  # TCP protocol code\n    # \u003cMultiaddr /ip4/192.168.1.1\u003e\n\n    # Decapsulate multiple layers\n    m3 = Multiaddr(\"/ip4/10.0.0.1/tcp/443/tls/p2p/QmPeer\")\n    m3.decapsulate_code(6)  # Remove TCP and everything after\n    # \u003cMultiaddr /ip4/10.0.0.1\u003e\n\n\nTunneling\n---------\n\nMultiaddr allows expressing tunnels very nicely.\n\n\n.. code-block:: python\n\n    printer = Multiaddr(\"/ip4/192.168.0.13/tcp/80\")\n    proxy = Multiaddr(\"/ip4/10.20.30.40/tcp/443\")\n    printerOverProxy = proxy.encapsulate(printer)\n    print(printerOverProxy)\n    # /ip4/10.20.30.40/tcp/443/ip4/192.168.0.13/tcp/80\n\n    proxyAgain = printerOverProxy.decapsulate(printer)\n    print(proxyAgain)\n    # /ip4/10.20.30.40/tcp/443\n\nDNS Resolution\n--------------\n\nMultiaddr supports DNS-based address resolution using the DNSADDR protocol. This is particularly useful for resolving bootstrap node addresses and maintaining peer IDs during resolution.\n\n\n.. code-block:: python\n\n    from multiaddr import Multiaddr\n    import trio\n\n    # Basic DNS resolution\n    ma = Multiaddr(\"/dns/example.com\")\n    resolved = await ma.resolve()\n    print(resolved)\n    # [Multiaddr(\"/ip4/93.184.216.34\"), Multiaddr(\"/ip6/2606:2800:220:1:248:1893:25c8:1946\")]\n\n    # DNSADDR with peer ID (bootstrap node style)\n    ma_with_peer = Multiaddr(\"/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN\")\n    resolved_with_peer = await ma_with_peer.resolve()\n    print(resolved_with_peer)\n    # [Multiaddr(\"/ip4/147.75.83.83/tcp/4001/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN\")]\n\n    # DNS4 and DNS6 resolution (IPv4/IPv6 specific)\n    ma_dns4 = Multiaddr(\"/dns4/example.com/tcp/443\")\n    resolved_dns4 = await ma_dns4.resolve()\n    print(resolved_dns4)\n    # [Multiaddr(\"/ip4/93.184.216.34/tcp/443\")]\n\n    ma_dns6 = Multiaddr(\"/dns6/example.com/tcp/443\")\n    resolved_dns6 = await ma_dns6.resolve()\n    print(resolved_dns6)\n    # [Multiaddr(\"/ip6/2606:2800:220:1:248:1893:25c8:1946/tcp/443\")]\n\n    # Using the DNS resolver directly\n    from multiaddr.resolvers import DNSResolver\n    resolver = DNSResolver()\n    resolved = await resolver.resolve(ma)\n    print(resolved)\n    # [Multiaddr(\"/ip4/93.184.216.34\"), Multiaddr(\"/ip6/2606:2800:220:1:248:1893:25c8:1946\")]\n\n    # Peer ID preservation test\n    original_peer_id = ma_with_peer.get_peer_id()\n    print(f\"Original peer ID: {original_peer_id}\")\n    # Original peer ID: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN\n\n    for resolved_addr in resolved_with_peer:\n        preserved_peer_id = resolved_addr.get_peer_id()\n        print(f\"Resolved peer ID: {preserved_peer_id}\")\n        # Resolved peer ID: QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN\n\nFor comprehensive examples including bootstrap node resolution, protocol comparison, and py-libp2p integration, see the `DNS examples \u003chttps://github.com/multiformats/py-multiaddr/tree/master/examples/dns\u003e`_ in the examples directory.\n\nThin Waist Address Validation\n-----------------------------\n\nMultiaddr provides thin waist address validation functionality to process multiaddrs and expand wildcard addresses to all available network interfaces. This is particularly useful for server configuration, network discovery, and dynamic port management.\n\n\n.. code-block:: python\n\n    from multiaddr import Multiaddr\n    from multiaddr.utils import get_thin_waist_addresses, get_network_addrs\n\n    # Network interface discovery\n    ipv4_addrs = get_network_addrs(4)\n    print(f\"Available IPv4 addresses: {ipv4_addrs}\")\n    # Available IPv4 addresses: ['192.168.1.12', '10.152.168.99']\n\n    # Specific address (no expansion)\n    addr = Multiaddr(\"/ip4/192.168.1.100/tcp/8080\")\n    result = get_thin_waist_addresses(addr)\n    print(result)\n    # [\u003cMultiaddr /ip4/192.168.1.100/tcp/8080\u003e]\n\n    # IPv4 wildcard expansion\n    addr = Multiaddr(\"/ip4/0.0.0.0/tcp/8080\")\n    result = get_thin_waist_addresses(addr)\n    print(result)\n    # [\u003cMultiaddr /ip4/192.168.1.12/tcp/8080\u003e, \u003cMultiaddr /ip4/10.152.168.99/tcp/8080\u003e]\n\n    # IPv6 wildcard expansion\n    addr = Multiaddr(\"/ip6/::/tcp/8080\")\n    result = get_thin_waist_addresses(addr)\n    print(result)\n    # [\u003cMultiaddr /ip6/::1/tcp/8080\u003e, \u003cMultiaddr /ip6/fd9b:9eba:8224:1:41a1:8939:231a:b414/tcp/8080\u003e]\n\n    # Port override\n    addr = Multiaddr(\"/ip4/0.0.0.0/tcp/8080\")\n    result = get_thin_waist_addresses(addr, port=9000)\n    print(result)\n    # [\u003cMultiaddr /ip4/192.168.1.12/tcp/9000\u003e, \u003cMultiaddr /ip4/10.152.168.99/tcp/9000\u003e]\n\n    # UDP transport support\n    addr = Multiaddr(\"/ip4/0.0.0.0/udp/1234\")\n    result = get_thin_waist_addresses(addr)\n    print(result)\n    # [\u003cMultiaddr /ip4/192.168.1.12/udp/1234\u003e, \u003cMultiaddr /ip4/10.152.168.99/udp/1234\u003e]\n\n    # Server binding scenario\n    wildcard = Multiaddr(\"/ip4/0.0.0.0/tcp/8080\")\n    interfaces = get_thin_waist_addresses(wildcard)\n    print(\"Available interfaces for server binding:\")\n    for i, interface in enumerate(interfaces, 1):\n        print(f\"  {i}. {interface}\")\n    # Available interfaces for server binding:\n    #   1. /ip4/192.168.1.12/tcp/8080\n    #   2. /ip4/10.152.168.99/tcp/8080\n\nFor comprehensive examples including error handling, practical usage scenarios, and detailed network interface information, see the `thin waist examples \u003chttps://github.com/multiformats/py-multiaddr/tree/master/examples/thin_waist\u003e`_ in the examples directory.\n\nFeatures\n========\n\n- **Multiaddr Protocol Support**: Full support for the multiaddr specification\n- **DNS Resolution**: Async DNS and DNSADDR resolution with trio\n- **Thin Waist Validation**: Network interface discovery and wildcard expansion\n- **Protocol Support**: IPv4, IPv6, TCP, UDP, DNS, DNS4, DNS6, DNSADDR, p2p, p2p-circuit, onion, onion3, quic, tls, and more\n- **Type Safety**: Full type hints and mypy support\n- **Modern Python**: Python 3.10+ support with modern tooling\n\nMaintainers\n===========\n\nOriginal author: `@sbuss`_.\n\nCurrent maintainers: `@acul71`_, `@pacrob`_, `@manusheel`_.\n\nContribute\n==========\n\nContributions welcome. Please check out `the issues`_.\n\nCheck out our `contributing document`_ for more information on how we work, and about contributing in general.\nPlease be aware that all interactions related to multiformats are subject to the IPFS `Code of Conduct`_.\n\nDevelopment\n-----------\n\nFor development setup, see `py-multiaddr contributing`_.\n\n.. code-block:: bash\n\n    # Clone the repository\n    git clone https://github.com/multiformats/py-multiaddr.git\n    cd py-multiaddr\n\n    # Install in development mode\n    pip install -e \".[dev]\"\n\n    # Run the development workflow\n    make pr\n\nLicense\n=======\n\nDual-licensed:\n\n-  `MIT`_ © 2014 Steven Buss\n-  `Apache 2`_ © 2014 Steven Buss\n\n.. _the issues: https://github.com/multiformats/py-multiaddr/issues\n.. _contributing document: https://github.com/multiformats/multiformats/blob/master/contributing.md\n.. _py-multiaddr contributing: https://github.com/multiformats/py-multiaddr/blob/master/CONTRIBUTING.rst\n.. _Code of Conduct: https://github.com/ipfs/community/blob/master/code-of-conduct.md\n.. _standard-readme: https://github.com/RichardLitt/standard-readme\n.. _MIT: LICENSE-MIT\n.. _Apache 2: LICENSE-APACHE2\n.. _`@sbuss`: https://github.com/sbuss\n.. _`@acul71`: https://github.com/acul71\n.. _`@pacrob`: https://github.com/pacrob\n.. _`@manusheel`: https://github.com/manusheel\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiformats%2Fpy-multiaddr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmultiformats%2Fpy-multiaddr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmultiformats%2Fpy-multiaddr/lists"}