Skip to content

Commit 9e9ede2

Browse files
committed
fix: resolve StopIteration error in BigQuery emulator fixture
Fixes a RuntimeError caused by StopIteration being raised inside a generator function when Docker container ports cannot be found. Changes: - Move container.reload() to the start of retry loop to ensure fresh port bindings are available - Replace unsafe next() call with explicit dict.get() for exact-key port matching (e.g., "9050/tcp" instead of startswith pattern) - Add descriptive error message showing available ports when lookup fails - Use RuntimeError instead of allowing StopIteration to propagate This fix ensures all database services (including BigQuery emulator) can properly start their Docker containers and expose ports reliably. Resolves issue where BigQuery tests failed with: "RuntimeError: generator raised StopIteration"
1 parent cf7b9fe commit 9e9ede2

File tree

2 files changed

+14
-7
lines changed

2 files changed

+14
-7
lines changed

src/pytest_databases/_service.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010

1111
import filelock
1212
import pytest
13-
from docker import DockerClient
1413
from docker.errors import APIError, ImageNotFound
1514
from typing_extensions import Self
1615

16+
from docker import DockerClient
1717
from pytest_databases.helpers import get_xdist_worker_id
1818
from pytest_databases.types import ServiceContainer
1919

@@ -176,17 +176,24 @@ def run(
176176
# spins it up and the metadata becomes available, so we're redoing the
177177
# check with a small incremental backup here
178178
for i in range(10):
179+
container.reload()
179180
if any(v for v in container.ports.values()):
180181
break
181-
container.reload()
182182
time.sleep(0.1 + (i / 10))
183183
else:
184184
msg = f"Service {name!r} failed to create container"
185185
raise ValueError(msg)
186186

187-
host_port = int(
188-
container.ports[next(k for k in container.ports if k.startswith(str(container_port)))][0]["HostPort"]
189-
)
187+
# Try TCP first (most common), fallback to UDP
188+
binding = container.ports.get(f"{container_port}/tcp") or container.ports.get(f"{container_port}/udp")
189+
if not binding:
190+
msg = (
191+
f"Container port {container_port} not found in exposed ports. "
192+
f"Available ports: {list(container.ports.keys())}"
193+
)
194+
raise RuntimeError(msg)
195+
196+
host_port = int(binding[0]["HostPort"])
190197
service = ServiceContainer(
191198
host=container_host,
192199
port=host_port,

tests/test_redis.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ def test_two({redis_compatible_service}: RedisService) -> None:
9595
assert not client.get("one")
9696
client.set("one", "1")
9797
assert client.get("one") == b"1"
98-
99-
98+
99+
100100
def test_use_same_db({redis_compatible_service}: RedisService) -> None:
101101
client_0 = redis.Redis(host={redis_compatible_service}.host, port={redis_compatible_service}.port, db=0)
102102
client_1 = redis.Redis(host={redis_compatible_service}.host, port={redis_compatible_service}.port, db=1)

0 commit comments

Comments
 (0)