From fd21bef9f7ac4cd50848e74d757f93ab94810d83 Mon Sep 17 00:00:00 2001 From: Khushiyant Date: Sun, 9 Mar 2025 17:45:24 +0530 Subject: [PATCH 1/2] feat: add ContainerInfo--object as return object to inspect_container Signed-off-by: Khushiyant --- docker/api/container.py | 39 +++++++++++++++++++++++-- tests/integration/api_container_test.py | 16 ++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/docker/api/container.py b/docker/api/container.py index d1b870f9c..b361d4b22 100644 --- a/docker/api/container.py +++ b/docker/api/container.py @@ -11,6 +11,37 @@ ) +class ContainerInfo: + def __init__(self, info: dict): + self._info = info + + def __repr__(self): + return ( + f"" + ) + + def __getattr__(self, item): + """ + Dynamically fetch any attribute from the underlying dictionary. + This allows direct access to all fields without manually defining them. + """ + try: + return self._info[item] + except KeyError as err: + raise AttributeError( + f"'ContainerInfo' object has no attribute '{item}'" + ) from err + + def __getitem__(self, item): + """ + Optional: If you'd like to access attributes using bracket notation. + """ + return self._info.get(item) + + def get_info(self): + """Returns the entire dictionary for reference if needed""" + return self._info + class ContainerApiMixin: @utils.check_resource('container') def attach(self, container, stdout=True, stderr=True, @@ -783,16 +814,18 @@ def inspect_container(self, container): container (str): The container to inspect Returns: - (dict): Similar to the output of `docker inspect`, but as a - single dict + (ContainerInfo): Similar to the output of `docker inspect`, but as a + docker.api.container.ContainerInfo object Raises: :py:class:`docker.errors.APIError` If the server returns an error. """ - return self._result( + container_info = self._result( self._get(self._url("/containers/{0}/json", container)), True ) + return ContainerInfo(container_info) + @utils.check_resource('container') def kill(self, container, signal=None): diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py index 0215e14c2..2cb6e6da2 100644 --- a/tests/integration/api_container_test.py +++ b/tests/integration/api_container_test.py @@ -1572,3 +1572,19 @@ def test_remove_link(self): x['Id'].startswith(container2_id) ] assert len(retrieved) == 2 + +class ContainerInfoObjectTest(BaseAPIIntegrationTest): + def test_container_info_object(self): + container = self.client.create_container( + TEST_IMG, 'true', host_config=self.client.create_host_config()) + self.tmp_containers.append(container) + self.client.start(container) + + inspect_data = self.client.inspect_container(container) + assert isinstance(inspect_data, docker.api.container.ContainerInfo) + assert inspect_data['Config']['Image'] == TEST_IMG + assert inspect_data['HostConfig']['NetworkMode'] == 'bridge' + + # attribute style access + assert inspect_data.Id == container['Id'] + assert inspect_data["Id"] == container["Id"] From 00a5086d23b542e89284f4ffbd1e932359893084 Mon Sep 17 00:00:00 2001 From: Khushiyant Date: Sun, 9 Mar 2025 17:57:25 +0530 Subject: [PATCH 2/2] chore: add dot attribute access to ContainerInfo Signed-off-by: Khushiyant --- docker/api/container.py | 5 ++++- tests/integration/api_container_test.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docker/api/container.py b/docker/api/container.py index b361d4b22..e31286805 100644 --- a/docker/api/container.py +++ b/docker/api/container.py @@ -26,7 +26,10 @@ def __getattr__(self, item): This allows direct access to all fields without manually defining them. """ try: - return self._info[item] + value = self._info[item] + if isinstance(value, dict): + return ContainerInfo(value) + return value except KeyError as err: raise AttributeError( f"'ContainerInfo' object has no attribute '{item}'" diff --git a/tests/integration/api_container_test.py b/tests/integration/api_container_test.py index 2cb6e6da2..cfe4f5829 100644 --- a/tests/integration/api_container_test.py +++ b/tests/integration/api_container_test.py @@ -1587,4 +1587,5 @@ def test_container_info_object(self): # attribute style access assert inspect_data.Id == container['Id'] - assert inspect_data["Id"] == container["Id"] + assert inspect_data.Config.Image == TEST_IMG + assert inspect_data.HostConfig.NetworkMode == 'bridge'