Update save / export methods to return data generators

Signed-off-by: Joffrey F <joffrey@docker.com>
This commit is contained in:
Joffrey F 2018-01-26 15:32:04 -08:00
parent deb8222d69
commit 388f291b13
5 changed files with 53 additions and 20 deletions

View File

@ -698,7 +698,7 @@ class ContainerApiMixin(object):
container (str): The container to export container (str): The container to export
Returns: Returns:
(str): The filesystem tar archive (generator): The archived filesystem data stream
Raises: Raises:
:py:class:`docker.errors.APIError` :py:class:`docker.errors.APIError`
@ -707,8 +707,7 @@ class ContainerApiMixin(object):
res = self._get( res = self._get(
self._url("/containers/{0}/export", container), stream=True self._url("/containers/{0}/export", container), stream=True
) )
self._raise_for_status(res) return self._stream_raw_result(res)
return res.raw
@utils.check_resource('container') @utils.check_resource('container')
@utils.minimum_version('1.20') @utils.minimum_version('1.20')
@ -737,7 +736,7 @@ class ContainerApiMixin(object):
self._raise_for_status(res) self._raise_for_status(res)
encoded_stat = res.headers.get('x-docker-container-path-stat') encoded_stat = res.headers.get('x-docker-container-path-stat')
return ( return (
res.raw, self._stream_raw_result(res),
utils.decode_json_header(encoded_stat) if encoded_stat else None utils.decode_json_header(encoded_stat) if encoded_stat else None
) )

View File

@ -21,8 +21,7 @@ class ImageApiMixin(object):
image (str): Image name to get image (str): Image name to get
Returns: Returns:
(urllib3.response.HTTPResponse object): The response from the (generator): A stream of raw archive data.
daemon.
Raises: Raises:
:py:class:`docker.errors.APIError` :py:class:`docker.errors.APIError`
@ -30,14 +29,14 @@ class ImageApiMixin(object):
Example: Example:
>>> image = cli.get_image("fedora:latest") >>> image = cli.get_image("busybox:latest")
>>> f = open('/tmp/fedora-latest.tar', 'w') >>> f = open('/tmp/busybox-latest.tar', 'w')
>>> f.write(image.data) >>> for chunk in image:
>>> f.write(chunk)
>>> f.close() >>> f.close()
""" """
res = self._get(self._url("/images/{0}/get", image), stream=True) res = self._get(self._url("/images/{0}/get", image), stream=True)
self._raise_for_status(res) return self._stream_raw_result(res)
return res.raw
@utils.check_resource('image') @utils.check_resource('image')
def history(self, image): def history(self, image):

View File

@ -61,8 +61,7 @@ class Image(Model):
Get a tarball of an image. Similar to the ``docker save`` command. Get a tarball of an image. Similar to the ``docker save`` command.
Returns: Returns:
(urllib3.response.HTTPResponse object): The response from the (generator): A stream of raw archive data.
daemon.
Raises: Raises:
:py:class:`docker.errors.APIError` :py:class:`docker.errors.APIError`
@ -70,10 +69,9 @@ class Image(Model):
Example: Example:
>>> image = cli.images.get("fedora:latest") >>> image = cli.get_image("busybox:latest")
>>> resp = image.save() >>> f = open('/tmp/busybox-latest.tar', 'w')
>>> f = open('/tmp/fedora-latest.tar', 'w') >>> for chunk in image:
>>> for chunk in resp.stream():
>>> f.write(chunk) >>> f.write(chunk)
>>> f.close() >>> f.close()
""" """

View File

@ -329,7 +329,7 @@ class PruneImagesTest(BaseAPIIntegrationTest):
img_id = self.client.inspect_image('hello-world')['Id'] img_id = self.client.inspect_image('hello-world')['Id']
result = self.client.prune_images() result = self.client.prune_images()
assert img_id not in [ assert img_id not in [
img.get('Deleted') for img in result['ImagesDeleted'] img.get('Deleted') for img in result.get('ImagesDeleted') or []
] ]
result = self.client.prune_images({'dangling': False}) result = self.client.prune_images({'dangling': False})
assert result['SpaceReclaimed'] > 0 assert result['SpaceReclaimed'] > 0
@ -339,3 +339,25 @@ class PruneImagesTest(BaseAPIIntegrationTest):
assert img_id in [ assert img_id in [
img.get('Deleted') for img in result['ImagesDeleted'] img.get('Deleted') for img in result['ImagesDeleted']
] ]
class SaveLoadImagesTest(BaseAPIIntegrationTest):
@requires_api_version('1.23')
def test_get_image_load_image(self):
with tempfile.TemporaryFile() as f:
stream = self.client.get_image(BUSYBOX)
for chunk in stream:
f.write(chunk)
f.seek(0)
result = self.client.load_image(f.read())
success = False
result_line = 'Loaded image: {}\n'.format(BUSYBOX)
for data in result:
print(data)
if 'stream' in data:
if data['stream'] == result_line:
success = True
break
assert success is True

View File

@ -1,9 +1,10 @@
import io import io
import tempfile
import docker import docker
import pytest import pytest
from .base import BaseIntegrationTest, TEST_API_VERSION from .base import BaseIntegrationTest, BUSYBOX, TEST_API_VERSION
class ImageCollectionTest(BaseIntegrationTest): class ImageCollectionTest(BaseIntegrationTest):
@ -76,6 +77,20 @@ class ImageCollectionTest(BaseIntegrationTest):
with pytest.raises(docker.errors.ImageLoadError): with pytest.raises(docker.errors.ImageLoadError):
client.images.load('abc') client.images.load('abc')
def test_save_and_load(self):
client = docker.from_env(version=TEST_API_VERSION)
image = client.images.get(BUSYBOX)
with tempfile.TemporaryFile() as f:
stream = image.save()
for chunk in stream:
f.write(chunk)
f.seek(0)
result = client.images.load(f.read())
assert len(result) == 1
assert result[0].id == image.id
class ImageTest(BaseIntegrationTest): class ImageTest(BaseIntegrationTest):