Coverage for frappe_manager / docker / __init__.py: 73%
48 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
« prev ^ index » next coverage.py v7.13.5, created at 2026-07-02 18:13 +0530
1"""
2Docker module for Frappe Manager.
4This module provides unified Docker functionality including:
5- Docker Compose file editing and building (ComposeFile)
6- Docker client wrapper (DockerClient)
7- Docker Compose CLI wrapper (DockerComposeWrapper)
8- Volume mount utilities (DockerVolumeMount, DockerVolumeType)
9"""
11from dataclasses import dataclass
12from enum import Enum
13from pathlib import Path
14from typing import Union
16from frappe_manager import CLI_SERVICES_DIRECTORY
19class DockerVolumeType(str, Enum):
20 volume = "volume"
21 bind = "bind"
24class DockerVolumeMount:
25 def __init__(self, host: str | Path, container: str, type: str, compose_path: Path):
26 self.host = host
27 self.type = type
28 self.container = Path(container)
29 self.compose_path = compose_path
31 if type == DockerVolumeType.bind:
32 self.host = Path(self.host)
33 # only join ./ paths
34 if str(host).startswith("./"):
35 self.host = compose_path.parent.joinpath(host)
37 def __str__(self):
38 source = Path(self.host) if not isinstance(self.host, Path) else self.host
40 if self.type == "bind":
41 source = str(self.host).replace(str(self.compose_path.parent), ".")
43 dest = str(self.container)
44 return f"{source}:{dest}"
47# For convenient imports: from frappe_manager.docker import ComposeFile, DockerClient, etc.
48# These use lazy imports to avoid circular dependency issues
49def __getattr__(name):
50 """Lazy import to avoid circular dependencies."""
51 if name == "ComposeFile":
52 from frappe_manager.docker.compose_file import ComposeFile
54 return ComposeFile
55 if name == "ComposeSecretNotFoundError":
56 from frappe_manager.docker.compose_exceptions import ComposeSecretNotFoundError
58 return ComposeSecretNotFoundError
59 if name == "ComposeServiceNotFound":
60 from frappe_manager.docker.compose_exceptions import ComposeServiceNotFound
62 return ComposeServiceNotFound
63 if name == "DockerClient":
64 from frappe_manager.docker.docker_client import DockerClient
66 return DockerClient
67 if name == "DockerComposeWrapper":
68 from frappe_manager.docker.docker_compose import DockerComposeWrapper
70 return DockerComposeWrapper
71 if name == "DockerException":
72 from frappe_manager.docker.docker_exceptions import DockerException
74 return DockerException
75 if name == "SubprocessOutput":
76 from frappe_manager.docker.subprocess_output import SubprocessOutput
78 return SubprocessOutput
79 raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
82__all__ = [
83 # Compose file management
84 "ComposeFile",
85 "ComposeSecretNotFoundError",
86 "ComposeServiceNotFound",
87 # Docker wrappers
88 "DockerClient",
89 "DockerComposeWrapper",
90 "DockerException",
91 "SubprocessOutput",
92 # Volume utilities
93 "DockerVolumeMount",
94 "DockerVolumeType",
95]