22
33import contextlib
44import json
5- import multiprocessing
65import os
7- import pathlib
8- import secrets
9- import subprocess
6+ import subprocess # noqa: S404
107import time
118from contextlib import AbstractContextManager , contextmanager
12- from functools import partial
13- from typing import Callable , Generator , Any
9+ from typing import TYPE_CHECKING , Any , Callable , Generator , Self
1410
15- import docker
1611import filelock
1712import pytest
18- from docker .models .containers import Container
19- from docker .errors import ImageNotFound
2013
14+ import docker
15+ from docker .errors import ImageNotFound
2116from pytest_databases .helpers import get_xdist_worker_id
2217from pytest_databases .types import ServiceContainer
2318
19+ if TYPE_CHECKING :
20+ import multiprocessing
21+ import pathlib
22+ from types import TracebackType
23+
24+ from docker .models .containers import Container
25+
2426
2527def get_docker_host () -> str :
2628 result = subprocess .run (
27- ["docker" , "context" , "ls" , "--format=json" ],
29+ ["docker" , "context" , "ls" , "--format=json" ], # noqa: S607
2830 text = True ,
2931 capture_output = True ,
3032 check = True ,
3133 )
32- contexts = (json .loads (l ) for l in result .stdout .splitlines ())
34+ contexts = (json .loads (line ) for line in result .stdout .splitlines ())
3335 return next (context ["DockerEndpoint" ] for context in contexts if context ["Current" ] is True )
3436
3537
@@ -40,12 +42,6 @@ def get_docker_client() -> docker.DockerClient:
4042 return docker .DockerClient .from_env (environment = env )
4143
4244
43- def log (msg ):
44- log_file = pathlib .Path ("out.log" )
45- with log_file .open ("a" ) as f :
46- f .write (msg + "\n " )
47-
48-
4945def _stop_all_containers (client : docker .DockerClient ) -> None :
5046 containers : list [Container ] = client .containers .list (all = True , filters = {"label" : "pytest_databases" })
5147 for container in containers :
@@ -56,7 +52,8 @@ def _stop_all_containers(client: docker.DockerClient) -> None:
5652 elif container .status == "removing" :
5753 continue
5854 else :
59- raise ValueError (f"Cannot handle container in state { container .status } " )
55+ msg = f"Cannot handle container in state { container .status } "
56+ raise ValueError (msg )
6057
6158
6259class DockerService (AbstractContextManager ):
@@ -72,13 +69,13 @@ def __init__(
7269 self ._session = session
7370 self ._is_xdist = get_xdist_worker_id () is not None
7471
75- def _daemon (self ):
72+ def _daemon (self ) -> None :
7673 while (self ._tmp_path / "ctrl" ).exists ():
7774 time .sleep (0.1 )
7875 self ._stop_all_containers ()
7976
80- def __enter__ (self ) -> DockerService :
81- if self ._is_xdist or True :
77+ def __enter__ (self ) -> Self :
78+ if self ._is_xdist :
8279 ctrl_file = _get_ctrl_file (self ._session )
8380 with filelock .FileLock (ctrl_file .with_suffix (".lock" )):
8481 if not ctrl_file .exists ():
@@ -88,7 +85,13 @@ def __enter__(self) -> DockerService:
8885 self ._stop_all_containers ()
8986 return self
9087
91- def __exit__ (self , exc_type , exc_val , exc_tb ) -> None :
88+ def __exit__ (
89+ self ,
90+ / ,
91+ __exc_type : type [BaseException ] | None ,
92+ __exc_value : BaseException | None ,
93+ __traceback : TracebackType | None ,
94+ ) -> None :
9295 if not self ._is_xdist :
9396 self ._stop_all_containers ()
9497
@@ -97,7 +100,8 @@ def _get_container(self, name: str) -> Container | None:
97100 filters = {"name" : name },
98101 )
99102 if len (containers ) > 1 :
100- raise ValueError (f"More than one running container found" )
103+ msg = "More than one running container found"
104+ raise ValueError (msg )
101105 if containers :
102106 return containers [0 ]
103107 return None
@@ -115,12 +119,13 @@ def run(
115119 env : dict [str , Any ] | None = None ,
116120 exec_after_start : str | list [str ] | None = None ,
117121 check : Callable [[ServiceContainer ], bool ] | None = None ,
118- wait_for_log : str | None = None ,
122+ wait_for_log : str | bytes | None = None ,
119123 timeout : int = 10 ,
120- pause : int = 0.1 ,
124+ pause : float = 0.1 ,
121125 ) -> Generator [ServiceContainer , None , None ]:
122126 if check is None and wait_for_log is None :
123- raise ValueError (f"Must set at least check or wait_for_log" )
127+ msg = "Must set at least check or wait_for_log"
128+ raise ValueError (msg )
124129
125130 name = f"pytest_databases_{ name } "
126131 lock = filelock .FileLock (self ._tmp_path / name ) if self ._is_xdist else contextlib .nullcontext ()
@@ -154,21 +159,24 @@ def run(
154159
155160 started = time .time ()
156161 if wait_for_log :
157- wait_for_log = wait_for_log .encode ()
162+ if isinstance (wait_for_log , str ):
163+ wait_for_log = wait_for_log .encode ()
158164 while time .time () - started < timeout :
159165 if wait_for_log in container .logs ():
160166 break
161167 time .sleep (pause )
162168 else :
163- raise ValueError (f"Service { name !r} failed to come online" )
169+ msg = f"Service { name !r} failed to come online"
170+ raise ValueError (msg )
164171
165172 if check :
166173 while time .time () - started < timeout :
167174 if check (service ) is True :
168175 break
169176 time .sleep (pause )
170177 else :
171- raise ValueError (f"Service { name !r} failed to come online" )
178+ msg = f"Service { name !r} failed to come online"
179+ raise ValueError (msg )
172180
173181 if exec_after_start :
174182 container .exec_run (exec_after_start )
@@ -208,13 +216,12 @@ def _get_base_tmp_path(tmp_path_factory: pytest.TempPathFactory) -> pathlib.Path
208216
209217
210218def _get_ctrl_file (session : pytest .Session ) -> pathlib .Path :
211- tmp_path = _get_base_tmp_path (session .config ._tmp_path_factory )
219+ tmp_path = _get_base_tmp_path (session .config ._tmp_path_factory ) # type: ignore[attr-defined]
212220 return tmp_path / "ctrl"
213221
214222
215223@pytest .hookimpl (wrapper = True )
216- def pytest_sessionfinish (session : pytest .Session , exitstatus ):
217- """Insert teardown that you want to occur only once here"""
224+ def pytest_sessionfinish (session : pytest .Session , exitstatus : int ) -> Generator [Any , Any , Any ]:
218225 try :
219226 return (yield )
220227 finally :
0 commit comments