7
7
8
8
import requests
9
9
import subprocess
10
+ from typing import Iterable , List , Optional , Tuple , Union
10
11
11
12
from testcontainers .core .waiting_utils import wait_container_is_ready
12
13
from testcontainers .core .exceptions import NoSuchPortExposed
@@ -16,18 +17,12 @@ class DockerCompose:
16
17
"""
17
18
Manage docker compose environments.
18
19
19
- Parameters
20
- ----------
21
- filepath: str
22
- The relative directory containing the docker compose configuration file
23
- compose_file_name: str
24
- The file name of the docker compose configuration file
25
- pull: bool
26
- Attempts to pull images before launching environment
27
- build: bool
28
- Whether to build images referenced in the configuration file
29
- env_file: str
30
- Path to an env file containing environment variables to pass to docker compose
20
+ Args:
21
+ filepath: Relative directory containing the docker compose configuration file.
22
+ compose_file_name: File name of the docker compose configuration file.
23
+ pull: Pull images before launching environment.
24
+ build: Build images referenced in the configuration file.
25
+ env_file: Path to an env file containing environment variables to pass to docker compose.
31
26
32
27
Example
33
28
-------
@@ -67,37 +62,33 @@ class DockerCompose:
67
62
expose:
68
63
- "5555"
69
64
"""
70
-
71
65
def __init__ (
72
66
self ,
73
- filepath ,
74
- compose_file_name = "docker-compose.yml" ,
75
- pull = False ,
76
- build = False ,
77
- env_file = None ):
67
+ filepath : str ,
68
+ compose_file_name : Union [ str , Iterable ] = "docker-compose.yml" ,
69
+ pull : bool = False ,
70
+ build : bool = False ,
71
+ env_file : Optional [ str ] = None ) -> None :
78
72
self .filepath = filepath
79
- self .compose_file_names = compose_file_name if isinstance (
80
- compose_file_name , (list , tuple )
81
- ) else [compose_file_name ]
73
+ self .compose_file_names = [compose_file_name ] if isinstance (compose_file_name , str ) else \
74
+ list (compose_file_name )
82
75
self .pull = pull
83
76
self .build = build
84
77
self .env_file = env_file
85
78
86
- def __enter__ (self ):
79
+ def __enter__ (self ) -> "DockerCompose" :
87
80
self .start ()
88
81
return self
89
82
90
- def __exit__ (self , exc_type , exc_val , exc_tb ):
83
+ def __exit__ (self , exc_type , exc_val , exc_tb ) -> None :
91
84
self .stop ()
92
85
93
- def docker_compose_command (self ):
86
+ def docker_compose_command (self ) -> List [ str ] :
94
87
"""
95
88
Returns command parts used for the docker compose commands
96
89
97
- Returns
98
- -------
99
- list[str]
100
- The docker compose command parts
90
+ Returns:
91
+ cmd: Docker compose command parts.
101
92
"""
102
93
docker_compose_cmd = ['docker-compose' ]
103
94
for file in self .compose_file_names :
@@ -106,7 +97,7 @@ def docker_compose_command(self):
106
97
docker_compose_cmd += ['--env-file' , self .env_file ]
107
98
return docker_compose_cmd
108
99
109
- def start (self ):
100
+ def start (self ) -> None :
110
101
"""
111
102
Starts the docker compose environment.
112
103
"""
@@ -120,21 +111,20 @@ def start(self):
120
111
121
112
self ._call_command (cmd = up_cmd )
122
113
123
- def stop (self ):
114
+ def stop (self ) -> None :
124
115
"""
125
116
Stops the docker compose environment.
126
117
"""
127
118
down_cmd = self .docker_compose_command () + ['down' , '-v' ]
128
119
self ._call_command (cmd = down_cmd )
129
120
130
- def get_logs (self ):
121
+ def get_logs (self ) -> Tuple [ str , str ] :
131
122
"""
132
123
Returns all log output from stdout and stderr
133
124
134
- Returns
135
- -------
136
- tuple[bytes, bytes]
137
- stdout, stderr
125
+ Returns:
126
+ stdout: Standard output stream.
127
+ stderr: Standard error stream.
138
128
"""
139
129
logs_cmd = self .docker_compose_command () + ["logs" ]
140
130
result = subprocess .run (
@@ -145,21 +135,17 @@ def get_logs(self):
145
135
)
146
136
return result .stdout , result .stderr
147
137
148
- def exec_in_container (self , service_name , command ) :
138
+ def exec_in_container (self , service_name : str , command : List [ str ]) -> Tuple [ str , str ] :
149
139
"""
150
140
Executes a command in the container of one of the services.
151
141
152
- Parameters
153
- ----------
154
- service_name: str
155
- Name of the docker compose service to run the command in
156
- command: list[str]
157
- The command to execute
142
+ Args:
143
+ service_name: Name of the docker compose service to run the command in.
144
+ command: Command to execute.
158
145
159
- Returns
160
- -------
161
- tuple[str, str, int]
162
- stdout, stderr, return code
146
+ Returns:
147
+ stdout: Standard output stream.
148
+ stderr: Standard error stream.
163
149
"""
164
150
exec_cmd = self .docker_compose_command () + ['exec' , '-T' , service_name ] + command
165
151
result = subprocess .run (
@@ -170,67 +156,54 @@ def exec_in_container(self, service_name, command):
170
156
)
171
157
return result .stdout .decode ("utf-8" ), result .stderr .decode ("utf-8" ), result .returncode
172
158
173
- def get_service_port (self , service_name , port ) :
159
+ def get_service_port (self , service_name : str , port : int ) -> int :
174
160
"""
175
161
Returns the mapped port for one of the services.
176
162
177
- Parameters
178
- ----------
179
- service_name: str
180
- Name of the docker compose service
181
- port: int
182
- The internal port to get the mapping for
163
+ Args:
164
+ service_name: Name of the docker compose service.
165
+ port: Internal port to get the mapping for.
183
166
184
- Returns
185
- -------
186
- str:
187
- The mapped port on the host
167
+ Returns:
168
+ mapped_port: Mapped port on the host.
188
169
"""
189
170
return self ._get_service_info (service_name , port )[1 ]
190
171
191
- def get_service_host (self , service_name , port ) :
172
+ def get_service_host (self , service_name : str , port : int ) -> str :
192
173
"""
193
174
Returns the host for one of the services.
194
175
195
- Parameters
196
- ----------
197
- service_name: str
198
- Name of the docker compose service
199
- port: int
200
- The internal port to get the host for
176
+ Args:
177
+ service_name: Name of the docker compose service.
178
+ port: Internal port to get the mapping for.
201
179
202
- Returns
203
- -------
204
- str:
205
- The hostname for the service
180
+ Returns:
181
+ host: Hostname for the service.
206
182
"""
207
183
return self ._get_service_info (service_name , port )[0 ]
208
184
209
- def _get_service_info (self , service , port ) :
185
+ def _get_service_info (self , service : str , port : int ) -> List [ str ] :
210
186
port_cmd = self .docker_compose_command () + ["port" , service , str (port )]
211
187
output = subprocess .check_output (port_cmd , cwd = self .filepath ).decode ("utf-8" )
212
188
result = str (output ).rstrip ().split (":" )
213
189
if len (result ) != 2 or not all (result ):
214
190
raise NoSuchPortExposed (f"port { port } is not exposed for service { service } " )
215
191
return result
216
192
217
- def _call_command (self , cmd , filepath = None ):
193
+ def _call_command (self , cmd : Union [ str , List [ str ]], filepath : Optional [ str ] = None ) -> None :
218
194
if filepath is None :
219
195
filepath = self .filepath
220
196
subprocess .call (cmd , cwd = filepath )
221
197
222
198
@wait_container_is_ready (requests .exceptions .ConnectionError )
223
- def wait_for (self , url ) :
199
+ def wait_for (self , url : str ) -> 'DockerCompose' :
224
200
"""
225
- Waits for a response from a given URL. This is typically used to
226
- block until a service in the environment has started and is responding.
227
- Note that it does not assert any sort of return code, only check that
228
- the connection was successful.
201
+ Waits for a response from a given URL. This is typically used to block until a service in
202
+ the environment has started and is responding. Note that it does not assert any sort of
203
+ return code, only check that the connection was successful.
229
204
230
- Parameters
231
- ----------
232
- url: str
233
- URL from one of the services in the environment to use to wait on
205
+ Args:
206
+ url: URL from one of the services in the environment to use to wait on.
234
207
"""
235
208
requests .get (url )
236
209
return self
0 commit comments