Architecture

How calimero-client-py is structured internally

Overview

calimero-client-py is a Python extension module built with PyO3 and Maturin. The Python API is a thin synchronous wrapper around an async Rust client — each method call spins up a Tokio runtime internally to drive async requests to completion before returning a result to Python.

1

Python layer

calimero/ package re-exports all types from the compiled Rust extension calimero_client_py.so.

2

PyO3 bindings

src/*.rs wraps every Rust type with a #[pyclass] and every function with #[pyfunction] for seamless Python interop.

3

Rust core

calimero_client crate provides the actual HTTP transport, auth, and serialization, shared with other Calimero tooling.

Module Structure

src/lib.rs
PyO3 module entry point. Registers all classes and functions.
src/client.rs
PyClient — wraps calimero_client::client::Client. All API methods: contexts, apps, blobs, identities, RPC.
src/connection.rs
PyConnectionInfo — wraps ConnectionInfo, exposes api_url, node_name, get(), detect_auth_mode().
src/auth.rs
PyAuthMode — "none" | "required" enum wrapper.
src/token.rs
PyJwtToken — JWT access/refresh token pair.
src/cache.rs
Token cache path utilities: get_token_cache_path(), get_token_cache_dir().
src/storage.rs
MeroboxFileStorage — disk-backed JWT token storage for the authenticator.
src/utils.rs
JSON → Python object conversion helpers used by all API wrappers.
calimero/__init__.py
Re-exports all types from calimero_client_py. This is the user-facing import surface.
calimero/cli.py
CLI entry point. Provides calimero-client-py shell command.
pyproject.toml
Maturin build config. Produces a source distribution (sdist). Requires Rust toolchain to build from source.
Cargo.toml
Rust crate manifest. Depends on calimero_client, pyo3, tokio.

Async Model

Python code calls synchronous methods — no async/await needed. Internally, each method creates or reuses a Tokio runtime (Runtime::block_on) that runs the async Rust future to completion before handing the result back to Python.

Why sync?

Simpler Python ergonomics

Python users benefit from straightforward synchronous calls without needing to manage event loops. The Rust layer handles all async complexity internally.

GIL

Thread safety

PyO3 acquires the GIL for all Python object creation (Python::with_gil). The async Rust work runs outside the GIL via block_on, allowing other threads to run during network I/O.

Authentication Flow

1

detect_auth_mode()

Call conn.detect_auth_mode() to probe the node. Returns AuthMode("none") for open nodes or AuthMode("required") for authenticated ones.

2

CliAuthenticator

When auth is required, the CliAuthenticator prompts the user in the terminal for credentials, obtains JWT tokens from the node, and stores them via MeroboxFileStorage.

3

Token cache

Tokens are cached at ~/.merobox/auth_cache/{node_name}-{hash}.json. Subsequent calls reuse cached tokens and refresh automatically before expiry.