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.
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), wherehandler(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(...)andpeer.store.fetch_attachment(...). - Transports — configure Bluetooth LE, LAN, AWDL, Wi-Fi Aware, and WebSocket via
DittoConfig/ thetransport_configtypes (BluetoothLEConfig,DittoLanConfig,WifiAwareConfig, …). - Disk usage, logging, and typed errors —
DiskUsageObserver,DittoLogger/LogLevel, and theDitto*Errorhierarchy.
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-xdistis intentionally unsupported). - A Ditto handle must not cross a process fork. Use
multiprocessing.get_context("spawn")and open a freshDittoin each worker.
Resources
- 📖 Documentation
- 🔎 DQL Reference
- 🧭 Ditto Portal
- 📦 PyPI
License
Ditto is commercial software. See ditto.com for licensing.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl.
File metadata
- Download URL: dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl
- Upload date:
- Size: 21.0 MB
- Tags: Python 3, manylinux: glibc 2.35+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c61cd25a2a885fed4e39f46886ff7d8ee9260faaadec32a6cc99afd53a208c89
|
|
| MD5 |
be7b9eb903c2498978c4d9d6406541c5
|
|
| BLAKE2b-256 |
b39214f43d858947a5cdae2e74703e324d2b35123bd799c38fdbdc1130fb32df
|
Provenance
The following attestation bundles were made for dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl:
Publisher:
python-sdk-publish.yml on getditto/ditto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_x86_64.whl -
Subject digest:
c61cd25a2a885fed4e39f46886ff7d8ee9260faaadec32a6cc99afd53a208c89 - Sigstore transparency entry: 2458810782
- Sigstore integration time:
-
Permalink:
getditto/ditto@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/getditto
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-sdk-publish.yml@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl.
File metadata
- Download URL: dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl
- Upload date:
- Size: 20.8 MB
- Tags: Python 3, manylinux: glibc 2.35+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad0c881ca44394d2d695e6d8dc67b9581a9a7998841da669164d8512b5bf22fb
|
|
| MD5 |
a9387d04aa81b34be3154214d49e2db1
|
|
| BLAKE2b-256 |
14337774aed5a981a654a1d13dcef2ee35118ad05dec4bb07451deec16c9d06d
|
Provenance
The following attestation bundles were made for dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl:
Publisher:
python-sdk-publish.yml on getditto/ditto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dittolive_ditto-5.2.0.dev0-py3-none-manylinux_2_35_aarch64.whl -
Subject digest:
ad0c881ca44394d2d695e6d8dc67b9581a9a7998841da669164d8512b5bf22fb - Sigstore transparency entry: 2458810322
- Sigstore integration time:
-
Permalink:
getditto/ditto@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/getditto
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-sdk-publish.yml@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl.
File metadata
- Download URL: dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl
- Upload date:
- Size: 17.5 MB
- Tags: Python 3, macOS 12.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f783104fadf0034b7fe6bed999386491423ea0f33e1d2674e936b903ae604c56
|
|
| MD5 |
f699ea79b9c860d1ab3329fdfed9bf99
|
|
| BLAKE2b-256 |
a0b3270a159554fdc99ecf2509a926386cd23d7e760375718709ca4637f57597
|
Provenance
The following attestation bundles were made for dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl:
Publisher:
python-sdk-publish.yml on getditto/ditto
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dittolive_ditto-5.2.0.dev0-py3-none-macosx_12_0_arm64.whl -
Subject digest:
f783104fadf0034b7fe6bed999386491423ea0f33e1d2674e936b903ae604c56 - Sigstore transparency entry: 2458810621
- Sigstore integration time:
-
Permalink:
getditto/ditto@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/getditto
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-sdk-publish.yml@9fdc4a2396ac9c5e05e1b0721ef6568c3c2a4e45 -
Trigger Event:
workflow_dispatch
-
Statement type: