# docker_utils

Python API: `modelconverter.utils.docker_utils`

Docker plumbing behind the `modelconverter` commands.

Conversions do not run on the host but inside a per-platform image (`rvc2`, `rvc3`, `rvc4` or `hailo`), which carries the vendor
conversion tools. This module finds such an image locally, pulls it or builds it, describes the conversion container -- its
mounts, environment and resource limits -- as a Docker Compose configuration, and runs the requested command inside it.

## Functions

### check_docker

```python
def check_docker():
```

Check that Docker commands can be run from here.

Raises

 * `RuntimeError`: If this process already runs inside a container, or if Docker is not installed on this system.

### docker_bin

```python
def docker_bin() -> str:
```

Return the path of the `docker` executable.

Returns

 * `str`: The path `docker` was found at.

Raises

 * `RuntimeError`: If Docker is not installed on this system.

### docker_build

```python
def docker_build(platform: Literal['rvc2', 'rvc3', 'rvc4', 'hailo'], bare_tag: str, version: str | None = None, image: str | None = None) -> str:
```

Build the Docker image of the given platform.

Parameters

 * `platform` (`Literal['rvc2', 'rvc3', 'rvc4', 'hailo']`): Platform to build the image for.
 * `bare_tag` (`str`): Suffix of the image tag, appended to the tool version. `dev` additionally installs the test tooling into
   the image; for RVC4 any other tag first prepares a clean build environment with
   [prepare_build_environment](https://docs.luxonis.com/software-v3/ai-inference/conversion/rvc-conversion/offline/modelconverter/modelconverter-api-reference/utils/docker_utils.md).
 * `version` (`str | None`): Version of the underlying conversion tools. Defaults to the platform's default version.
 * `image` (`str | None`): Full name of the image to build. If it carries no tag, the `<version>-<bare_tag>` tag is appended.
   Defaults to `luxonis/modelconverter-<platform>`.

Returns

 * `str`: The name of the built image, including its tag.

Raises

 * `RuntimeError`: If the `docker build` invocation fails.

### docker_exec

```python
def docker_exec(platform: Literal['rvc2', 'rvc3', 'rvc4', 'hailo'], *args: str, bare_tag: str, use_gpu: bool, version: str | None = None, image: str | None = None, memory: int | None = None, cpus: float | None = None):
```

Run a command inside the given platform's container.

Creates the host directories mounted into the container, writes a temporary Compose file for it and runs the command with `docker
compose run`. The arguments are handed to the container's entrypoint as `argv` and never re-evaluated by a shell.

> **Note**
> This never returns: the host process exits with the container's return code.

Parameters

 * `platform` (`Literal['rvc2', 'rvc3', 'rvc4', 'hailo']`): Platform whose image the command runs in.
 * `*args` (`str`): The command and its arguments.
 * `bare_tag` (`str`): Suffix of the image tag, appended to the tool version, e.g. `latest` or `dev`.
 * `use_gpu` (`bool`): Whether to give the container the GPU. Only has an effect for the `hailo` platform.
 * `version` (`str | None`): Version of the underlying conversion tools. Defaults to the platform's default version.
 * `image` (`str | None`): Full name of the image to use. Defaults to the official image of the platform.
 * `memory` (`int | None`): Memory limit of the container in bytes. `None` sets no limit.
 * `cpus` (`float | None`): Number of CPU cores the container may use, possibly fractional. `None` sets no limit.

Raises

 * `SystemExit`: Always, carrying the container's return code.

### docker_user_namespace_mode

```python
def docker_user_namespace_mode() -> UserNamespaceMode:
```

Return how the active Docker daemon maps the container's root user onto the host.

 * `rootless`: the daemon itself runs as the invoking user, so container root is already that user.
 * `userns`: the daemon runs as root with user-namespace remapping, so container root is a subordinate uid that cannot even be
   chowned to the host user from inside the container.
 * `rootful`: container root is host root, so what the container writes has to be handed back to the invoking user.
 * `unknown`: the daemon could not be asked.

The answer cannot change within a run, so it is cached: this is a round-trip to the daemon on a path that would otherwise take it
once per generated compose config.

### download_snpe_archive

```python
def download_snpe_archive(version: str, dest: Path) -> Path:
```

Download the SNPE archive of the given version.

Parameters

 * `version` (`str`): Version of the Qualcomm AI Runtime (SNPE) to download.
 * `dest` (`Path`): Directory to place the archive in. Created if missing.

Returns

 * `Path`: Path to the archive. If it is already present, it is returned without downloading anything.

Raises

 * `RuntimeError`: If the download fails. The message explains how to download the archive manually.

### generate_compose_config

```python
def generate_compose_config(image: str, gpu: bool = False, memory: int | None = None, cpus: float | None = None, extra_environment: dict[str, str] | None = None) -> str:
```

Generate the Compose configuration of the conversion service.

The service mounts the modelconverter cache and the host's `./output` directory, forwards the bucket-storage credentials, and --
for a rootful daemon -- the host user's uid and gid, so that the container can hand the files it wrote back to the invoking user.

Parameters

 * `image` (`str`): Image the service runs. An image whose name ends in `-dev` additionally mounts the host's sources, tests and
   `pyproject.toml` over the ones baked into it.
 * `gpu` (`bool`): Whether to run the container with the `nvidia` runtime.
 * `memory` (`int | None`): Memory limit of the container in bytes. `None` sets no limit.
 * `cpus` (`float | None`): Number of CPU cores the container may use, possibly fractional. `None` sets no limit.
 * `extra_environment` (`dict[str, str] | None`): Additional environment variables for the container, merged over the defaults.

Returns

 * `str`: The Compose configuration as a YAML document.

### get_container_memory_available

```python
def get_container_memory_available() -> int:
```

Return the bytes of memory still available to this container.

That is its memory limit less the resident memory of every process running inside it, never less than zero.

### get_container_memory_limit

```python
def get_container_memory_limit() -> int:
```

Return the memory limit of the current container in bytes.

### get_docker_client_from_active_context

```python
def get_docker_client_from_active_context() -> docker.DockerClient:
```

Create a Docker client for the active Docker context.

The daemon endpoint is read from the context `docker context show` reports, so a non-default context (rootless, remote, Colima,
...) is honored instead of the environment defaults. TLS is enabled for a `tcp://` endpoint unless the context skips the
verification.

Returns

 * `docker.DockerClient`: A client talking to the active context's daemon.

### get_docker_image

```python
def get_docker_image(platform: Literal['rvc2', 'rvc3', 'rvc4', 'hailo'], bare_tag: str, version: str, image: str | None = None) -> str:
```

Return an image to run the given platform's conversion in.

A matching local image is used if there is one. Otherwise the candidate images are pulled from `ghcr.io`, and should that fail as
well, the image is built locally.

Parameters

 * `platform` (`Literal['rvc2', 'rvc3', 'rvc4', 'hailo']`): Platform the image is for.
 * `bare_tag` (`str`): Suffix of the image tag, appended to the tool version, e.g. `latest` or `dev`.
 * `version` (`str`): Version of the underlying conversion tools.
 * `image` (`str | None`): Full name of the image to use. If it carries no tag, the `<version>-<bare_tag>` tag is appended.
   Defaults to `luxonis/modelconverter-<platform>`.

Returns

 * `str`: The name of the image to run, including its tag.

### get_local_docker_image

```python
def get_local_docker_image(platform: Literal['rvc2', 'rvc3', 'rvc4', 'hailo'], bare_tag: str, version: str, image: str | None = None) -> str | None:
```

Return a matching image already present on the local daemon.

Both the bare candidate names and their `docker.io` and `ghcr.io` spellings are looked for among the local images.

Parameters

 * `platform` (`Literal['rvc2', 'rvc3', 'rvc4', 'hailo']`): Platform the image is for.
 * `bare_tag` (`str`): Suffix of the image tag, appended to the tool version, e.g. `latest` or `dev`.
 * `version` (`str`): Version of the underlying conversion tools.
 * `image` (`str | None`): Full name of the image to look for. If it carries no tag, the `<version>-<bare_tag>` tag is appended.
   Defaults to `luxonis/modelconverter-<platform>`.

Returns

 * `str | None`: The full name of the first matching local image, including its tag, or `None` if no candidate is available
   locally.

### prepare_build_environment

```python
def prepare_build_environment(platform: Literal['rvc2', 'rvc3', 'rvc4', 'hailo'], version: str) -> Path:
```

Prepare a directory the platform's image can be built from.

Downloads and extracts the modelconverter sources of the running version and puts the SNPE archive of `version` in place, either
by copying a locally available one or by downloading it.

Parameters

 * `platform` (`Literal['rvc2', 'rvc3', 'rvc4', 'hailo']`): Platform to prepare the build for. Only `rvc4` is supported.
 * `version` (`str`): Version of the conversion tools whose SNPE archive the build needs.

Returns

 * `Path`: Path to the extracted source tree to build the image from.

Raises

 * `NotImplementedError`: If `platform` is not `rvc4`.

### pull_image

```python
def pull_image(client: docker.DockerClient, image: str) -> str:
```

Pull an image, showing a progress bar for each of its layers.

The Docker SDK is used instead of a `docker pull` subprocess because the latter asks for login credentials interactively when the
image is private.

Parameters

 * `client` (`docker.DockerClient`): Docker client to pull with.
 * `image` (`str`): Image to pull, optionally including a tag.

Returns

 * `str`: The name of the pulled image.

Raises

 * `RuntimeError`: If the daemon reports an error while it pulls.

### rvc4_tag_version

```python
def rvc4_tag_version(version: str) -> str:
```

Remove the build component from a version string.

> **Example**
> ```pycon
>>> rvc4_tag_version("2.41.0.251128")
'2.41.0'
>>> rvc4_tag_version("2.41.0")
'2.41.0'
```

Parameters

 * `version` (`str`): Version string to strip, e.g. `2.41.0.251128`.

Returns

 * `str`: The version without its build component, e.g. `2.41.0`.

## Attributes

### UserNamespaceMode
