Skip to content

Commit 16fb2b2

Browse files
chore: Update pyproject and tests to support Mac's/arm local development (#814)
I want to help contribute to testcontainers-python but issues getting the local environment running. Starting off with fixing the install + test suite so myself and other people on Mac can get up and running faster. Manual testing done: This branch was tested on a few different Mac machines the and a Linux VM (still on arm). `make install` and `make tests` checked in all envs, I also checked docs, build, and cleans on the Linux VM and a M2 mac. Notes: * Poetry markers aren't bullet proof, but works for ibm so it's good enough for now, else we'd need a more complex install and test build scripts (for dind tests) which I played around with but ended up removing to keep the PR smaller and less complex. * Skipping arm + mac specific tests in the test suite, these are testing either features that Macs don't have or the community module doesn't actually support macs. For the sake of contributors this shouldn't matter, the CI will still be testing everything fully. * Mac skip reasons given: I'm not deeply familiar with these community packages or the menewsha of mac docker vs other OS dockers. There might be better explanations for why it needed to be skipped. Ticket: #813 --------- Co-authored-by: David Ankin <[email protected]>
1 parent b7d41dd commit 16fb2b2

File tree

6 files changed

+35
-10
lines changed

6 files changed

+35
-10
lines changed

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/tests/test_core_registry.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
from testcontainers.core.waiting_utils import wait_container_is_ready
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"
@@ -41,6 +46,10 @@ def test_missing_on_private_registry(monkeypatch):
4146
wait_container_is_ready(test_container)
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(
4554
"image,tag,username,password",
4655
[

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
"""

core/tests/test_ryuk.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,14 @@
88
from testcontainers.core.config import testcontainers_config
99
from testcontainers.core.container import Reaper
1010
from testcontainers.core.container import DockerContainer
11+
from testcontainers.core.utils import is_mac
1112
from testcontainers.core.waiting_utils import wait_for_logs
1213

1314

15+
@pytest.mark.skipif(
16+
is_mac(),
17+
reason="Ryuk container reaping is unreliable on Docker Desktop for macOS due to VM-based container lifecycle handling",
18+
)
1419
@pytest.mark.inside_docker_check
1520
def test_wait_for_reaper(monkeypatch: MonkeyPatch):
1621
Reaper.delete_instance()
@@ -41,6 +46,9 @@ def test_wait_for_reaper(monkeypatch: MonkeyPatch):
4146
Reaper.delete_instance()
4247

4348

49+
@pytest.mark.skipif(
50+
is_mac(), reason="Ryuk disabling behavior is unreliable on Docker Desktop for macOS due to Docker socket emulation"
51+
)
4452
@pytest.mark.inside_docker_check
4553
def test_container_without_ryuk(monkeypatch: MonkeyPatch):
4654
Reaper.delete_instance()

poetry.lock

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ httpx = { version = "*", optional = true }
118118
azure-cosmos = { version = "*", optional = true }
119119
cryptography = { version = "*", optional = true }
120120
trino = { version = "*", optional = true }
121-
ibm_db_sa = { version = "*", optional = true }
121+
ibm_db_sa = { version = "*", optional = true, markers = "platform_machine != 'aarch64' and platform_machine != 'arm64'" }
122122

123123
[tool.poetry.extras]
124124
arangodb = ["python-arango"]

0 commit comments

Comments
 (0)