Skip to content

Commit 581ccc9

Browse files
committed
Add chunk_size parameter to data downloading methods (export, get_archive, save)
Signed-off-by: Joffrey F <[email protected]>
1 parent 9e75609 commit 581ccc9

File tree

8 files changed

+53
-18
lines changed

8 files changed

+53
-18
lines changed

docker/api/client.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,10 +350,10 @@ def _multiplexed_response_stream_helper(self, response):
350350
break
351351
yield data
352352

353-
def _stream_raw_result(self, response):
354-
''' Stream result for TTY-enabled container '''
353+
def _stream_raw_result(self, response, chunk_size=1, decode=True):
354+
''' Stream result for TTY-enabled container and raw binary data'''
355355
self._raise_for_status(response)
356-
for out in response.iter_content(chunk_size=1, decode_unicode=True):
356+
for out in response.iter_content(chunk_size, decode):
357357
yield out
358358

359359
def _read_from_socket(self, response, stream, tty=False):

docker/api/container.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from .. import errors
55
from .. import utils
6+
from ..constants import DEFAULT_DATA_CHUNK_SIZE
67
from ..types import (
78
ContainerConfig, EndpointConfig, HostConfig, NetworkingConfig
89
)
@@ -643,12 +644,15 @@ def diff(self, container):
643644
)
644645

645646
@utils.check_resource('container')
646-
def export(self, container):
647+
def export(self, container, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
647648
"""
648649
Export the contents of a filesystem as a tar archive.
649650
650651
Args:
651652
container (str): The container to export
653+
chunk_size (int): The number of bytes returned by each iteration
654+
of the generator. If ``None``, data will be streamed as it is
655+
received. Default: 2 MB
652656
653657
Returns:
654658
(generator): The archived filesystem data stream
@@ -660,17 +664,20 @@ def export(self, container):
660664
res = self._get(
661665
self._url("/containers/{0}/export", container), stream=True
662666
)
663-
return self._stream_raw_result(res)
667+
return self._stream_raw_result(res, chunk_size, False)
664668

665669
@utils.check_resource('container')
666-
def get_archive(self, container, path):
670+
def get_archive(self, container, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
667671
"""
668672
Retrieve a file or folder from a container in the form of a tar
669673
archive.
670674
671675
Args:
672676
container (str): The container where the file is located
673677
path (str): Path to the file or folder to retrieve
678+
chunk_size (int): The number of bytes returned by each iteration
679+
of the generator. If ``None``, data will be streamed as it is
680+
received. Default: 2 MB
674681
675682
Returns:
676683
(tuple): First element is a raw tar data stream. Second element is
@@ -688,7 +695,7 @@ def get_archive(self, container, path):
688695
self._raise_for_status(res)
689696
encoded_stat = res.headers.get('x-docker-container-path-stat')
690697
return (
691-
self._stream_raw_result(res),
698+
self._stream_raw_result(res, chunk_size, False),
692699
utils.decode_json_header(encoded_stat) if encoded_stat else None
693700
)
694701

docker/api/image.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@
44
import six
55

66
from .. import auth, errors, utils
7+
from ..constants import DEFAULT_DATA_CHUNK_SIZE
78

89
log = logging.getLogger(__name__)
910

1011

1112
class ImageApiMixin(object):
1213

1314
@utils.check_resource('image')
14-
def get_image(self, image):
15+
def get_image(self, image, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
1516
"""
1617
Get a tarball of an image. Similar to the ``docker save`` command.
1718
1819
Args:
1920
image (str): Image name to get
21+
chunk_size (int): The number of bytes returned by each iteration
22+
of the generator. If ``None``, data will be streamed as it is
23+
received. Default: 2 MB
2024
2125
Returns:
2226
(generator): A stream of raw archive data.
@@ -34,7 +38,7 @@ def get_image(self, image):
3438
>>> f.close()
3539
"""
3640
res = self._get(self._url("/images/{0}/get", image), stream=True)
37-
return self._stream_raw_result(res)
41+
return self._stream_raw_result(res, chunk_size, False)
3842

3943
@utils.check_resource('image')
4044
def history(self, image):

docker/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@
1717

1818
DEFAULT_USER_AGENT = "docker-sdk-python/{0}".format(version)
1919
DEFAULT_NUM_POOLS = 25
20+
DEFAULT_DATA_CHUNK_SIZE = 1024 * 2048

docker/models/containers.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from collections import namedtuple
44

55
from ..api import APIClient
6+
from ..constants import DEFAULT_DATA_CHUNK_SIZE
67
from ..errors import (ContainerError, ImageNotFound,
78
create_unexpected_kwargs_error)
89
from ..types import HostConfig
@@ -181,26 +182,34 @@ def exec_run(self, cmd, stdout=True, stderr=True, stdin=False, tty=False,
181182
exec_output
182183
)
183184

184-
def export(self):
185+
def export(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
185186
"""
186187
Export the contents of the container's filesystem as a tar archive.
187188
189+
Args:
190+
chunk_size (int): The number of bytes returned by each iteration
191+
of the generator. If ``None``, data will be streamed as it is
192+
received. Default: 2 MB
193+
188194
Returns:
189195
(str): The filesystem tar archive
190196
191197
Raises:
192198
:py:class:`docker.errors.APIError`
193199
If the server returns an error.
194200
"""
195-
return self.client.api.export(self.id)
201+
return self.client.api.export(self.id, chunk_size)
196202

197-
def get_archive(self, path):
203+
def get_archive(self, path, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
198204
"""
199205
Retrieve a file or folder from the container in the form of a tar
200206
archive.
201207
202208
Args:
203209
path (str): Path to the file or folder to retrieve
210+
chunk_size (int): The number of bytes returned by each iteration
211+
of the generator. If ``None``, data will be streamed as it is
212+
received. Default: 2 MB
204213
205214
Returns:
206215
(tuple): First element is a raw tar data stream. Second element is
@@ -210,7 +219,7 @@ def get_archive(self, path):
210219
:py:class:`docker.errors.APIError`
211220
If the server returns an error.
212221
"""
213-
return self.client.api.get_archive(self.id, path)
222+
return self.client.api.get_archive(self.id, path, chunk_size)
214223

215224
def kill(self, signal=None):
216225
"""

docker/models/images.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import six
55

66
from ..api import APIClient
7+
from ..constants import DEFAULT_DATA_CHUNK_SIZE
78
from ..errors import BuildError, ImageLoadError
89
from ..utils import parse_repository_tag
910
from ..utils.json_stream import json_stream
@@ -58,10 +59,15 @@ def history(self):
5859
"""
5960
return self.client.api.history(self.id)
6061

61-
def save(self):
62+
def save(self, chunk_size=DEFAULT_DATA_CHUNK_SIZE):
6263
"""
6364
Get a tarball of an image. Similar to the ``docker save`` command.
6465
66+
Args:
67+
chunk_size (int): The number of bytes returned by each iteration
68+
of the generator. If ``None``, data will be streamed as it is
69+
received. Default: 2 MB
70+
6571
Returns:
6672
(generator): A stream of raw archive data.
6773
@@ -77,7 +83,7 @@ def save(self):
7783
>>> f.write(chunk)
7884
>>> f.close()
7985
"""
80-
return self.client.api.get_image(self.id)
86+
return self.client.api.get_image(self.id, chunk_size)
8187

8288
def tag(self, repository, tag=None, **kwargs):
8389
"""

tests/unit/models_containers_test.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import docker
2+
from docker.constants import DEFAULT_DATA_CHUNK_SIZE
23
from docker.models.containers import Container, _create_container_args
34
from docker.models.images import Image
45
import unittest
@@ -422,13 +423,17 @@ def test_export(self):
422423
client = make_fake_client()
423424
container = client.containers.get(FAKE_CONTAINER_ID)
424425
container.export()
425-
client.api.export.assert_called_with(FAKE_CONTAINER_ID)
426+
client.api.export.assert_called_with(
427+
FAKE_CONTAINER_ID, DEFAULT_DATA_CHUNK_SIZE
428+
)
426429

427430
def test_get_archive(self):
428431
client = make_fake_client()
429432
container = client.containers.get(FAKE_CONTAINER_ID)
430433
container.get_archive('foo')
431-
client.api.get_archive.assert_called_with(FAKE_CONTAINER_ID, 'foo')
434+
client.api.get_archive.assert_called_with(
435+
FAKE_CONTAINER_ID, 'foo', DEFAULT_DATA_CHUNK_SIZE
436+
)
432437

433438
def test_image(self):
434439
client = make_fake_client()

tests/unit/models_images_test.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from docker.constants import DEFAULT_DATA_CHUNK_SIZE
12
from docker.models.images import Image
23
import unittest
34

@@ -116,7 +117,9 @@ def test_save(self):
116117
client = make_fake_client()
117118
image = client.images.get(FAKE_IMAGE_ID)
118119
image.save()
119-
client.api.get_image.assert_called_with(FAKE_IMAGE_ID)
120+
client.api.get_image.assert_called_with(
121+
FAKE_IMAGE_ID, DEFAULT_DATA_CHUNK_SIZE
122+
)
120123

121124
def test_tag(self):
122125
client = make_fake_client()

0 commit comments

Comments
 (0)