python-on-whales

repository·master·Indexed 20 days ago

https://github.com/gabrieldemarmiesse/python-on-whales

A Python client for Docker and compatible engines like Podman and Nerdctl. It provides a 1-to-1 mapping with the Docker CLI, turning commands into typed, object-oriented Python code. The library supports standard operations such as run, pull, build, and compose, and allows Docker objects to be used as context managers for automatic cleanup. It is thread-safe and subprocess-based, requiring the Docker or Podman CLI to be installed on the system.

Tokens
14.6K
Snippets
54
Records
77
Agent score
69%

What's inside python-on-whales

  1. Multithreading and multiprocessing with Python on Whales

    master

    Python on Whales is safe to use with multithreading and multiprocessing.

    Key technical details:

    • Subprocess-based: The library calls the Docker CLI via subprocess. It does not store intermediate state that would cause thread-safety issues.
    • Stateful Objects: Docker objects (like containers or images) store attributes (equivalent to docker inspect output) for user convenience, but the library's internal logic does not depend on these attributes. This means you can safely share these objects between threads or processes, or even pickle them.
    • Daemon Responsibility: The Docker daemon handles concurrency and conflicting requests (e.g., two threads trying to create a container with the same name).

    Warning: While the library is thread-safe, your application logic must account for the state of the Docker daemon. For example, if one thread prunes containers while another thread is attempting to read logs from a container that was just removed, the second thread will fail.

  2. Use Docker objects as context managers for automatic cleanup

    master

    Many Docker objects (like Volumes, Containers, etc.) can be used as Python context managers. When the execution leaves the with block, the object is automatically removed, even if an exception occurs.

    from python_on_whales import docker
    
    # The volume will be automatically removed after the block finishes
    with docker.volume.create("random_name") as some_volume:
        docker.run(
            "postgres:9.6",
            name="some-postgres",
            envs={"POSTGRES_PASSWORD": "mysecretpassword"},
            volumes=[(some_volume, "/var/lib/postgresql/data")],
            detach=True,
        )
        # Perform operations with the volume here
    
    # Volume is gone now
  3. Access generic resources via environment variables

    master

    When a container is assigned generic resources, Docker injects environment variables to inform the application which specific resources are available.

    • Single resource: The variable DOCKER_RESOURCE_<KIND> (uppercase) will contain the name of the resource (e.g., DOCKER_RESOURCE_HAMSTER=Robert).
    • Multiple resources: If a service requests multiple units of a kind, the variable will contain a comma-separated list of the names (e.g., DOCKER_RESOURCE_HAMSTER=Lucie,Annie,James).
  4. Choose between Docker-py and Python on Whales

    master

    Deciding which library to use depends on your requirements for abstraction level and dependencies:

    • Use Docker-py if you need to interact with the Docker Engine API directly for low-level operations, require high performance/speed, or want to avoid a dependency on the Docker CLI binary (~50MB).
    • Use Python on Whales if you want a high-level wrapper that provides a 1-to-1 mapping to the Docker CLI commands. This is ideal for writing CI logic in Python instead of Bash. It also provides access to features that are easier to implement via the CLI, such as docker.buildx.build(...) and docker.stack.deploy(...).
  5. Use Podman or Nerdctl instead of Docker

    master

    Python on Whales supports Docker-compatible clients like Podman and Nerdctl by allowing you to specify an arbitrary binary to execute commands.

    To use a different client, instantiate python_on_whales.DockerClient and pass the desired binary name as a list to the client_call argument.

    from python_on_whales import DockerClient
    
    # Using nerdctl
    nerdctl = DockerClient(client_call=["nerdctl"])
    nerdctl.pull("python:3.9")
    
    # Using podman
    podman = DockerClient(client_call=["podman"])
    podman.pull("hello-world")
    podman.run("hello-world")
    print(podman.ps())