Metadata-Version: 2.4
Name: compose2pod
Version: 0.3.1
Summary: Convert a Docker Compose file into a script that runs its services as a single Podman pod
Keywords: podman,docker-compose,compose,pod,ci,testing,containers
Author: Artur Shiriev
Author-email: Artur Shiriev <me@shiriev.ru>
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Typing :: Typed
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Testing
Requires-Dist: pyyaml>=6 ; extra == 'yaml'
Requires-Python: >=3.10, <4
Project-URL: Repository, https://github.com/modern-python/compose2pod
Project-URL: Issues, https://github.com/modern-python/compose2pod/issues
Project-URL: Changelog, https://github.com/modern-python/compose2pod/releases
Provides-Extra: yaml
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)"  srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/compose2pod/lockup-dark.svg">
    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/compose2pod/lockup-light.svg">
    <img alt="compose2pod" src="https://raw.githubusercontent.com/modern-python/.github/main/brand/projects/compose2pod/lockup.png" width="420">
  </picture>
</p>

[![PyPI version](https://img.shields.io/pypi/v/compose2pod.svg)](https://pypi.org/project/compose2pod/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/compose2pod.svg)](https://pypi.org/project/compose2pod/)
[![Downloads](https://static.pepy.tech/badge/compose2pod/month)](https://pepy.tech/projects/compose2pod)
[![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](https://github.com/modern-python/compose2pod/actions/workflows/ci.yml)
[![CI](https://github.com/modern-python/compose2pod/actions/workflows/ci.yml/badge.svg)](https://github.com/modern-python/compose2pod/actions/workflows/ci.yml)
[![License](https://img.shields.io/github/license/modern-python/compose2pod.svg)](https://github.com/modern-python/compose2pod/blob/main/LICENSE)
[![GitHub stars](https://img.shields.io/github/stars/modern-python/compose2pod)](https://github.com/modern-python/compose2pod/stargazers)
[![Context7](https://img.shields.io/badge/Context7-docs-blue)](https://context7.com/modern-python/compose2pod)
[![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv)
[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty)

Convert a Docker Compose file into a POSIX `sh` script that runs its services as a **single Podman pod**.

Built for CI and test environments where you can't use `docker compose` or `podman kube play`:

- **No bridge networking / netavark.** Unprivileged CI containers often have a read-only `/proc/sys`, so netavark fails to create bridge networks. A single pod shares one network namespace with no bridge: services talk over `127.0.0.1`, and names resolve via `--add-host`.
- **No systemd.** Podman healthchecks are normally scheduled by systemd timers. compose2pod gates startup by polling `podman healthcheck run` directly, so `depends_on: service_healthy` works without systemd.
- **No heavy runtime.** The core is stdlib-only — no dependencies, no compiled wheels — so it installs and runs in minimal Python images.

## Requirements

**Podman >= 6.0.0.** Earlier releases have a bug where a container stopping
inside a multi-container pod wipes `/etc/hosts` for every container in that
pod, not just the one that stopped — fixed in 6.0.0. compose2pod's generated
scripts rely on one shared `--add-host`-populated `/etc/hosts` for the whole
pod (see `architecture/supported-subset.md`), so a `service_completed_successfully`
dependency (a container that runs and exits, e.g. a migration step) can wipe
name resolution for everything started after it on a pre-6.0.0 Podman.

## Install

```bash
pip install compose2pod            # core: reads compose as JSON
pip install compose2pod[yaml]      # optional: read YAML directly (adds PyYAML)
```

## Usage

```bash
# YAML directly (needs the [yaml] extra)
compose2pod docker-compose.yml --target app --image myimage:ci > run.sh

# Or stay dependency-free by piping JSON (e.g. via yq)
yq -o=json '.' docker-compose.yml | compose2pod --target app --image myimage:ci > run.sh

sh ./run.sh
```

## Supported compose subset

compose2pod refuses **every document `docker compose config` refuses** — a
measured property, checked continuously by a differential conformance harness
that runs the real Docker CLI and the real compose2pod pipeline over the same
YAML. So a file that compiles is a file Docker would run; where compose2pod
still refuses a form Docker accepts, it is because Podman genuinely cannot
express it (each such case is documented, not guessed).

Within that boundary it covers most of what real compose files use:

- **Services** — `image`/`build`, `command`/`entrypoint`, `environment` and
  `env_file` (string and long-form `{path, required, format}`), `volumes`
  (short-form and long-form `--mount`, including the `bind`/`volume`/`tmpfs`
  option maps), `tmpfs`, `healthcheck`, `depends_on` (all conditions), network
  `aliases`, `hostname`/`container_name`.
- **Confinement & metadata** — `user`, `working_dir`, `read_only`, `init`,
  `privileged`, `cap_add`/`cap_drop`, `security_opt`, `devices`, `group_add`,
  `platform`, `labels`, `annotations`, `pull_policy` (the quoted-boolean and
  YAML-1.1 spellings Docker accepts, too).
- **Resources** — the legacy keys (`mem_limit`, `cpus`, `pids_limit`,
  `ulimits`, …) and the modern `deploy.resources` block.
- **Pod-wide** — `dns`/`dns_search`/`dns_opt`, `sysctls`, `extra_hosts`.
- **Composition** — same-file `extends`, `secrets`/`configs`, `profiles`.

Compose extension fields (any `x-`-prefixed key) and YAML anchors are accepted
as-is, so a top-level `x-*` anchor block for shared config just works.
`${VAR}`-style variable interpolation is left live in the generated script,
resolved by its shell against the environment present when the script runs (no
`.env` file support). See `architecture/supported-subset.md` for the full
accept/ignore/reject matrix and `planning/decisions/` for the boundary rulings.

## Status

Beta. Part of the [modern-python](https://github.com/modern-python) family. MIT licensed.
