From bd5d8307097d6dad0bd452cd279dbe3a55661447 Mon Sep 17 00:00:00 2001 From: rhoban Date: Thu, 3 Apr 2025 12:49:29 -0400 Subject: [PATCH 1/4] DockerContainer initializer to accept its private members as kwargs --- core/testcontainers/core/container.py | 40 +++++++++++++++++++++++++-- core/tests/test_container.py | 21 ++++++++++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/core/testcontainers/core/container.py b/core/testcontainers/core/container.py index 74f7828e..705c0a07 100644 --- a/core/testcontainers/core/container.py +++ b/core/testcontainers/core/container.py @@ -28,6 +28,18 @@ class DockerContainer: """ Basic container object to spin up Docker instances. + Args: + image: The name of the image to start. + docker_client_kw: Dictionary with arguments that will be passed to the + docker.DockerClient init. + command: Optional execution command for the container. + name: Optional name for the container. + ports: Ports to be exposed by the container. The port number will be + automatically assigned on the host, use + :code:`get_exposed_port(PORT)` method to get the port number on the host. + volumes: Volumes to mount into the container. Each entry should be a tuple with + three values: host path, container path and. mode (default 'ro'). + .. doctest:: >>> from testcontainers.core.container import DockerContainer @@ -41,18 +53,40 @@ def __init__( self, image: str, docker_client_kw: Optional[dict] = None, + command: Optional[str] = None, + env: Optional[dict[str, str]] = None, + name: Optional[str] = None, + ports: Optional[list[int]] = None, + volumes: Optional[list[tuple[str, str, str]]] = None, + network: Optional[Network] = None, + network_aliases: Optional[list[str]] = None, **kwargs, ) -> None: - self.env = {} + self.env = env or {} + self.ports = {} + if ports: + self.with_exposed_ports(*ports) + self.volumes = {} + if volumes: + for vol in volumes: + self.with_volume_mapping(*vol) + self.image = image self._docker = DockerClient(**(docker_client_kw or {})) self._container = None - self._command = None - self._name = None + self._command = command + self._name = name + self._network: Optional[Network] = None + if network is not None: + self.with_network(network) + self._network_aliases: Optional[list[str]] = None + if network_aliases: + self.with_network_aliases(*network_aliases) + self._kwargs = kwargs def with_env(self, key: str, value: str) -> Self: diff --git a/core/tests/test_container.py b/core/tests/test_container.py index e1e7cff7..bb7dd059 100644 --- a/core/tests/test_container.py +++ b/core/tests/test_container.py @@ -75,3 +75,24 @@ def test_get_exposed_port_original(container: DockerContainer, monkeypatch: pyte monkeypatch.setattr(client, "get_connection_mode", lambda: ConnectionMode.bridge_ip) assert container.get_exposed_port(8080) == 8080 + + +@pytest.mark.parametrize( + "init_attr,init_value,class_attr,stored_value", + [ + ("command", "ps", "_command", "ps"), + ("env", {"e1": "v1"}, "env", {"e1": "v1"}), + ("name", "foo-bar", "_name", "foo-bar"), + ("ports", [22, 80], "ports", {22: None, 80: None}), + ( + "volumes", + [("/tmp", "/tmp2", "ro")], + "volumes", + {"/tmp": {"bind": "/tmp2", "mode": "ro"}}, + ), + ], +) +def test_attribute(init_attr, init_value, class_attr, stored_value): + """Test that the attributes set through the __init__ function are properly stored.""" + with DockerContainer("ubuntu", **{init_attr: init_value}) as container: + assert getattr(container, class_attr) == stored_value From 55c6661ffb213eda06f6d47e3264cd4720b6db40 Mon Sep 17 00:00:00 2001 From: rhoban Date: Mon, 5 May 2025 22:40:20 -0400 Subject: [PATCH 2/4] Update docs --- core/testcontainers/core/container.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/testcontainers/core/container.py b/core/testcontainers/core/container.py index 705c0a07..b7979a61 100644 --- a/core/testcontainers/core/container.py +++ b/core/testcontainers/core/container.py @@ -39,6 +39,8 @@ class DockerContainer: :code:`get_exposed_port(PORT)` method to get the port number on the host. volumes: Volumes to mount into the container. Each entry should be a tuple with three values: host path, container path and. mode (default 'ro'). + network: Optional network to connect the container to. + network_aliases: Optional list of aliases for the container in the network. .. doctest:: From 80270e5b4dfe331add53b28d6ee709231c1b254d Mon Sep 17 00:00:00 2001 From: David Ankin Date: Sun, 18 May 2025 00:31:41 -0400 Subject: [PATCH 3/4] fix tests --- core/tests/compose_fixtures/port_multiple/compose.yaml | 2 ++ core/tests/test_utils.py | 1 + 2 files changed, 3 insertions(+) diff --git a/core/tests/compose_fixtures/port_multiple/compose.yaml b/core/tests/compose_fixtures/port_multiple/compose.yaml index e8e147bb..662079f5 100644 --- a/core/tests/compose_fixtures/port_multiple/compose.yaml +++ b/core/tests/compose_fixtures/port_multiple/compose.yaml @@ -6,6 +6,7 @@ services: - '81' - '82' - target: 80 + published: "5000-5999" host_ip: 127.0.0.1 protocol: tcp command: @@ -18,6 +19,7 @@ services: init: true ports: - target: 80 + published: "5000-5999" host_ip: 127.0.0.1 protocol: tcp command: diff --git a/core/tests/test_utils.py b/core/tests/test_utils.py index 4c240ed4..e811ee39 100644 --- a/core/tests/test_utils.py +++ b/core/tests/test_utils.py @@ -33,6 +33,7 @@ def test_is_windows(monkeypatch: MonkeyPatch) -> None: def test_is_arm(monkeypatch: MonkeyPatch) -> None: + monkeypatch.setattr("platform.machine", lambda: "x86_64") assert not utils.is_arm() monkeypatch.setattr("platform.machine", lambda: "arm64") assert utils.is_arm() From 711ec78bd008e074abce0de6e9947144ebb9fc9d Mon Sep 17 00:00:00 2001 From: David Ankin Date: Sun, 18 May 2025 01:06:02 -0400 Subject: [PATCH 4/4] fix docs - we need to publish network docs too now --- core/README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/README.rst b/core/README.rst index 1461ba7d..5176ce07 100644 --- a/core/README.rst +++ b/core/README.rst @@ -18,6 +18,8 @@ Testcontainers Core .. autoclass:: testcontainers.core.generic.DbContainer +.. autoclass:: testcontainers.core.network.Network + .. raw:: html