Skip to content

Commit 23919a3

Browse files
committed
Merge branch 'main' into wait_for_healthcheck
2 parents 6287732 + f467c84 commit 23919a3

File tree

159 files changed

+11067
-96
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

159 files changed

+11067
-96
lines changed
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "4.10.0"
2+
".": "4.11.0"
33
}

.github/workflows/ci-core.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Contrinuous Integration for the core package
1+
# Continuous Integration for the core package
22

33
name: core
44

@@ -25,6 +25,8 @@ jobs:
2525
run: poetry install --all-extras
2626
- name: Run twine check
2727
run: poetry build && poetry run twine check dist/*.tar.gz
28+
- name: Set up Docker
29+
uses: docker/setup-docker-action@v4
2830
- name: Run tests
2931
run: make core/tests
3032
- name: Rename coverage file

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,6 @@ venv
7272
.python-version
7373
.env
7474
.github-token
75+
76+
# docs build
77+
site/

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,30 @@
11
# Changelog
22

3+
## [4.11.0](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.10.0...testcontainers-v4.11.0) (2025-06-15)
4+
5+
6+
### Features
7+
8+
* **core:** Protocol support for container port bind and expose ([#690](https://github.com/testcontainers/testcontainers-python/issues/690)) ([a0d4317](https://github.com/testcontainers/testcontainers-python/commit/a0d4317643005dde4f344eccbfc56c062e83bf05))
9+
* DockerContainer initializer to accept its private members as kwargs ([#809](https://github.com/testcontainers/testcontainers-python/issues/809)) ([e7feb53](https://github.com/testcontainers/testcontainers-python/commit/e7feb53fe532b6d32d5d0c5a5d517249f8e7de50))
10+
11+
12+
### Bug Fixes
13+
14+
* **compose:** use provided docker command instead of default ([#785](https://github.com/testcontainers/testcontainers-python/issues/785)) ([0ae704a](https://github.com/testcontainers/testcontainers-python/commit/0ae704a24de440b715d5f3c11eaa4f18ccd437b5))
15+
* **core:** Add kwargs to image build ([#708](https://github.com/testcontainers/testcontainers-python/issues/708)) ([cc02f94](https://github.com/testcontainers/testcontainers-python/commit/cc02f9444b41efa62836b21210b07aee1da94d0b))
16+
* **core:** change with_command type to include list of strings ([#789](https://github.com/testcontainers/testcontainers-python/issues/789)) ([f7c29cb](https://github.com/testcontainers/testcontainers-python/commit/f7c29cb913e4d42d535783c3aa0f3566d4e543bf))
17+
* **core:** Determine docker socket for rootless docker ([#779](https://github.com/testcontainers/testcontainers-python/issues/779)) ([6817582](https://github.com/testcontainers/testcontainers-python/commit/6817582bf67ed36448b69019ab897c50ae80e7e1))
18+
* **core:** Typing in docker_client ([#702](https://github.com/testcontainers/testcontainers-python/issues/702)) ([e8bf224](https://github.com/testcontainers/testcontainers-python/commit/e8bf2244c7210e31b34e5fecf2602fdd1b8c0834))
19+
* **core:** Typing in generic + network ([#700](https://github.com/testcontainers/testcontainers-python/issues/700)) ([2061912](https://github.com/testcontainers/testcontainers-python/commit/2061912e67705be801136f349f372f542a1f262f))
20+
* **core:** Typing in version ([#701](https://github.com/testcontainers/testcontainers-python/issues/701)) ([9dc2a02](https://github.com/testcontainers/testcontainers-python/commit/9dc2a02ca9b9ffbaacfd7de79ec9f78175758ec0))
21+
* **core:** wait in test core registry ([#812](https://github.com/testcontainers/testcontainers-python/issues/812)) ([b574c0e](https://github.com/testcontainers/testcontainers-python/commit/b574c0e0a11d57c8c56aef448292f8c2fc233078))
22+
* **modules:** fix cosmosdb failure ([#827](https://github.com/testcontainers/testcontainers-python/issues/827)) ([dafcbed](https://github.com/testcontainers/testcontainers-python/commit/dafcbed7608e857bebcdd0b4638bec27abadc693))
23+
* **modules:** update chroma version ([#826](https://github.com/testcontainers/testcontainers-python/issues/826)) ([b7d41dd](https://github.com/testcontainers/testcontainers-python/commit/b7d41ddc5742dd380b6e01c712a02b044a64cbb3))
24+
* **rabbitmq:** correct pika pypi reference ([#817](https://github.com/testcontainers/testcontainers-python/issues/817)) ([e90d308](https://github.com/testcontainers/testcontainers-python/commit/e90d30826fb7d7cf3cc7db39a86465d448aaa6e0))
25+
* **registry:** module typed ([#811](https://github.com/testcontainers/testcontainers-python/issues/811)) ([6b11268](https://github.com/testcontainers/testcontainers-python/commit/6b1126884c82529a93bd55030374d322dd0870bc))
26+
* use connection mode override function in config ([#775](https://github.com/testcontainers/testcontainers-python/issues/775)) ([ab2a1ab](https://github.com/testcontainers/testcontainers-python/commit/ab2a1abd957ffb35719f673a7674df83287f1545)), closes [#774](https://github.com/testcontainers/testcontainers-python/issues/774)
27+
328
## [4.10.0](https://github.com/testcontainers/testcontainers-python/compare/testcontainers-v4.9.2...testcontainers-v4.10.0) (2025-04-02)
429

530

Dockerfile.docs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM python:3.11-slim
2+
3+
RUN pip install poetry
4+
5+
WORKDIR /docs

Makefile

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,39 @@ clean-all: clean ## Remove all generated files and reset the local virtual envir
6868
.PHONY: help
6969
help: ## Display command usage
7070
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
71+
72+
## --------------------------------------
73+
74+
DOCS_CONTAINER=mkdocs-container
75+
DOCS_IMAGE=mkdocs-poetry
76+
DOCS_DOCKERFILE := Dockerfile.docs
77+
78+
.PHONY: clean-docs
79+
clean-docs:
80+
@echo "Destroying docs"
81+
@if docker ps -a --format '{{.Names}}' | grep -q '^$(DOCS_CONTAINER)$$'; then \
82+
docker rm -f $(DOCS_CONTAINER); \
83+
fi
84+
@if docker images -q $(DOCS_IMAGE) | grep -q .; then \
85+
docker rmi $(DOCS_IMAGE); \
86+
fi
87+
88+
.PHONY: docs-ensure-image
89+
docs-ensure-image:
90+
@if [ -z "$$(docker images -q $(DOCS_IMAGE))" ]; then \
91+
docker build -f $(DOCS_DOCKERFILE) -t $(DOCS_IMAGE) . ; \
92+
fi
93+
94+
.PHONY: serve-docs
95+
serve-docs: docs-ensure-image
96+
docker run --rm --name $(DOCS_CONTAINER) -it -p 8000:8000 \
97+
-v $(PWD):/testcontainers-go \
98+
-w /testcontainers-go \
99+
$(DOCS_IMAGE) bash -c "\
100+
cd docs && poetry install --no-root && \
101+
poetry run mkdocs serve -f ../mkdocs.yml -a 0.0.0.0:8000"
102+
103+
# Needed if dependencies are added to the docs site
104+
.PHONY: export-docs-deps
105+
export-docs-deps:
106+
cd docs && poetry export --without-hashes --output requirements.txt

core/testcontainers/core/docker_client.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ def find_host_network(self) -> Optional[str]:
151151
except ipaddress.AddressValueError:
152152
continue
153153
if docker_host in subnet:
154-
return cast(str, network.name)
154+
return cast("str", network.name)
155155
except (ipaddress.AddressValueError, OSError):
156156
pass
157157
return None
@@ -163,7 +163,7 @@ def port(self, container_id: str, port: int) -> str:
163163
port_mappings = self.client.api.port(container_id, port)
164164
if not port_mappings:
165165
raise ConnectionError(f"Port mapping for container {container_id} and port {port} is not available")
166-
return cast(str, port_mappings[0]["HostPort"])
166+
return cast("str", port_mappings[0]["HostPort"])
167167

168168
def get_container(self, container_id: str) -> dict[str, Any]:
169169
"""
@@ -172,7 +172,7 @@ def get_container(self, container_id: str) -> dict[str, Any]:
172172
containers = self.client.api.containers(filters={"id": container_id})
173173
if not containers:
174174
raise RuntimeError(f"Could not get container with id {container_id}")
175-
return cast(dict[str, Any], containers[0])
175+
return cast("dict[str, Any]", containers[0])
176176

177177
def bridge_ip(self, container_id: str) -> str:
178178
"""
@@ -241,7 +241,7 @@ def host(self) -> str:
241241
hostname = url.hostname
242242
if not hostname or (hostname == "localnpipe" and utils.is_windows()):
243243
return "localhost"
244-
return cast(str, url.hostname)
244+
return cast("str", url.hostname)
245245
if utils.inside_container() and ("unix" in url.scheme or "npipe" in url.scheme):
246246
ip_address = utils.default_gateway_ip()
247247
if ip_address:
@@ -257,7 +257,7 @@ def login(self, auth_config: DockerAuthInfo) -> None:
257257

258258
def client_networks_create(self, name: str, param: dict[str, Any]) -> dict[str, Any]:
259259
labels = create_labels("", param.get("labels"))
260-
return cast(dict[str, Any], self.client.networks.create(name, **{**param, "labels": labels}))
260+
return cast("dict[str, Any]", self.client.networks.create(name, **{**param, "labels": labels}))
261261

262262

263263
def get_docker_host() -> Optional[str]:

core/testcontainers/core/utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313

1414
def setup_logger(name: str) -> logging.Logger:
1515
logger = logging.getLogger(name)
16-
logger.setLevel(logging.INFO)
17-
handler = logging.StreamHandler()
18-
handler.setLevel(logging.INFO)
19-
logger.addHandler(handler)
16+
# logger.setLevel(logging.INFO)
17+
# handler = logging.StreamHandler()
18+
# handler.setLevel(logging.INFO)
19+
# logger.addHandler(handler)
2020
return logger
2121

2222

core/tests/test_core_registry.py

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,16 @@
1515
from testcontainers.core.config import testcontainers_config
1616
from testcontainers.core.container import DockerContainer
1717
from testcontainers.core.docker_client import DockerClient
18-
from testcontainers.core.waiting_utils import wait_container_is_ready
18+
from testcontainers.core.waiting_utils import wait_for_logs
1919

2020
from testcontainers.registry import DockerRegistryContainer
21+
from testcontainers.core.utils import is_mac
2122

2223

24+
@pytest.mark.skipif(
25+
is_mac(),
26+
reason="Docker Desktop on macOS does not support insecure private registries without daemon reconfiguration",
27+
)
2328
def test_missing_on_private_registry(monkeypatch):
2429
username = "user"
2530
password = "pass"
@@ -38,18 +43,22 @@ def test_missing_on_private_registry(monkeypatch):
3843
with pytest.raises(NotFound):
3944
# Test a container with image from private registry
4045
with DockerContainer(f"{registry_url}/{image}:{tag}") as test_container:
41-
wait_container_is_ready(test_container)
46+
wait_for_logs(test_container, "Hello from Docker!")
4247

4348

49+
@pytest.mark.skipif(
50+
is_mac(),
51+
reason="Docker Desktop on macOS does not support local insecure registries over HTTP without modifying daemon settings",
52+
)
4453
@pytest.mark.parametrize(
45-
"image,tag,username,password",
54+
"image,tag,username,password,expected_output",
4655
[
47-
("nginx", "test", "user", "pass"),
48-
("hello-world", "latest", "new_user", "new_pass"),
49-
("alpine", "3.12", None, None),
56+
("nginx", "test", "user", "pass", "start worker processes"),
57+
("hello-world", "latest", "new_user", "new_pass", "Hello from Docker!"),
58+
("alpine", "3.12", None, None, ""),
5059
],
5160
)
52-
def test_with_private_registry(image, tag, username, password, monkeypatch):
61+
def test_with_private_registry(image, tag, username, password, expected_output, monkeypatch):
5362
client = DockerClient().client
5463

5564
with DockerRegistryContainer(username=username, password=password) as registry:
@@ -76,7 +85,7 @@ def test_with_private_registry(image, tag, username, password, monkeypatch):
7685

7786
# Test a container with image from private registry
7887
with DockerContainer(f"{registry_url}/{image}:{tag}") as test_container:
79-
wait_container_is_ready(test_container)
88+
wait_for_logs(test_container, expected_output)
8089

8190
# cleanup
8291
client.images.remove(f"{registry_url}/{image}:{tag}")

core/tests/test_docker_in_docker.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from testcontainers.core.container import DockerContainer
1616
from testcontainers.core.docker_client import DockerClient, LOGGER
1717
from testcontainers.core.utils import inside_container
18+
from testcontainers.core.utils import is_mac
1819
from testcontainers.core.waiting_utils import wait_for_logs
1920

2021

@@ -36,6 +37,7 @@ def _wait_for_dind_return_ip(client, dind):
3637
return docker_host_ip
3738

3839

40+
@pytest.mark.skipif(is_mac(), reason="Docker socket forwarding (socat) is unsupported on Docker Desktop for macOS")
3941
def test_wait_for_logs_docker_in_docker():
4042
# real dind isn't possible (AFAIK) in CI
4143
# forwarding the socket to a container port is at least somewhat the same
@@ -64,6 +66,9 @@ def test_wait_for_logs_docker_in_docker():
6466
not_really_dind.remove()
6567

6668

69+
@pytest.mark.skipif(
70+
is_mac(), reason="Bridge networking and Docker socket forwarding are not supported on Docker Desktop for macOS"
71+
)
6772
def test_dind_inherits_network():
6873
client = DockerClient()
6974
try:
@@ -158,6 +163,9 @@ def test_find_host_network_in_dood() -> None:
158163
assert DockerClient().find_host_network() == os.environ[EXPECTED_NETWORK_VAR]
159164

160165

166+
@pytest.mark.skipif(
167+
is_mac(), reason="Docker socket mounting and container networking do not work reliably on Docker Desktop for macOS"
168+
)
161169
@pytest.mark.skipif(not Path(tcc.ryuk_docker_socket).exists(), reason="No docker socket available")
162170
def test_dood(python_testcontainer_image: str) -> None:
163171
"""

0 commit comments

Comments
 (0)