compose2pod 0.4.2__tar.gz → 0.4.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {compose2pod-0.4.2 → compose2pod-0.4.3}/PKG-INFO +8 -7
- {compose2pod-0.4.2 → compose2pod-0.4.3}/README.md +4 -5
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/graph.py +1 -1
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/parsing.py +4 -6
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/values.py +1 -1
- compose2pod-0.4.3/pyproject.toml +113 -0
- compose2pod-0.4.2/pyproject.toml → compose2pod-0.4.3/pyproject.toml.orig +16 -11
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/__init__.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/__main__.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/cli.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/emit.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/exceptions.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/extends.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/healthcheck.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/keys.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/pod.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/py.typed +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/read.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/resources.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/shell.py +0 -0
- {compose2pod-0.4.2 → compose2pod-0.4.3}/compose2pod/stores.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: compose2pod
|
|
3
|
-
Version: 0.4.
|
|
3
|
+
Version: 0.4.3
|
|
4
4
|
Summary: Convert a Docker Compose file into a script that runs its services as a single Podman pod
|
|
5
|
-
Keywords: podman,docker-compose,
|
|
5
|
+
Keywords: podman,docker-compose,docker,containers,cli,python
|
|
6
6
|
Author: Artur Shiriev
|
|
7
7
|
Author-email: Artur Shiriev <me@shiriev.ru>
|
|
8
8
|
License-Expression: MIT
|
|
@@ -13,11 +13,13 @@ Classifier: Programming Language :: Python :: 3.11
|
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
16
17
|
Classifier: Typing :: Typed
|
|
17
18
|
Classifier: Topic :: Software Development :: Libraries
|
|
18
19
|
Classifier: Topic :: Software Development :: Testing
|
|
19
20
|
Requires-Dist: pyyaml>=6 ; extra == 'yaml'
|
|
20
21
|
Requires-Python: >=3.10, <4
|
|
22
|
+
Project-URL: Homepage, https://modern-python.org
|
|
21
23
|
Project-URL: Repository, https://github.com/modern-python/compose2pod
|
|
22
24
|
Project-URL: Issues, https://github.com/modern-python/compose2pod/issues
|
|
23
25
|
Project-URL: Changelog, https://github.com/modern-python/compose2pod/releases
|
|
@@ -55,9 +57,8 @@ Built for CI and test environments where you can't use `docker compose` or `podm
|
|
|
55
57
|
## Requirements
|
|
56
58
|
|
|
57
59
|
compose2pod's generated scripts own `/etc/hosts`: they write it to a temp
|
|
58
|
-
file and bind-mount it read-only into every container under `--no-hosts
|
|
59
|
-
|
|
60
|
-
works on any Podman version. `host.containers.internal` /
|
|
60
|
+
file and bind-mount it read-only into every container under `--no-hosts`, so
|
|
61
|
+
pod-internal name resolution works on any Podman version. `host.containers.internal` /
|
|
61
62
|
`host.docker.internal` are not provided — add an explicit `extra_hosts`
|
|
62
63
|
entry if you need them.
|
|
63
64
|
|
|
@@ -109,8 +110,8 @@ Compose extension fields (any `x-`-prefixed key) and YAML anchors are accepted
|
|
|
109
110
|
as-is, so a top-level `x-*` anchor block for shared config just works.
|
|
110
111
|
`${VAR}`-style variable interpolation is left live in the generated script,
|
|
111
112
|
resolved by its shell against the environment present when the script runs (no
|
|
112
|
-
`.env` file support).
|
|
113
|
-
|
|
113
|
+
`.env` file support). The boundary rulings — which forms are refused, and why —
|
|
114
|
+
are recorded in [`docs/adr/`](https://github.com/modern-python/compose2pod/tree/main/docs/adr/).
|
|
114
115
|
|
|
115
116
|
## Status
|
|
116
117
|
|
|
@@ -29,9 +29,8 @@ Built for CI and test environments where you can't use `docker compose` or `podm
|
|
|
29
29
|
## Requirements
|
|
30
30
|
|
|
31
31
|
compose2pod's generated scripts own `/etc/hosts`: they write it to a temp
|
|
32
|
-
file and bind-mount it read-only into every container under `--no-hosts
|
|
33
|
-
|
|
34
|
-
works on any Podman version. `host.containers.internal` /
|
|
32
|
+
file and bind-mount it read-only into every container under `--no-hosts`, so
|
|
33
|
+
pod-internal name resolution works on any Podman version. `host.containers.internal` /
|
|
35
34
|
`host.docker.internal` are not provided — add an explicit `extra_hosts`
|
|
36
35
|
entry if you need them.
|
|
37
36
|
|
|
@@ -83,8 +82,8 @@ Compose extension fields (any `x-`-prefixed key) and YAML anchors are accepted
|
|
|
83
82
|
as-is, so a top-level `x-*` anchor block for shared config just works.
|
|
84
83
|
`${VAR}`-style variable interpolation is left live in the generated script,
|
|
85
84
|
resolved by its shell against the environment present when the script runs (no
|
|
86
|
-
`.env` file support).
|
|
87
|
-
|
|
85
|
+
`.env` file support). The boundary rulings — which forms are refused, and why —
|
|
86
|
+
are recorded in [`docs/adr/`](https://github.com/modern-python/compose2pod/tree/main/docs/adr/).
|
|
88
87
|
|
|
89
88
|
## Status
|
|
90
89
|
|
|
@@ -58,7 +58,7 @@ def _depends_on_entry_condition(dep: str, spec: dict[str, Any]) -> str:
|
|
|
58
58
|
# defaults to service_started -- that default is Docker's own and
|
|
59
59
|
# stays. This one was compose2pod's own invention (`spec.get(...,
|
|
60
60
|
# "service_started")`) and was a false green against the hard rule
|
|
61
|
-
# in `
|
|
61
|
+
# in `docs/adr/0006-docker-rejection-parity.md`.
|
|
62
62
|
msg = f"depends_on entry {dep!r}: missing required key 'condition'"
|
|
63
63
|
raise UnsupportedComposeError(msg)
|
|
64
64
|
condition = spec["condition"]
|
|
@@ -34,9 +34,8 @@ def _validate_string_list(name: str, key: str, value: Any) -> None: # noqa: ANN
|
|
|
34
34
|
raise UnsupportedComposeError(msg)
|
|
35
35
|
|
|
36
36
|
|
|
37
|
-
# Accepted but never emitted -- meaningless inside a single shared-namespace pod
|
|
38
|
-
#
|
|
39
|
-
# the *gate*: a key compose2pod does not use is still one Docker validates, and a
|
|
37
|
+
# Accepted but never emitted -- meaningless inside a single shared-namespace pod.
|
|
38
|
+
# Ignored at *emit* is not unchecked at the *gate*: a key compose2pod does not use is still one Docker validates, and a
|
|
40
39
|
# document carrying a malformed one is a document Docker will not run. Each value
|
|
41
40
|
# is the shape validator; the content rules are Docker's own, measured -- it
|
|
42
41
|
# accepts `restart: banana` and any `stop_signal` string, so neither is enumerated
|
|
@@ -866,8 +865,7 @@ def _sweep_service(name: str, svc: dict[str, Any]) -> None:
|
|
|
866
865
|
|
|
867
866
|
Two of the service's own top-level keys are skipped rather than swept,
|
|
868
867
|
because compose2pod never reads their contents: `build` (accepted, but
|
|
869
|
-
`image_for` never reads its contents
|
|
870
|
-
architecture/supported-subset.md) and any `x-`-prefixed key (an
|
|
868
|
+
`image_for` never reads its contents) and any `x-`-prefixed key (an
|
|
871
869
|
extension field whose value is arbitrary user payload, by design, same
|
|
872
870
|
as everywhere else `x-` is skipped). `depends_on`/`networks`/`ulimits`
|
|
873
871
|
are identifier-keyed and go through `_sweep_identifier_map` instead of
|
|
@@ -1053,7 +1051,7 @@ def _validate_network_driver_opts(name: str, key: str, value: Any) -> None: # n
|
|
|
1053
1051
|
Measured against `docker compose config` v5.1.2: a bool/null/list entry
|
|
1054
1052
|
value is refused ('must be a number or string') even though the key
|
|
1055
1053
|
itself may be any string. compose2pod never reads a network entry's
|
|
1056
|
-
`driver_opts` contents
|
|
1054
|
+
`driver_opts` contents, but a
|
|
1057
1055
|
malformed value here is still a document Docker refuses.
|
|
1058
1056
|
"""
|
|
1059
1057
|
if not isinstance(value, dict):
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Value grammars: the shapes `docker compose config` accepts for a scalar key.
|
|
2
2
|
|
|
3
3
|
compose2pod refuses every document Docker refuses
|
|
4
|
-
(`
|
|
4
|
+
(`docs/adr/0006-docker-rejection-parity.md`), which means
|
|
5
5
|
matching Docker's *value* grammars, not just its types: `mem_limit: ""` and
|
|
6
6
|
`cpus: somevalue` are documents Docker will not run.
|
|
7
7
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "compose2pod"
|
|
3
|
+
description = "Convert a Docker Compose file into a script that runs its services as a single Podman pod"
|
|
4
|
+
requires-python = ">=3.10,<4"
|
|
5
|
+
license = "MIT"
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
keywords = [
|
|
8
|
+
"podman",
|
|
9
|
+
"docker-compose",
|
|
10
|
+
"docker",
|
|
11
|
+
"containers",
|
|
12
|
+
"cli",
|
|
13
|
+
"python",
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Programming Language :: Python :: 3.14",
|
|
23
|
+
"Programming Language :: Python :: Free Threading :: 2 - Beta",
|
|
24
|
+
"Typing :: Typed",
|
|
25
|
+
"Topic :: Software Development :: Libraries",
|
|
26
|
+
"Topic :: Software Development :: Testing",
|
|
27
|
+
]
|
|
28
|
+
version = "0.4.3"
|
|
29
|
+
|
|
30
|
+
[[project.authors]]
|
|
31
|
+
name = "Artur Shiriev"
|
|
32
|
+
email = "me@shiriev.ru"
|
|
33
|
+
|
|
34
|
+
[project.optional-dependencies]
|
|
35
|
+
yaml = ["PyYAML>=6"]
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
compose2pod = "compose2pod.cli:main"
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://modern-python.org"
|
|
42
|
+
Repository = "https://github.com/modern-python/compose2pod"
|
|
43
|
+
Issues = "https://github.com/modern-python/compose2pod/issues"
|
|
44
|
+
Changelog = "https://github.com/modern-python/compose2pod/releases"
|
|
45
|
+
|
|
46
|
+
[build-system]
|
|
47
|
+
requires = ["uv_build>=0.11,<1.0"]
|
|
48
|
+
build-backend = "uv_build"
|
|
49
|
+
|
|
50
|
+
[tool.uv.build-backend]
|
|
51
|
+
module-name = "compose2pod"
|
|
52
|
+
module-root = ""
|
|
53
|
+
|
|
54
|
+
[tool.ruff]
|
|
55
|
+
fix = true
|
|
56
|
+
unsafe-fixes = true
|
|
57
|
+
line-length = 120
|
|
58
|
+
|
|
59
|
+
[tool.ruff.lint]
|
|
60
|
+
select = ["ALL"]
|
|
61
|
+
ignore = [
|
|
62
|
+
"D1",
|
|
63
|
+
"D203",
|
|
64
|
+
"D213",
|
|
65
|
+
"COM812",
|
|
66
|
+
"ISC001",
|
|
67
|
+
"CPY001",
|
|
68
|
+
"FBT",
|
|
69
|
+
"TCH",
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
[tool.ruff.lint.isort]
|
|
73
|
+
lines-after-imports = 2
|
|
74
|
+
no-lines-before = [
|
|
75
|
+
"standard-library",
|
|
76
|
+
"local-folder",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint.per-file-ignores]
|
|
80
|
+
"tests/**" = ["S101"]
|
|
81
|
+
|
|
82
|
+
[tool.pytest.ini_options]
|
|
83
|
+
addopts = "-m 'not integration and not conformance'"
|
|
84
|
+
testpaths = ["tests"]
|
|
85
|
+
pythonpath = ["."]
|
|
86
|
+
markers = [
|
|
87
|
+
"integration: end-to-end tests that execute generated scripts against real podman (CI-only)",
|
|
88
|
+
"conformance: differential tests asserting compose2pod refuses whatever `docker compose config` refuses (CI-only; needs the docker CLI, no daemon)",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
[tool.coverage.report]
|
|
92
|
+
exclude_also = ["if typing.TYPE_CHECKING:"]
|
|
93
|
+
fail_under = 100
|
|
94
|
+
|
|
95
|
+
[tool.coverage.run]
|
|
96
|
+
omit = [
|
|
97
|
+
"compose2pod/__main__.py",
|
|
98
|
+
"tests/integration/*",
|
|
99
|
+
"tests/conformance/*",
|
|
100
|
+
]
|
|
101
|
+
|
|
102
|
+
[dependency-groups]
|
|
103
|
+
dev = [
|
|
104
|
+
"pytest",
|
|
105
|
+
"pytest-cov",
|
|
106
|
+
]
|
|
107
|
+
lint = [
|
|
108
|
+
"ruff",
|
|
109
|
+
"ty",
|
|
110
|
+
"eof-fixer",
|
|
111
|
+
"typing-extensions",
|
|
112
|
+
"types-PyYAML",
|
|
113
|
+
]
|
|
@@ -5,7 +5,7 @@ authors = [{ name = "Artur Shiriev", email = "me@shiriev.ru" }]
|
|
|
5
5
|
requires-python = ">=3.10,<4"
|
|
6
6
|
license = "MIT"
|
|
7
7
|
readme = "README.md"
|
|
8
|
-
keywords = ["podman", "docker-compose", "
|
|
8
|
+
keywords = ["podman", "docker-compose", "docker", "containers", "cli", "python"]
|
|
9
9
|
classifiers = [
|
|
10
10
|
"Development Status :: 4 - Beta",
|
|
11
11
|
"Intended Audience :: Developers",
|
|
@@ -14,11 +14,12 @@ classifiers = [
|
|
|
14
14
|
"Programming Language :: Python :: 3.12",
|
|
15
15
|
"Programming Language :: Python :: 3.13",
|
|
16
16
|
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Programming Language :: Python :: Free Threading :: 2 - Beta",
|
|
17
18
|
"Typing :: Typed",
|
|
18
19
|
"Topic :: Software Development :: Libraries",
|
|
19
20
|
"Topic :: Software Development :: Testing",
|
|
20
21
|
]
|
|
21
|
-
version = "0.4.
|
|
22
|
+
version = "0.4.3"
|
|
22
23
|
|
|
23
24
|
[project.optional-dependencies]
|
|
24
25
|
yaml = ["PyYAML>=6"]
|
|
@@ -27,6 +28,7 @@ yaml = ["PyYAML>=6"]
|
|
|
27
28
|
compose2pod = "compose2pod.cli:main"
|
|
28
29
|
|
|
29
30
|
[project.urls]
|
|
31
|
+
Homepage = "https://modern-python.org"
|
|
30
32
|
Repository = "https://github.com/modern-python/compose2pod"
|
|
31
33
|
Issues = "https://github.com/modern-python/compose2pod/issues"
|
|
32
34
|
Changelog = "https://github.com/modern-python/compose2pod/releases"
|
|
@@ -56,23 +58,25 @@ lint = [
|
|
|
56
58
|
fix = true
|
|
57
59
|
unsafe-fixes = true
|
|
58
60
|
line-length = 120
|
|
59
|
-
target-version = "py310"
|
|
60
61
|
|
|
61
62
|
[tool.ruff.lint]
|
|
62
63
|
select = ["ALL"]
|
|
63
64
|
ignore = [
|
|
64
|
-
"D1", #
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
65
|
+
"D1", # docstrings are not forced; a docstring exists when it says something
|
|
66
|
+
"D203", # conflicts with D211
|
|
67
|
+
"D213", # conflicts with D212
|
|
68
|
+
"COM812", # conflicts with the formatter
|
|
69
|
+
"ISC001", # conflicts with the formatter
|
|
70
|
+
"CPY001", # no per-file copyright header
|
|
71
|
+
"FBT", # boolean positional arguments are fine
|
|
72
|
+
"TCH", # imports stay real; TYPE_CHECKING-only imports break runtime introspection
|
|
72
73
|
]
|
|
73
74
|
isort.lines-after-imports = 2
|
|
74
75
|
isort.no-lines-before = ["standard-library", "local-folder"]
|
|
75
76
|
|
|
77
|
+
[tool.ruff.lint.per-file-ignores]
|
|
78
|
+
"tests/**" = ["S101"]
|
|
79
|
+
|
|
76
80
|
[tool.pytest.ini_options]
|
|
77
81
|
addopts = "-m 'not integration and not conformance'"
|
|
78
82
|
testpaths = ["tests"]
|
|
@@ -84,6 +88,7 @@ markers = [
|
|
|
84
88
|
|
|
85
89
|
[tool.coverage]
|
|
86
90
|
report.exclude_also = ["if typing.TYPE_CHECKING:"]
|
|
91
|
+
report.fail_under = 100
|
|
87
92
|
# The __main__.py shim is a pure `sys.exit(main())` entrypoint exercised only via
|
|
88
93
|
# subprocess (tests/test_cli.py::test_python_m_runs), which the parent coverage process
|
|
89
94
|
# can't measure; omit it rather than enable subprocess/branch coverage machinery.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|