diff --git a/core/testcontainers/core/docker_client.py b/core/testcontainers/core/docker_client.py index 52785253..07c7ef53 100644 --- a/core/testcontainers/core/docker_client.py +++ b/core/testcontainers/core/docker_client.py @@ -151,7 +151,7 @@ def find_host_network(self) -> Optional[str]: except ipaddress.AddressValueError: continue if docker_host in subnet: - return cast(str, network.name) + return cast("str", network.name) except (ipaddress.AddressValueError, OSError): pass return None @@ -163,7 +163,7 @@ def port(self, container_id: str, port: int) -> str: port_mappings = self.client.api.port(container_id, port) if not port_mappings: raise ConnectionError(f"Port mapping for container {container_id} and port {port} is not available") - return cast(str, port_mappings[0]["HostPort"]) + return cast("str", port_mappings[0]["HostPort"]) def get_container(self, container_id: str) -> dict[str, Any]: """ @@ -172,7 +172,7 @@ def get_container(self, container_id: str) -> dict[str, Any]: containers = self.client.api.containers(filters={"id": container_id}) if not containers: raise RuntimeError(f"Could not get container with id {container_id}") - return cast(dict[str, Any], containers[0]) + return cast("dict[str, Any]", containers[0]) def bridge_ip(self, container_id: str) -> str: """ @@ -241,7 +241,7 @@ def host(self) -> str: hostname = url.hostname if not hostname or (hostname == "localnpipe" and utils.is_windows()): return "localhost" - return cast(str, url.hostname) + return cast("str", url.hostname) if utils.inside_container() and ("unix" in url.scheme or "npipe" in url.scheme): ip_address = utils.default_gateway_ip() if ip_address: @@ -257,7 +257,7 @@ def login(self, auth_config: DockerAuthInfo) -> None: def client_networks_create(self, name: str, param: dict[str, Any]) -> dict[str, Any]: labels = create_labels("", param.get("labels")) - return cast(dict[str, Any], self.client.networks.create(name, **{**param, "labels": labels})) + return cast("dict[str, Any]", self.client.networks.create(name, **{**param, "labels": labels})) def get_docker_host() -> Optional[str]: diff --git a/core/tests/test_core_registry.py b/core/tests/test_core_registry.py index 384b0669..36e4730f 100644 --- a/core/tests/test_core_registry.py +++ b/core/tests/test_core_registry.py @@ -18,8 +18,13 @@ from testcontainers.core.waiting_utils import wait_container_is_ready from testcontainers.registry import DockerRegistryContainer +from testcontainers.core.utils import is_mac +@pytest.mark.skipif( + is_mac(), + reason="Docker Desktop on macOS does not support insecure private registries without daemon reconfiguration", +) def test_missing_on_private_registry(monkeypatch): username = "user" password = "pass" @@ -41,6 +46,10 @@ def test_missing_on_private_registry(monkeypatch): wait_container_is_ready(test_container) +@pytest.mark.skipif( + is_mac(), + reason="Docker Desktop on macOS does not support local insecure registries over HTTP without modifying daemon settings", +) @pytest.mark.parametrize( "image,tag,username,password", [ diff --git a/core/tests/test_docker_in_docker.py b/core/tests/test_docker_in_docker.py index b07f80e9..02b8e1fc 100644 --- a/core/tests/test_docker_in_docker.py +++ b/core/tests/test_docker_in_docker.py @@ -15,6 +15,7 @@ from testcontainers.core.container import DockerContainer from testcontainers.core.docker_client import DockerClient, LOGGER from testcontainers.core.utils import inside_container +from testcontainers.core.utils import is_mac from testcontainers.core.waiting_utils import wait_for_logs @@ -36,6 +37,7 @@ def _wait_for_dind_return_ip(client, dind): return docker_host_ip +@pytest.mark.skipif(is_mac(), reason="Docker socket forwarding (socat) is unsupported on Docker Desktop for macOS") def test_wait_for_logs_docker_in_docker(): # real dind isn't possible (AFAIK) in CI # 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(): not_really_dind.remove() +@pytest.mark.skipif( + is_mac(), reason="Bridge networking and Docker socket forwarding are not supported on Docker Desktop for macOS" +) def test_dind_inherits_network(): client = DockerClient() try: @@ -158,6 +163,9 @@ def test_find_host_network_in_dood() -> None: assert DockerClient().find_host_network() == os.environ[EXPECTED_NETWORK_VAR] +@pytest.mark.skipif( + is_mac(), reason="Docker socket mounting and container networking do not work reliably on Docker Desktop for macOS" +) @pytest.mark.skipif(not Path(tcc.ryuk_docker_socket).exists(), reason="No docker socket available") def test_dood(python_testcontainer_image: str) -> None: """ diff --git a/core/tests/test_ryuk.py b/core/tests/test_ryuk.py index 5d6b208a..76556d4f 100644 --- a/core/tests/test_ryuk.py +++ b/core/tests/test_ryuk.py @@ -8,9 +8,14 @@ from testcontainers.core.config import testcontainers_config from testcontainers.core.container import Reaper from testcontainers.core.container import DockerContainer +from testcontainers.core.utils import is_mac from testcontainers.core.waiting_utils import wait_for_logs +@pytest.mark.skipif( + is_mac(), + reason="Ryuk container reaping is unreliable on Docker Desktop for macOS due to VM-based container lifecycle handling", +) @pytest.mark.inside_docker_check def test_wait_for_reaper(monkeypatch: MonkeyPatch): Reaper.delete_instance() @@ -41,6 +46,9 @@ def test_wait_for_reaper(monkeypatch: MonkeyPatch): Reaper.delete_instance() +@pytest.mark.skipif( + is_mac(), reason="Ryuk disabling behavior is unreliable on Docker Desktop for macOS due to Docker socket emulation" +) @pytest.mark.inside_docker_check def test_container_without_ryuk(monkeypatch: MonkeyPatch): Reaper.delete_instance() diff --git a/poetry.lock b/poetry.lock index 4930fa8c..563589b6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "alabaster" @@ -1908,7 +1908,7 @@ description = "Python DBI driver for DB2 (LUW, zOS, i5) and IDS" optional = true python-versions = "*" groups = ["main"] -markers = "extra == \"db2\"" +markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and extra == \"db2\"" files = [ {file = "ibm_db-3.2.3-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:3399466141c29704f4e8ba709a67ba27ab413239c0244c3c4510126e946ff603"}, {file = "ibm_db-3.2.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e12ff6426d4f718e1ff6615e64a2880bd570826f19a031c82dbf296714cafd7d"}, @@ -1955,7 +1955,7 @@ description = "SQLAlchemy support for IBM Data Servers" optional = true python-versions = "*" groups = ["main"] -markers = "extra == \"db2\"" +markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and extra == \"db2\"" files = [ {file = "ibm_db_sa-0.4.1-py3-none-any.whl", hash = "sha256:49926ba9799e6ebd9ddd847141537c83d179ecf32fe24b7e997ac4614d3f616a"}, {file = "ibm_db_sa-0.4.1.tar.gz", hash = "sha256:a46df130a3681646490925cf4e1bca12b46283f71eea39b70b4f9a56e95341ac"}, @@ -6157,4 +6157,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "ffdbe7b233214e09e1b586e0bf6145e00621fa83d7680c083aa02cf2a8609550" +content-hash = "e17b2d64a82b0929e19aa488550d2159c713979a3145fdfe103c62cd486f79fc" diff --git a/pyproject.toml b/pyproject.toml index 70df36b7..bc55e7f7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -118,7 +118,7 @@ httpx = { version = "*", optional = true } azure-cosmos = { version = "*", optional = true } cryptography = { version = "*", optional = true } trino = { version = "*", optional = true } -ibm_db_sa = { version = "*", optional = true } +ibm_db_sa = { version = "*", optional = true, markers = "platform_machine != 'aarch64' and platform_machine != 'arm64'" } [tool.poetry.extras] arangodb = ["python-arango"]