pyrig-containers 0.1.0__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.
- pyrig_containers-0.1.0/LICENSE +21 -0
- pyrig_containers-0.1.0/PKG-INFO +56 -0
- pyrig_containers-0.1.0/README.md +34 -0
- pyrig_containers-0.1.0/pyproject.toml +97 -0
- pyrig_containers-0.1.0/src/pyrig_containers/__init__.py +1 -0
- pyrig_containers-0.1.0/src/pyrig_containers/py.typed +0 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/__init__.py +1 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/configs/__init__.py +1 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/configs/container_file.py +99 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/tools/__init__.py +1 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/tools/container_engine.py +54 -0
- pyrig_containers-0.1.0/src/pyrig_containers/rig/tools/package_manager.py +22 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Winipedia
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyrig-containers
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A pyrig plugin to integrate containers.
|
|
5
|
+
Keywords:
|
|
6
|
+
Author: Winipedia
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Requires-Dist: pyrig>=12.1.1
|
|
14
|
+
Maintainer: Winipedia
|
|
15
|
+
Requires-Python: >=3.13
|
|
16
|
+
Project-URL: Homepage, https://github.com/Winipedia/pyrig-containers
|
|
17
|
+
Project-URL: Documentation, https://Winipedia.github.io/pyrig-containers
|
|
18
|
+
Project-URL: Source, https://github.com/Winipedia/pyrig-containers
|
|
19
|
+
Project-URL: Issues, https://github.com/Winipedia/pyrig-containers/issues
|
|
20
|
+
Project-URL: Changelog, https://github.com/Winipedia/pyrig-containers/releases
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# pyrig-containers
|
|
24
|
+
|
|
25
|
+
<!-- security -->
|
|
26
|
+
[](https://github.com/pypa/pip-audit)
|
|
27
|
+
[](https://github.com/PyCQA/bandit)
|
|
28
|
+
<!-- ci/cd -->
|
|
29
|
+
[](https://github.com/Winipedia/pyrig-containers/actions/workflows/health_check.yml)
|
|
30
|
+
[](https://github.com/Winipedia/pyrig-containers/actions/workflows/deploy.yml)
|
|
31
|
+
<!-- code-quality -->
|
|
32
|
+
[](https://github.com/rvben/rumdl)
|
|
33
|
+
[](https://github.com/astral-sh/ruff)
|
|
34
|
+
[](https://github.com/astral-sh/ty)
|
|
35
|
+
[](https://github.com/j178/prek)
|
|
36
|
+
<!-- testing -->
|
|
37
|
+
[](https://codecov.io/gh/Winipedia/pyrig-containers)
|
|
38
|
+
[](https://pytest.org)
|
|
39
|
+
<!-- tooling -->
|
|
40
|
+
[](https://podman.io)
|
|
41
|
+
[](https://github.com/astral-sh/uv)
|
|
42
|
+
[](https://github.com/Winipedia/pyrig)
|
|
43
|
+
[](https://github.com/Winipedia/pyrig-containers)
|
|
44
|
+
[](https://git-scm.com)
|
|
45
|
+
<!-- documentation -->
|
|
46
|
+
[](https://www.mkdocs.org)
|
|
47
|
+
[](https://Winipedia.github.io/pyrig-containers)
|
|
48
|
+
<!-- project-info -->
|
|
49
|
+
[](https://www.python.org)
|
|
50
|
+
[](https://github.com/Winipedia/pyrig-containers/blob/main/LICENSE)
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
> A pyrig plugin to integrate containers.
|
|
55
|
+
|
|
56
|
+
---
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# pyrig-containers
|
|
2
|
+
|
|
3
|
+
<!-- security -->
|
|
4
|
+
[](https://github.com/pypa/pip-audit)
|
|
5
|
+
[](https://github.com/PyCQA/bandit)
|
|
6
|
+
<!-- ci/cd -->
|
|
7
|
+
[](https://github.com/Winipedia/pyrig-containers/actions/workflows/health_check.yml)
|
|
8
|
+
[](https://github.com/Winipedia/pyrig-containers/actions/workflows/deploy.yml)
|
|
9
|
+
<!-- code-quality -->
|
|
10
|
+
[](https://github.com/rvben/rumdl)
|
|
11
|
+
[](https://github.com/astral-sh/ruff)
|
|
12
|
+
[](https://github.com/astral-sh/ty)
|
|
13
|
+
[](https://github.com/j178/prek)
|
|
14
|
+
<!-- testing -->
|
|
15
|
+
[](https://codecov.io/gh/Winipedia/pyrig-containers)
|
|
16
|
+
[](https://pytest.org)
|
|
17
|
+
<!-- tooling -->
|
|
18
|
+
[](https://podman.io)
|
|
19
|
+
[](https://github.com/astral-sh/uv)
|
|
20
|
+
[](https://github.com/Winipedia/pyrig)
|
|
21
|
+
[](https://github.com/Winipedia/pyrig-containers)
|
|
22
|
+
[](https://git-scm.com)
|
|
23
|
+
<!-- documentation -->
|
|
24
|
+
[](https://www.mkdocs.org)
|
|
25
|
+
[](https://Winipedia.github.io/pyrig-containers)
|
|
26
|
+
<!-- project-info -->
|
|
27
|
+
[](https://www.python.org)
|
|
28
|
+
[](https://github.com/Winipedia/pyrig-containers/blob/main/LICENSE)
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
> A pyrig plugin to integrate containers.
|
|
33
|
+
|
|
34
|
+
---
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "pyrig-containers"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "A pyrig plugin to integrate containers."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.13"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"pyrig>=12.1.1",
|
|
9
|
+
]
|
|
10
|
+
license = "MIT"
|
|
11
|
+
license-files = [
|
|
12
|
+
"LICENSE",
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Programming Language :: Python :: 3.13",
|
|
16
|
+
"Programming Language :: Python :: 3.14",
|
|
17
|
+
"Operating System :: OS Independent",
|
|
18
|
+
"Typing :: Typed",
|
|
19
|
+
]
|
|
20
|
+
keywords = []
|
|
21
|
+
|
|
22
|
+
[[project.authors]]
|
|
23
|
+
name = "Winipedia"
|
|
24
|
+
|
|
25
|
+
[[project.maintainers]]
|
|
26
|
+
name = "Winipedia"
|
|
27
|
+
|
|
28
|
+
[project.urls]
|
|
29
|
+
Homepage = "https://github.com/Winipedia/pyrig-containers"
|
|
30
|
+
Documentation = "https://Winipedia.github.io/pyrig-containers"
|
|
31
|
+
Source = "https://github.com/Winipedia/pyrig-containers"
|
|
32
|
+
Issues = "https://github.com/Winipedia/pyrig-containers/issues"
|
|
33
|
+
Changelog = "https://github.com/Winipedia/pyrig-containers/releases"
|
|
34
|
+
|
|
35
|
+
[project.scripts]
|
|
36
|
+
pyrig-containers = "pyrig.rig.cli.main:main"
|
|
37
|
+
|
|
38
|
+
[dependency-groups]
|
|
39
|
+
dev = [
|
|
40
|
+
"bandit>=1.9.4",
|
|
41
|
+
"mkdocs>=1.6.1",
|
|
42
|
+
"mkdocs-material>=9.7.6",
|
|
43
|
+
"mkdocs-mermaid2-plugin>=1.2.3",
|
|
44
|
+
"mkdocstrings[python]>=1.0.4",
|
|
45
|
+
"pip-audit>=2.10.0",
|
|
46
|
+
"prek>=0.4.4",
|
|
47
|
+
"pygithub>=2.9.1",
|
|
48
|
+
"pyrig-codecov>=1.1.2",
|
|
49
|
+
"pyrig-dev>=1.0.0",
|
|
50
|
+
"pytest>=9.0.3",
|
|
51
|
+
"pytest-cov>=7.1.0",
|
|
52
|
+
"pytest-mock>=3.15.1",
|
|
53
|
+
"ruff>=0.15.16",
|
|
54
|
+
"rumdl>=0.2.9",
|
|
55
|
+
"ty>=0.0.44",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[build-system]
|
|
59
|
+
requires = [
|
|
60
|
+
"uv_build",
|
|
61
|
+
]
|
|
62
|
+
build-backend = "uv_build"
|
|
63
|
+
|
|
64
|
+
[tool.ruff.lint]
|
|
65
|
+
select = [
|
|
66
|
+
"ALL",
|
|
67
|
+
]
|
|
68
|
+
ignore = [
|
|
69
|
+
"COM812",
|
|
70
|
+
"ANN401",
|
|
71
|
+
]
|
|
72
|
+
fixable = [
|
|
73
|
+
"ALL",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint.per-file-ignores]
|
|
77
|
+
"**/tests/**/*.py" = [
|
|
78
|
+
"S101",
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
[tool.ruff.lint.pydocstyle]
|
|
82
|
+
convention = "google"
|
|
83
|
+
|
|
84
|
+
[tool.ty.terminal]
|
|
85
|
+
error-on-warning = true
|
|
86
|
+
|
|
87
|
+
[tool.pytest.ini_options]
|
|
88
|
+
testpaths = [
|
|
89
|
+
"tests",
|
|
90
|
+
]
|
|
91
|
+
addopts = "--cov=pyrig_containers --cov-branch --cov-report=term-missing --cov-fail-under=100 --cov-report=xml"
|
|
92
|
+
|
|
93
|
+
[tool.bandit.assert_used]
|
|
94
|
+
skips = [
|
|
95
|
+
"*/tests/*.py",
|
|
96
|
+
"*/test_*/*.py",
|
|
97
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""The top-level package for the project."""
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package initialization."""
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package initialization."""
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""Containerfile configuration management."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from pyrig.rig.configs.base.string_ import StringConfigFile
|
|
7
|
+
from pyrig.rig.configs.license import LicenseConfigFile
|
|
8
|
+
from pyrig.rig.configs.markdown.readme import ReadmeConfigFile
|
|
9
|
+
from pyrig.rig.configs.pyproject import PyprojectConfigFile
|
|
10
|
+
from pyrig.rig.tools.package_manager import PackageManager
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ContainerfileConfigFile(StringConfigFile):
|
|
14
|
+
"""Generates a production-ready Containerfile for the project.
|
|
15
|
+
|
|
16
|
+
Produces a Containerfile with a Python slim base image, uv as the package
|
|
17
|
+
manager, a non-root runtime user (appuser, UID 1000), and layer ordering
|
|
18
|
+
optimized for cache reuse. Compatible with Docker, Podman, and buildah.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def stem(self) -> str:
|
|
22
|
+
"""Return the filename stem 'Containerfile'."""
|
|
23
|
+
return "Containerfile"
|
|
24
|
+
|
|
25
|
+
def parent_path(self) -> Path:
|
|
26
|
+
"""Return the project root directory."""
|
|
27
|
+
return Path()
|
|
28
|
+
|
|
29
|
+
def extension(self) -> str:
|
|
30
|
+
"""Return an empty string (Containerfile has no file extension)."""
|
|
31
|
+
return ""
|
|
32
|
+
|
|
33
|
+
def extension_separator(self) -> str:
|
|
34
|
+
"""Return an empty string, overriding the base class default separator '.'.
|
|
35
|
+
|
|
36
|
+
Prevents the base class from appending a dot to the filename, since
|
|
37
|
+
Containerfile uses neither an extension nor a separator.
|
|
38
|
+
"""
|
|
39
|
+
return ""
|
|
40
|
+
|
|
41
|
+
def lines(self) -> list[str]:
|
|
42
|
+
"""Return the Containerfile build instructions.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
List of instruction lines produced by `layers()`.
|
|
46
|
+
"""
|
|
47
|
+
return self.layers()
|
|
48
|
+
|
|
49
|
+
def layers(self) -> list[str]:
|
|
50
|
+
"""Generate the complete sequence of Containerfile build instructions.
|
|
51
|
+
|
|
52
|
+
Produces an optimized layer order so that infrequently changing files
|
|
53
|
+
(project metadata and lock file) are copied before the source tree is
|
|
54
|
+
added. This maximizes Docker/Podman build cache reuse when only source
|
|
55
|
+
code changes.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
List of Containerfile instruction strings followed by a trailing
|
|
59
|
+
empty string.
|
|
60
|
+
|
|
61
|
+
Note:
|
|
62
|
+
Reads ``requires-python`` from ``pyproject.toml`` and falls back to
|
|
63
|
+
the bundled ``LATEST_PYTHON_VERSION`` resource file when no upper
|
|
64
|
+
bound is specified.
|
|
65
|
+
"""
|
|
66
|
+
latest_python_version = PyprojectConfigFile.I.latest_possible_python_version()
|
|
67
|
+
package_root = PackageManager.I.package_root().as_posix()
|
|
68
|
+
project_name = PackageManager.I.project_name()
|
|
69
|
+
workdir = Path(project_name).as_posix()
|
|
70
|
+
app_user_name = "appuser"
|
|
71
|
+
entrypoint = json.dumps(list(PackageManager.I.run_args(project_name)))
|
|
72
|
+
readme_path, license_path, pyproject_path, lock_file_path = (
|
|
73
|
+
ReadmeConfigFile.I.path().as_posix(),
|
|
74
|
+
LicenseConfigFile.I.path().as_posix(),
|
|
75
|
+
PyprojectConfigFile.I.path().as_posix(),
|
|
76
|
+
PackageManager.I.lock_file().as_posix(),
|
|
77
|
+
)
|
|
78
|
+
copy_files = f"{readme_path} {license_path} {pyproject_path} {lock_file_path}"
|
|
79
|
+
install_dependencies_no_dev = (
|
|
80
|
+
PackageManager.I.install_dependencies_no_dev_args()
|
|
81
|
+
)
|
|
82
|
+
image_url, image_source_path, image_destination_path = (
|
|
83
|
+
PackageManager.I.container_image()
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return [
|
|
87
|
+
f"FROM python:{latest_python_version}-slim",
|
|
88
|
+
f"WORKDIR /{workdir}",
|
|
89
|
+
f"COPY --from={image_url} {image_source_path} {image_destination_path}",
|
|
90
|
+
f"COPY {copy_files} ./",
|
|
91
|
+
f"RUN useradd -m -u 1000 {app_user_name}",
|
|
92
|
+
f"RUN chown -R {app_user_name}:{app_user_name} .",
|
|
93
|
+
f"USER {app_user_name}",
|
|
94
|
+
f"COPY --chown={app_user_name}:{app_user_name} {package_root} {package_root}", # noqa: E501
|
|
95
|
+
f"RUN {install_dependencies_no_dev}",
|
|
96
|
+
f"RUN rm {copy_files}",
|
|
97
|
+
f"ENTRYPOINT {entrypoint}",
|
|
98
|
+
"",
|
|
99
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Package initialization."""
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Container engine wrapper.
|
|
2
|
+
|
|
3
|
+
Wraps container engine commands and information.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pyrig.rig.tools.base.tool import Group, Tool
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ContainerEngine(Tool):
|
|
10
|
+
"""Container engine wrapper.
|
|
11
|
+
|
|
12
|
+
Constructs podman command arguments for building and saving container images.
|
|
13
|
+
Typical usage: call ``build_args`` to build the image, then ``save_args``
|
|
14
|
+
to export it as a tar archive.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def name(self) -> str:
|
|
18
|
+
"""Get tool name.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
'podman'
|
|
22
|
+
"""
|
|
23
|
+
return "podman"
|
|
24
|
+
|
|
25
|
+
def group(self) -> str:
|
|
26
|
+
"""Returns the group the tool belongs to."""
|
|
27
|
+
return Group.TOOLING
|
|
28
|
+
|
|
29
|
+
def image_url(self) -> str:
|
|
30
|
+
"""Return the badge image URL for this tool.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
The URL of the badge image as a string.
|
|
34
|
+
"""
|
|
35
|
+
return "https://img.shields.io/badge/Container-Podman-A23CD6?logo=podman&logoColor=grey&colorA=0D1F3F&colorB=A23CD6"
|
|
36
|
+
|
|
37
|
+
def link_url(self) -> str:
|
|
38
|
+
"""Return the URL that the badge should link to for this tool.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
The URL of the project page as a string.
|
|
42
|
+
"""
|
|
43
|
+
return "https://podman.io"
|
|
44
|
+
|
|
45
|
+
def dev_dependencies(self) -> tuple[str, ...]:
|
|
46
|
+
"""Get tool dependencies.
|
|
47
|
+
|
|
48
|
+
Podman is a system package (not a Python dependency), so this
|
|
49
|
+
returns an empty tuple.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
Empty tuple — podman must be installed at the OS level.
|
|
53
|
+
"""
|
|
54
|
+
return ()
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Package manager wrapper.
|
|
2
|
+
|
|
3
|
+
Wraps PackageManager commands and information.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pyrig.rig.tools.package_manager import PackageManager as BasePackageManager
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class PackageManager(BasePackageManager):
|
|
10
|
+
"""You can override methods from the base class to customize behavior."""
|
|
11
|
+
|
|
12
|
+
def container_image(self) -> tuple[str, str, str]:
|
|
13
|
+
"""Return the container image coordinates for copying uv.
|
|
14
|
+
|
|
15
|
+
Used when generating a ``Containerfile`` to add a
|
|
16
|
+
``COPY --from=<image> <src> <dst>`` directive that installs uv
|
|
17
|
+
into the container image.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Tuple of (image_name, path_in_source_image, path_in_target_image).
|
|
21
|
+
"""
|
|
22
|
+
return "ghcr.io/astral-sh/uv:latest", "/uv", "/usr/local/bin/uv"
|