2929from . import schema , schema_adapted , schema_advanced , schema_external , schema_simple
3030from . import schema_uuid as schema_uuid_module
3131
32-
3332# Configure logging for container management
3433logger = logging .getLogger (__name__ )
3534
@@ -46,8 +45,6 @@ def pytest_configure(config):
4645 pass
4746
4847
49-
50-
5148# Global container registry for cleanup
5249_active_containers = set ()
5350_docker_client = None
@@ -64,18 +61,24 @@ def _get_docker_client():
6461def _cleanup_containers ():
6562 """Clean up any remaining containers"""
6663 if _active_containers :
67- logger .info (f"Emergency cleanup: { len (_active_containers )} containers to clean up" )
64+ logger .info (
65+ f"Emergency cleanup: { len (_active_containers )} containers to clean up"
66+ )
6867 try :
6968 client = _get_docker_client ()
7069 for container_id in list (_active_containers ):
7170 try :
7271 container = client .containers .get (container_id )
7372 container .remove (force = True )
74- logger .info (f"Emergency cleanup: removed container { container_id [:12 ]} " )
73+ logger .info (
74+ f"Emergency cleanup: removed container { container_id [:12 ]} "
75+ )
7576 except docker .errors .NotFound :
7677 logger .debug (f"Container { container_id [:12 ]} already removed" )
7778 except Exception as e :
78- logger .error (f"Error cleaning up container { container_id [:12 ]} : { e } " )
79+ logger .error (
80+ f"Error cleaning up container { container_id [:12 ]} : { e } "
81+ )
7982 finally :
8083 _active_containers .discard (container_id )
8184 except Exception as e :
@@ -102,7 +105,9 @@ def _unregister_container(container):
102105
103106def _signal_handler (signum , frame ):
104107 """Handle signals to ensure container cleanup"""
105- logger .warning (f"Received signal { signum } , performing emergency container cleanup..." )
108+ logger .warning (
109+ f"Received signal { signum } , performing emergency container cleanup..."
110+ )
106111 _cleanup_containers ()
107112
108113 # Restore default signal handler and re-raise the signal
@@ -115,6 +120,7 @@ def _signal_handler(signum, frame):
115120# In pytest, we'll rely on fixture teardown and atexit handlers primarily
116121try :
117122 import pytest
123+
118124 # If we're here, pytest is available, so only register SIGTERM (for CI/batch scenarios)
119125 signal .signal (signal .SIGTERM , _signal_handler )
120126 # Don't intercept SIGINT (Ctrl+C) to allow pytest's normal cancellation behavior
@@ -150,9 +156,7 @@ def mysql_container(docker_client):
150156 container = docker_client .containers .run (
151157 f"datajoint/mysql:{ mysql_ver } " ,
152158 name = container_name ,
153- environment = {
154- "MYSQL_ROOT_PASSWORD" : "password"
155- },
159+ environment = {"MYSQL_ROOT_PASSWORD" : "password" },
156160 command = "mysqld --default-authentication-plugin=mysql_native_password" ,
157161 ports = {"3306/tcp" : None }, # Let Docker assign random port
158162 detach = True ,
@@ -162,7 +166,7 @@ def mysql_container(docker_client):
162166 "timeout" : 30000000000 , # 30s in nanoseconds
163167 "retries" : 5 ,
164168 "interval" : 15000000000 , # 15s in nanoseconds
165- }
169+ },
166170 )
167171
168172 # Register container for cleanup
@@ -172,7 +176,9 @@ def mysql_container(docker_client):
172176 # Wait for health check
173177 max_wait = 120 # 2 minutes
174178 start_time = time .time ()
175- logger .info (f"Waiting for MySQL container { container_name } to become healthy (max { max_wait } s)" )
179+ logger .info (
180+ f"Waiting for MySQL container { container_name } to become healthy (max { max_wait } s)"
181+ )
176182
177183 while time .time () - start_time < max_wait :
178184 container .reload ()
@@ -182,15 +188,19 @@ def mysql_container(docker_client):
182188 break
183189 time .sleep (2 )
184190 else :
185- logger .error (f"MySQL container { container_name } failed to become healthy within { max_wait } s" )
191+ logger .error (
192+ f"MySQL container { container_name } failed to become healthy within { max_wait } s"
193+ )
186194 container .remove (force = True )
187195 raise RuntimeError ("MySQL container failed to become healthy" )
188196
189197 # Get the mapped port
190198 port_info = container .attrs ["NetworkSettings" ]["Ports" ]["3306/tcp" ]
191199 if port_info :
192200 host_port = port_info [0 ]["HostPort" ]
193- logger .info (f"MySQL container { container_name } is healthy and accessible on localhost:{ host_port } " )
201+ logger .info (
202+ f"MySQL container { container_name } is healthy and accessible on localhost:{ host_port } "
203+ )
194204 else :
195205 raise RuntimeError ("Failed to get MySQL port mapping" )
196206
@@ -223,14 +233,11 @@ def minio_container(docker_client):
223233 container = docker_client .containers .run (
224234 f"minio/minio:{ minio_ver } " ,
225235 name = container_name ,
226- environment = {
227- "MINIO_ACCESS_KEY" : "datajoint" ,
228- "MINIO_SECRET_KEY" : "datajoint"
229- },
230- command = ['server' , '--address' , ':9000' , '/data' ],
236+ environment = {"MINIO_ACCESS_KEY" : "datajoint" , "MINIO_SECRET_KEY" : "datajoint" },
237+ command = ["server" , "--address" , ":9000" , "/data" ],
231238 ports = {"9000/tcp" : None }, # Let Docker assign random port
232239 detach = True ,
233- remove = True
240+ remove = True ,
234241 )
235242
236243 # Register container for cleanup
@@ -250,20 +257,26 @@ def minio_container(docker_client):
250257 minio_url = f"http://localhost:{ host_port } "
251258 max_wait = 60
252259 start_time = time .time ()
253- logger .info (f"Waiting for MinIO container { container_name } to become ready (max { max_wait } s)" )
260+ logger .info (
261+ f"Waiting for MinIO container { container_name } to become ready (max { max_wait } s)"
262+ )
254263
255264 while time .time () - start_time < max_wait :
256265 try :
257266 response = requests .get (f"{ minio_url } /minio/health/live" , timeout = 5 )
258267 if response .status_code == 200 :
259- logger .info (f"MinIO container { container_name } is ready and accessible at { minio_url } " )
268+ logger .info (
269+ f"MinIO container { container_name } is ready and accessible at { minio_url } "
270+ )
260271 break
261272 except requests .exceptions .RequestException :
262273 logger .debug (f"MinIO container { container_name } not ready yet, retrying..." )
263274 pass
264275 time .sleep (2 )
265276 else :
266- logger .error (f"MinIO container { container_name } failed to become ready within { max_wait } s" )
277+ logger .error (
278+ f"MinIO container { container_name } failed to become ready within { max_wait } s"
279+ )
267280 container .remove (force = True )
268281 raise RuntimeError ("MinIO container failed to become ready" )
269282
@@ -336,7 +349,9 @@ def configure_datajoint_for_containers(mysql_container):
336349 os .environ ["DJ_PORT" ] = str (port )
337350
338351 # Verify the environment variables were set
339- logger .info (f"🔧 Environment after setting: DJ_HOST={ os .environ .get ('DJ_HOST' )} , DJ_PORT={ os .environ .get ('DJ_PORT' )} " )
352+ logger .info (
353+ f"🔧 Environment after setting: DJ_HOST={ os .environ .get ('DJ_HOST' )} , DJ_PORT={ os .environ .get ('DJ_PORT' )} "
354+ )
340355
341356 # Also update DataJoint's configuration directly for in-process connections
342357 dj .config ["database.host" ] = host
0 commit comments