Skip to content

Commit d31dede

Browse files
committed
Change to V2
1 parent 029423a commit d31dede

File tree

2 files changed

+43
-25
lines changed

2 files changed

+43
-25
lines changed

compose/testcontainers/compose/__init__.py

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1+
# type: ignore
12
import subprocess
23
from typing import Iterable, List, Optional, Tuple, Union
34

45
import requests
5-
66
from testcontainers.core.exceptions import NoSuchPortExposed
77
from testcontainers.core.waiting_utils import wait_container_is_ready
88

@@ -14,6 +14,9 @@ class DockerCompose:
1414
Args:
1515
filepath: Relative directory containing the docker compose configuration file.
1616
compose_file_name: File name of the docker compose configuration file.
17+
compose_command: The command to use for docker compose. If not specified, a call to
18+
docker compose --help will be made to determine the correct command to use.
19+
If docker compose is not installed, docker-compose will be used.
1720
pull: Pull images before launching environment.
1821
build: Build images referenced in the configuration file.
1922
env_file: Path to an env file containing environment variables to pass to docker compose.
@@ -45,21 +48,19 @@ def __init__(
4548
self,
4649
filepath: str,
4750
compose_file_name: Union[str, Iterable] = "docker-compose.yml",
51+
compose_command: str = None,
4852
pull: bool = False,
4953
build: bool = False,
5054
env_file: Optional[str] = None,
5155
services: Optional[List[str]] = None,
5256
) -> None:
5357
self.filepath = filepath
54-
self.compose_file_names = (
55-
[compose_file_name]
56-
if isinstance(compose_file_name, str)
57-
else list(compose_file_name)
58-
)
58+
self.compose_file_names = [compose_file_name] if isinstance(compose_file_name, str) else list(compose_file_name)
5959
self.pull = pull
6060
self.build = build
6161
self.env_file = env_file
6262
self.services = services
63+
self.compose_command = self._get_compose_command(compose_command)
6364

6465
def __enter__(self) -> "DockerCompose":
6566
self.start()
@@ -68,14 +69,37 @@ def __enter__(self) -> "DockerCompose":
6869
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
6970
self.stop()
7071

72+
def _get_compose_command(self, command):
73+
"""
74+
Returns the basecommand parts used for the docker compose commands
75+
depending on the docker compose api.
76+
77+
Returns
78+
-------
79+
list[str]
80+
The docker compose command parts
81+
"""
82+
if command:
83+
return command.split(" ")
84+
85+
if (
86+
subprocess.run(
87+
["docker", "compose", "--help"], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT
88+
).returncode
89+
== 0
90+
):
91+
return ["docker", "compose"]
92+
93+
return ["docker-compose"]
94+
7195
def docker_compose_command(self) -> List[str]:
7296
"""
7397
Returns command parts used for the docker compose commands
7498
7599
Returns:
76100
cmd: Docker compose command parts.
77101
"""
78-
docker_compose_cmd = ["docker-compose"]
102+
docker_compose_cmd = self.compose_command.copy()
79103
for file in self.compose_file_names:
80104
docker_compose_cmd += ["-f", file]
81105
if self.env_file:
@@ -95,7 +119,6 @@ def start(self) -> None:
95119
up_cmd.append("--build")
96120
if self.services:
97121
up_cmd.extend(self.services)
98-
99122
self._call_command(cmd=up_cmd)
100123

101124
def stop(self) -> None:
@@ -105,7 +128,7 @@ def stop(self) -> None:
105128
down_cmd = self.docker_compose_command() + ["down", "-v"]
106129
self._call_command(cmd=down_cmd)
107130

108-
def get_logs(self) -> Tuple[bytes, bytes]:
131+
def get_logs(self) -> Tuple[str, str]:
109132
"""
110133
Returns all log output from stdout and stderr
111134
@@ -122,9 +145,7 @@ def get_logs(self) -> Tuple[bytes, bytes]:
122145
)
123146
return result.stdout, result.stderr
124147

125-
def exec_in_container(
126-
self, service_name: str, command: List[str]
127-
) -> Tuple[str, str, int]:
148+
def exec_in_container(self, service_name: str, command: List[str]) -> Tuple[str, str]:
128149
"""
129150
Executes a command in the container of one of the services.
130151
@@ -136,20 +157,14 @@ def exec_in_container(
136157
stdout: Standard output stream.
137158
stderr: Standard error stream.
138159
"""
139-
exec_cmd = (
140-
self.docker_compose_command() + ["exec", "-T", service_name] + command
141-
)
160+
exec_cmd = self.docker_compose_command() + ["exec", "-T", service_name] + command
142161
result = subprocess.run(
143162
exec_cmd,
144163
cwd=self.filepath,
145164
stdout=subprocess.PIPE,
146165
stderr=subprocess.PIPE,
147166
)
148-
return (
149-
result.stdout.decode("utf-8"),
150-
result.stderr.decode("utf-8"),
151-
result.returncode,
152-
)
167+
return result.stdout.decode("utf-8"), result.stderr.decode("utf-8"), result.returncode
153168

154169
def get_service_port(self, service_name: str, port: int) -> int:
155170
"""
@@ -179,15 +194,16 @@ def get_service_host(self, service_name: str, port: int) -> str:
179194

180195
def _get_service_info(self, service: str, port: int) -> List[str]:
181196
port_cmd = self.docker_compose_command() + ["port", service, str(port)]
182-
output = subprocess.check_output(port_cmd, cwd=self.filepath).decode("utf-8")
197+
try:
198+
output = subprocess.check_output(port_cmd, cwd=self.filepath).decode("utf-8")
199+
except subprocess.CalledProcessError as e:
200+
raise NoSuchPortExposed(str(e.stderr))
183201
result = str(output).rstrip().split(":")
184202
if len(result) != 2 or not all(result):
185203
raise NoSuchPortExposed(f"port {port} is not exposed for service {service}")
186204
return result
187205

188-
def _call_command(
189-
self, cmd: Union[str, List[str]], filepath: Optional[str] = None
190-
) -> None:
206+
def _call_command(self, cmd: Union[str, List[str]], filepath: Optional[str] = None) -> None:
191207
if filepath is None:
192208
filepath = self.filepath
193209
subprocess.call(cmd, cwd=filepath)

compose/tests/test_docker_compose.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ def test_can_build_images_before_spawning_service_via_compose():
3434

3535
assert compose.build
3636
docker_compose_cmd = call_mock.call_args_list[0][1]["cmd"]
37-
assert "docker-compose" in docker_compose_cmd
37+
assert "docker-compose" in docker_compose_cmd or (
38+
"docker" in docker_compose_cmd and "compose" in docker_compose_cmd
39+
)
3840
assert "up" in docker_compose_cmd
3941
assert "--build" in docker_compose_cmd
4042

0 commit comments

Comments
 (0)