Async-native Python library for interacting with Docker
Project description
🐳 aiowhales
The async Docker client for Python.
Talk to Docker the way Python was meant to — with async and await.
Built on aiohttp, aiowhales talks directly to the Docker Engine API over Unix sockets or TCP. No subprocess shells. No sync wrappers. No blocking threads. Just pure async Python.
async with AsyncDockerClient() as docker:
container = await docker.containers.run("python:3.13-slim", "echo hello!", detach=True)
async for line in docker.containers.logs(container.id):
print(line) # hello!
Why aiowhales?
| aiowhales | docker-py | subprocess | |
|---|---|---|---|
| Async native | ✅ | ❌ | ❌ |
| Direct API (no CLI) | ✅ | ✅ | ❌ |
| Typed models | ✅ | ❌ | ❌ |
Streaming (async for) |
✅ | ❌ | ❌ |
| Built-in test mocks | ✅ | ❌ | ❌ |
| Cross-platform | ✅ | ✅ | ✅ |
Install
pip install aiowhales
uv add aiowhales
Quick Start
import asyncio
from aiowhales import AsyncDockerClient
async def main():
async with AsyncDockerClient() as docker:
# Pull an image with streaming progress
async for progress in docker.images.pull("python:3.12-slim"):
print(progress.status)
# Run a container
container = await docker.containers.run(
"python:3.12-slim",
"python -c 'print(\"hello from aiowhales!\")'",
detach=True,
)
# Stream logs
await docker.containers.wait(container.id)
async for line in docker.containers.logs(container.id):
print(line)
# Clean up
await docker.containers.remove(container.id)
asyncio.run(main())
Features
🔌 Connecting
from aiowhales import AsyncDockerClient, from_env
# Unix socket (default on Linux/macOS)
async with AsyncDockerClient() as docker: ...
# TCP (default on Windows, or remote hosts)
async with AsyncDockerClient("tcp://192.168.1.100:2375") as docker: ...
# From DOCKER_HOST env var
docker = from_env()
📦 Containers
# List
containers = await docker.containers.list(all=True)
# Run
container = await docker.containers.run("nginx:latest", name="web", ports={"80/tcp": 8080})
# Lifecycle
await docker.containers.stop(container.id)
await docker.containers.start(container.id)
await docker.containers.restart(container.id)
# Inspect
info = await docker.containers.get(container.id)
print(info.status, info.image)
# Exec into a running container
result = await docker.containers.exec_run(container.id, ["ls", "-la"])
# Stream logs in real time
async for line in docker.containers.logs(container.id, follow=True):
print(line)
# Live resource stats
stats = await docker.containers.stats(container.id)
print(f"CPU: {stats.cpu_percent}% Memory: {stats.memory_usage}")
# Remove
await docker.containers.remove(container.id, force=True)
🖼️ Images
# List
images = await docker.images.list()
# Pull with progress
async for progress in docker.images.pull("ubuntu:latest"):
print(f"{progress.status} {progress.progress or ''}")
# Build from Dockerfile
async for output in docker.images.build(".", tags=["myapp:latest"]):
print(output.stream)
# Tag and push
await docker.images.tag("myapp:latest", "registry.example.com/myapp:v1")
async for progress in docker.images.push("registry.example.com/myapp:v1"):
print(progress.status)
# Remove
await docker.images.remove("myapp:latest")
💾 Volumes
volumes = await docker.volumes.list()
vol = await docker.volumes.create("my-data", labels={"env": "dev"})
await docker.volumes.remove("my-data")
pruned = await docker.volumes.prune()
🌐 Networks
networks = await docker.networks.list()
net = await docker.networks.create("my-net", driver="bridge")
await docker.networks.connect(net.id, container.id, aliases=["web"])
await docker.networks.disconnect(net.id, container.id)
await docker.networks.remove(net.id)
⚡ Exec
# Run a command inside a container
result = await docker.exec.run(container.id, ["echo", "hello"])
print(result.exit_code, result.output)
# Stream output
async for line in docker.exec.stream(container.id, ["tail", "-f", "/var/log/app.log"]):
print(line)
🎼 Compose
await docker.compose.up("./my-project", detach=True, build=True)
services = await docker.compose.ps("./my-project")
async for line in docker.compose.logs("./my-project", service="web", follow=True):
print(line)
await docker.compose.down("./my-project", volumes=True)
📡 Events
async for event in docker.events(filters={"type": ["container"]}):
print(f"{event.action} {event.actor_id}")
Testing
aiowhales ships with MockTransport — test your Docker code without a running daemon:
from aiowhales import AsyncDockerClient
from aiowhales.testing import MockTransport
transport = MockTransport()
transport.register("GET", "/containers/json", [
{"Id": "abc123", "Names": ["/myapp"], "State": "running",
"Image": "nginx", "Created": 0, "Labels": {}, "Ports": []}
])
async with AsyncDockerClient(transport=transport) as docker:
containers = await docker.containers.list()
assert containers[0].id == "abc123"
Models
All models are frozen dataclasses — immutable snapshots of Docker state:
| Model | What it represents |
|---|---|
Container |
Container state — id, name, status, image, ports, labels |
Image |
Image metadata — id, tags, size, created |
Volume |
Volume info — name, driver, mountpoint, labels |
Network |
Network info — id, name, driver, connected containers |
ContainerStats |
Live CPU / memory / network usage |
ExecResult |
Command result — exit code + output |
DockerEvent |
Engine event — action, type, actor, timestamp |
PullProgress / PushProgress |
Image transfer progress |
BuildOutput |
Build step output |
Platform Support
| Platform | Transport | Status |
|---|---|---|
| Linux | Unix socket | ✅ Fully supported |
| macOS | Unix socket | ✅ Fully supported |
| Windows | TCP (Docker Desktop) | ✅ Fully supported |
Requirements
- Python 3.11+
- aiohttp >= 3.9
- Docker Engine API v1.43+
License
Apache License 2.0 — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 aiowhales-0.1.1.tar.gz.
File metadata
- Download URL: aiowhales-0.1.1.tar.gz
- Upload date:
- Size: 122.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
45df2ac9e0dc33dc48980678588ebdb5dfb3e242eadadbe17ca0fd6c7248c596
|
|
| MD5 |
7acff13357772f8497b720b92b40c627
|
|
| BLAKE2b-256 |
ddb744a690ef9dd76f4de735dde312689313ab5486b9d1819bd8d822f3680a1f
|
Provenance
The following attestation bundles were made for aiowhales-0.1.1.tar.gz:
Publisher:
publish.yml on GuySharir/aiowhales
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiowhales-0.1.1.tar.gz -
Subject digest:
45df2ac9e0dc33dc48980678588ebdb5dfb3e242eadadbe17ca0fd6c7248c596 - Sigstore transparency entry: 1059382960
- Sigstore integration time:
-
Permalink:
GuySharir/aiowhales@ad66687dc906a2b4880cd01f454ece61e3bf8b50 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/GuySharir
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad66687dc906a2b4880cd01f454ece61e3bf8b50 -
Trigger Event:
release
-
Statement type:
File details
Details for the file aiowhales-0.1.1-py3-none-any.whl.
File metadata
- Download URL: aiowhales-0.1.1-py3-none-any.whl
- Upload date:
- Size: 27.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a4ef05a27baf4f27938f6d0100d5a6f60090115b5f365ca79324c1bc79c7cad1
|
|
| MD5 |
296308f35a77f64b6f8bee3ebf438dfc
|
|
| BLAKE2b-256 |
a07fe3ffd27ad9d403f6c67fe7e47f85120bd1278b4e22d41faa03b44a3ab28a
|
Provenance
The following attestation bundles were made for aiowhales-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on GuySharir/aiowhales
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
aiowhales-0.1.1-py3-none-any.whl -
Subject digest:
a4ef05a27baf4f27938f6d0100d5a6f60090115b5f365ca79324c1bc79c7cad1 - Sigstore transparency entry: 1059382971
- Sigstore integration time:
-
Permalink:
GuySharir/aiowhales@ad66687dc906a2b4880cd01f454ece61e3bf8b50 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/GuySharir
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@ad66687dc906a2b4880cd01f454ece61e3bf8b50 -
Trigger Event:
release
-
Statement type: