Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Ditto Python SDK

An asyncio-native Python binding for Ditto — a cross-platform, peer-to-peer database that syncs data with and without internet connectivity. Install it, read and write with DQL, and Ditto automatically syncs changes to other devices over Bluetooth LE, P2P Wi-Fi, LAN, and the cloud.

The distribution is named dittolive-ditto; you import it as ditto.

Docs DQL PyPI Portal

Public Preview. This is an early preview release. The API may change before a stable release, and it is published as a pre-release — see Installation.

Installation

python3 -m pip install --pre dittolive-ditto

--pre is required while the SDK is in preview (the published versions are pre-releases such as 5.2.0.dev0). Requires Python 3.10+.

Published wheels are platform-specific and bundle the matching native library (libdittoffi) — there is nothing else to install or build.

Preview wheels are currently published for macOS on Apple Silicon and Linux on x86_64 and arm64 (manylinux_2_35 — glibc 2.35+); more platforms are on the way.

Getting Started

Ditto.open(...) is both awaitable and an async context manager. The context manager form closes the peer for you:

import asyncio
from ditto import Ditto, DittoConfig, DittoConfigConnect


async def main() -> None:
    config = DittoConfig(
        database_id="your-database-id",
        connect=DittoConfigConnect.small_peers_only(),
        persistence_directory="./ditto-data",
    )

    async with Ditto.open(config) as peer:
        await peer.store.execute(
            "INSERT INTO cars DOCUMENTS (:car)",
            {"car": {"_id": "car1", "make": "Tesla", "color": "red"}},
        )
        with await peer.store.execute("SELECT * FROM cars") as result:
            for item in result:
                print(item.value)


asyncio.run(main())

The equivalent explicit form (close() is async because shutdown may wait for native work):

peer = await Ditto.open(config)
try:
    ...
finally:
    await peer.close()

DittoConfigConnect.small_peers_only() runs fully offline / local + peer-to-peer. To sync through a Ditto server (Big Peer), use DittoConfigConnect.server(...) — see Sync and Connecting to a Ditto Server.

Store and Queries (DQL)

All reads and writes go through DQL, executed on peer.store. execute() is async and returns a QueryResult you iterate for document values. The snippets below run inside the async with Ditto.open(config) as peer: block from Getting Started; each result owns native resources, so wrap it in with await …: (as the read below does) when you keep it:

# Create / upsert
await peer.store.execute(
    "INSERT INTO cars DOCUMENTS (:car) ON ID CONFLICT DO UPDATE",
    {"car": {"_id": "car1", "make": "Tesla", "color": "red"}},
)

# Update
await peer.store.execute(
    "UPDATE cars SET color = :color WHERE _id = :id",
    {"color": "blue", "id": "car1"},
)

# Read
with await peer.store.execute("SELECT * FROM cars WHERE color = :color",
                              {"color": "blue"}) as result:
    cars = [item.value for item in result]

# Delete: writes a tombstone that propagates removal to peers
# (use EVICT instead to drop a document only from the local store)
await peer.store.execute("DELETE FROM cars WHERE _id = :id", {"id": "car1"})

Reactive Observers

Register an observer to be called with the current result set whenever documents matching a query change locally or arrive from a peer:

def on_change(result):
    for item in result:
        print("cars changed:", item.value)


observer = peer.store.register_observer("SELECT * FROM cars", on_change)
# ... later, to stop receiving updates (close() alone does not stop delivery):
observer.cancel()

The handler may be a sync or async function, and is delivered on the event loop that registered it.

Sync

Sync is off until you start it. peer.sync.start() brings up the transports; register_subscription(...) tells Ditto which documents to sync from other peers (the argument must be a SELECT query):

peer.sync.start()
subscription = peer.sync.register_subscription("SELECT * FROM cars")
# ... later:
subscription.cancel()

Syncing with other peers or a Ditto server requires a license. For offline / small-peers-only use you can set an offline token obtained from the Ditto Portal:

peer.set_offline_only_license_token("your-offline-license-token")

Connecting to a Ditto Server

Connecting through a server (DittoConfigConnect.server(...)) requires setting an authentication expiration handler before starting sync — otherwise sync.start() raises DittoExpirationHandlerMissingError:

from datetime import timedelta
from ditto import Ditto, DittoConfig, DittoConfigConnect

config = DittoConfig(
    database_id="your-database-id",
    connect=DittoConfigConnect.server("https://your-app.cloud.ditto.live"),
)

async with Ditto.open(config) as peer:
    def on_expiring(ditto: Ditto, remaining: timedelta) -> None:
        # Obtain a fresh token and call `ditto.auth.login(...)`.
        ...

    peer.auth.expiration_handler = on_expiring
    peer.sync.start()

Also Available

The SDK surfaces the rest of Ditto's v5 API through the same peer. All of these are importable from the top-level ditto package:

  • Presence — observe the live mesh with peer.presence.register_observer(handler), where handler(graph: PresenceGraph) is called on each change.
  • Transactions — group reads/writes with peer.store.transaction(...).
  • Attachments — store and fetch large binaries via peer.store.new_attachment(...) and peer.store.fetch_attachment(...).
  • Transports — configure Bluetooth LE, LAN, AWDL, Wi-Fi Aware, and WebSocket via DittoConfig / the transport_config types (BluetoothLEConfig, DittoLanConfig, WifiAwareConfig, …).
  • Disk usage, logging, and typed errorsDiskUsageObserver, DittoLogger / LogLevel, and the Ditto*Error hierarchy.

See the Ditto documentation for concepts (mesh networking, data handling, sync) and the DQL reference.

Native Library Discovery

Wheel installs need no configuration. If you are working from a source checkout instead, point the loader at a compatible libdittoffi with DITTOFFI_LIB_PATH (the file or a directory containing it) or DITTOFFI_SEARCH_PATH (platform-separated directories). Importing ditto never loads the native library; it loads on first use of a native API.

Concurrency and Resource Ownership

  • Native callbacks are delivered on the asyncio event loop that registered them; handlers may be sync or async.
  • Result and observer objects own native resources — close them promptly or use their context-manager support. Ditto.close() is async.
  • Ditto's native runtime and logger hold process-global state, so tests must run sequentially (pytest-xdist is intentionally unsupported).
  • A Ditto handle must not cross a process fork. Use multiprocessing.get_context("spawn") and open a fresh Ditto in each worker.

Resources

License

Ditto is commercial software. See ditto.com for licensing.

Release files for dittolive-ditto 5.2.0.dev0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for dittolive-ditto 5.2.0.dev0
File Interpreter ABI Platform
dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl Python 3 none Linux glibc 2.35+ x86-64 Details
dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl Python 3 none Linux glibc 2.35+ ARM64 Details
dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl Python 3 none macOS 12.0+ ARM64 Details

Total release size:59.2 MB

Release files / dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl

Download URL dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl
Size 21.0 MB
Tags Linux glibc 2.35+ x86-64 Python 3
SHA-256 checksum
How to use checksums
c61cd25a2a885fed4e39f46886ff7d8ee9260faaadec32a6cc99afd53a208c89
BLAKE2b-256 checksum
How to use checksums
b39214f43d858947a5cdae2e74703e324d2b35123bd799c38fdbdc1130fb32df
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.

Transparency log

Release files / dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl

Download URL dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl
Size 20.8 MB
Tags Linux glibc 2.35+ ARM64 Python 3
SHA-256 checksum
How to use checksums
ad0c881ca44394d2d695e6d8dc67b9581a9a7998841da669164d8512b5bf22fb
BLAKE2b-256 checksum
How to use checksums
14337774aed5a981a654a1d13dcef2ee35118ad05dec4bb07451deec16c9d06d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.

Transparency log

Release files / dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl

Download URL dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl
Size 17.5 MB
Tags Python 3 macOS 12.0+ ARM64
SHA-256 checksum
How to use checksums
f783104fadf0034b7fe6bed999386491423ea0f33e1d2674e936b903ae604c56
BLAKE2b-256 checksum
How to use checksums
a0b3270a159554fdc99ecf2509a926386cd23d7e760375718709ca4637f57597
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

5.2.0.dev0 This release

3 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page