Skip to content

Commit 4152dd4

Browse files
authored
fix: resolve StopIteration error in BigQuery emulator fixture (#99)
Fixed a `RuntimeError: generator raised StopIteration` that prevented the BigQuery emulator fixture from starting Docker containers. This issue affected BigQuery tests and could potentially impact other database services under certain conditions.
1 parent cf7b9fe commit 4152dd4

4 files changed

Lines changed: 1402 additions & 1086 deletions

File tree

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ exclude: "^docs/conf.py"
22

33
repos:
44
- repo: https://github.com/pre-commit/pre-commit-hooks
5-
rev: v5.0.0
5+
rev: v6.0.0
66
hooks:
77
- id: trailing-whitespace
88
- id: check-added-large-files
@@ -19,7 +19,7 @@ repos:
1919

2020
# Ruff replaces black, flake8, autoflake and isort
2121
- repo: https://github.com/charliermarsh/ruff-pre-commit
22-
rev: "v0.11.11" # make sure this is always consistent with hatch configs
22+
rev: "v0.13.3" # make sure this is always consistent with hatch configs
2323
hooks:
2424
- id: ruff
2525
args: [--config, ./pyproject.toml]

src/pytest_databases/_service.py

Lines changed: 21 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

@@ -139,6 +139,7 @@ def run(
139139
shm_size: int | None = None,
140140
mem_limit: str | None = None,
141141
platform: str | None = None,
142+
protocol: str = "tcp",
142143
) -> Generator[ServiceContainer, None, None]:
143144
if check is None and wait_for_log is None:
144145
msg = "Must set at least check or wait_for_log"
@@ -176,17 +177,32 @@ def run(
176177
# spins it up and the metadata becomes available, so we're redoing the
177178
# check with a small incremental backup here
178179
for i in range(10):
180+
container.reload()
179181
if any(v for v in container.ports.values()):
180182
break
181-
container.reload()
182183
time.sleep(0.1 + (i / 10))
183184
else:
184185
msg = f"Service {name!r} failed to create container"
185186
raise ValueError(msg)
186187

187-
host_port = int(
188-
container.ports[next(k for k in container.ports if k.startswith(str(container_port)))][0]["HostPort"]
189-
)
188+
# Get port binding based on protocol configuration
189+
binding = None
190+
if protocol == "both":
191+
binding = container.ports.get(f"{container_port}/tcp") or container.ports.get(f"{container_port}/udp")
192+
elif protocol in {"tcp", "udp"}:
193+
binding = container.ports.get(f"{container_port}/{protocol}")
194+
else:
195+
msg = f"Invalid protocol '{protocol}'. Must be 'tcp', 'udp', or 'both'."
196+
raise ValueError(msg)
197+
198+
if not binding:
199+
msg = (
200+
f"Container port {container_port}/{protocol} not found in exposed ports. "
201+
f"Available ports: {list(container.ports.keys())}"
202+
)
203+
raise RuntimeError(msg)
204+
205+
host_port = int(binding[0]["HostPort"])
190206
service = ServiceContainer(
191207
host=container_host,
192208
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)