diff --git a/docker/models/containers.py b/docker/models/containers.py index d4ed1aa3..1e06ed60 100644 --- a/docker/models/containers.py +++ b/docker/models/containers.py @@ -4,8 +4,10 @@ from collections import namedtuple from ..api import APIClient from ..constants import DEFAULT_DATA_CHUNK_SIZE -from ..errors import (ContainerError, ImageNotFound, - create_unexpected_kwargs_error) +from ..errors import ( + ContainerError, DockerException, ImageNotFound, + create_unexpected_kwargs_error +) from ..types import HostConfig from ..utils import version_gte from .images import Image @@ -27,7 +29,7 @@ class Container(Model): """ The image of the container. """ - image_id = self.attrs['Image'] + image_id = self.attrs.get('ImageID', self.attrs['Image']) if image_id is None: return None return self.client.images.get(image_id.split(':')[1]) @@ -37,15 +39,23 @@ class Container(Model): """ The labels of a container as dictionary. """ - result = self.attrs['Config'].get('Labels') - return result or {} + try: + result = self.attrs['Config'].get('Labels') + return result or {} + except KeyError: + raise DockerException( + 'Label data is not available for sparse objects. Call reload()' + ' to retrieve all information' + ) @property def status(self): """ The status of the container. For example, ``running``, or ``exited``. """ - return self.attrs['State']['Status'] + if isinstance(self.attrs['State'], dict): + return self.attrs['State']['Status'] + return self.attrs['State'] def attach(self, **kwargs): """ @@ -863,14 +873,16 @@ class ContainerCollection(Collection): container. Give the container name or id. - `since` (str): Only containers created after a particular container. Give container name or id. - sparse (bool): Do not inspect containers. Returns partial - informations, but guaranteed not to block. Use reload() on - each container to get the full list of attributes. A comprehensive list can be found in the documentation for `docker ps `_. + sparse (bool): Do not inspect containers. Returns partial + information, but guaranteed not to block. Use + :py:meth:`Container.reload` on resulting objects to retrieve + all attributes. Default: ``False`` + Returns: (list of :py:class:`Container`) diff --git a/tests/integration/models_containers_test.py b/tests/integration/models_containers_test.py index fac4de2b..38aae4d2 100644 --- a/tests/integration/models_containers_test.py +++ b/tests/integration/models_containers_test.py @@ -159,6 +159,28 @@ class ContainerCollectionTest(BaseIntegrationTest): container = containers[0] assert container.attrs['Config']['Image'] == 'alpine' + assert container.status == 'running' + assert container.image == client.images.get('alpine') + + container.kill() + container.remove() + assert container_id not in [c.id for c in client.containers.list()] + + def test_list_sparse(self): + client = docker.from_env(version=TEST_API_VERSION) + container_id = client.containers.run( + "alpine", "sleep 300", detach=True).id + self.tmp_containers.append(container_id) + containers = [c for c in client.containers.list(sparse=True) if c.id == + container_id] + assert len(containers) == 1 + + container = containers[0] + assert container.attrs['Image'] == 'alpine' + assert container.status == 'running' + assert container.image == client.images.get('alpine') + with pytest.raises(docker.errors.DockerException): + container.labels container.kill() container.remove()