> ## Documentation Index
> Fetch the complete documentation index at: https://number0-improve-contact.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Python

> Use iroh from Python via the iroh-ffi bindings.

| Platform | Architectures            |
| -------- | ------------------------ |
| macOS    | arm64, x86\_64           |
| Linux    | x86\_64, aarch64 (glibc) |
| Windows  | x86\_64                  |

* **API reference:** [Python API docs](https://n0-computer.github.io/iroh-ffi/python/)
* **Example app:** [hello-iroh-ffi](https://github.com/n0-computer/hello-iroh-ffi/tree/main/python), a console reader for the cross-platform dot demo
* **All languages:** [platform support matrix](/languages#platform-support)

The Python bindings to iroh are published as prebuilt wheels on [PyPI](https://pypi.org/project/iroh/) and shipped from [iroh-ffi](https://github.com/n0-computer/iroh-ffi). The bindings are generated by [uniffi-rs](https://github.com/mozilla/uniffi-rs), so every class, method, and enum carries a docstring you can introspect from a REPL.

## Install

```bash theme={null}
pip install iroh
```

Prebuilt wheels are published for:

* Linux: `x86_64` and `aarch64` (manylinux 2\_28)
* macOS: `arm64` and `x86_64`
* Windows: `amd64`

## Register your event loop

Before calling any other iroh API, hand your asyncio event loop to the bindings:

```python theme={null}
async def main():
    iroh.iroh_ffi.uniffi_set_event_loop(asyncio.get_running_loop())
    # ... the rest of your program
```

Here is why. iroh's Rust runtime runs on its own background threads. When an operation completes (a connection arrives, a stream read finishes), one of those threads schedules the wakeup back onto your Python event loop. A Rust thread has no running asyncio loop of its own, so the bindings cannot discover yours: `uniffi_set_event_loop` tells them which loop to use. Without it, the bindings fall back to `asyncio.get_running_loop()`, which raises `RuntimeError: no running event loop` when called from a Rust thread. In practice this surfaces as that exact error, or as an `await` that never completes.

The awkward name comes from [uniffi](https://github.com/mozilla/uniffi-rs), the tool that generates the bindings, which is also why it lives under `iroh.iroh_ffi` rather than on the `iroh` module itself.

Two rules of thumb:

1. Call it from inside a running coroutine, typically as the first line of the function you pass to `asyncio.run()`. It cannot go at module level, because `asyncio.get_running_loop()` only works while a loop is running.
2. Register once per event loop. If your program creates more than one loop (repeated `asyncio.run()` calls, or pytest-asyncio's per-test loops), register each new loop before using iroh on it. In a test suite, an autouse fixture handles this:

```python theme={null}
# conftest.py
import asyncio
import pytest
import iroh

@pytest.fixture(autouse=True)
async def _uniffi_event_loop():
    iroh.iroh_ffi.uniffi_set_event_loop(asyncio.get_running_loop())
    yield
```

## Hello, iroh

```python theme={null}
import asyncio
import iroh

ALPN = b"hello-iroh/0"

async def main():
    iroh.iroh_ffi.uniffi_set_event_loop(asyncio.get_running_loop())
    ep = await iroh.Endpoint.bind(
        iroh.EndpointOptions(preset=iroh.preset_n0(), alpns=[ALPN])
    )
    print("endpoint id:", ep.id())

asyncio.run(main())
```

This binds an endpoint with the `n0` preset, advertises a single ALPN, and prints the endpoint id once binding completes.

## A two-peer echo

The [main.py example](https://github.com/n0-computer/iroh-ffi/blob/main/python/main.py) in the iroh-ffi repo runs a sender/receiver pair over QUIC:

```bash theme={null}
# Terminal 1
python main.py serve

# Terminal 2: paste the ticket printed from Terminal 1
python main.py connect <ticket>
```

The client opens a bi-directional stream, sends `hello`, and prints what the other peer echoes back.

## Next steps

<Card title="Connect two endpoints" icon="rocket" href="/connect-two-endpoints" horizontal>
  Conceptual walkthrough of endpoints, tickets, and ALPNs. The code samples are Rust, but every API maps 1:1 to Python.
</Card>

<Card title="hello-iroh-ffi example app" icon="github" href="https://github.com/n0-computer/hello-iroh-ffi/tree/main/python" horizontal>
  A headless Python peer for the cross-platform dot demo. It speaks the same wire format as the Swift and Kotlin apps and prints received positions to the console.
</Card>

<Card title="Python API reference" icon="book" href="https://n0-computer.github.io/iroh-ffi/python/" horizontal>
  Full class, method, and enum reference generated from the uniffi-rs bindings.
</Card>

<Card title="iroh-ffi on GitHub" icon="github" href="https://github.com/n0-computer/iroh-ffi" horizontal>
  Source, examples, and issue tracker for the Python (and other-language) bindings.
</Card>
