Skip to content

Commit daa9f17

Browse files
authored
Merge pull request #2671 from aiordache/default_tag
Set image default tag on pull
2 parents e09b070 + aed5700 commit daa9f17

File tree

7 files changed

+49
-24
lines changed

7 files changed

+49
-24
lines changed

docker/api/image.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,14 @@ def prune_images(self, filters=None):
343343
return self._result(self._post(url, params=params), True)
344344

345345
def pull(self, repository, tag=None, stream=False, auth_config=None,
346-
decode=False, platform=None):
346+
decode=False, platform=None, all_tags=False):
347347
"""
348348
Pulls an image. Similar to the ``docker pull`` command.
349349
350350
Args:
351351
repository (str): The repository to pull
352-
tag (str): The tag to pull
352+
tag (str): The tag to pull. If ``tag`` is ``None`` or empty, it
353+
is set to ``latest``.
353354
stream (bool): Stream the output as a generator. Make sure to
354355
consume the generator, otherwise pull might get cancelled.
355356
auth_config (dict): Override the credentials that are found in the
@@ -358,6 +359,8 @@ def pull(self, repository, tag=None, stream=False, auth_config=None,
358359
decode (bool): Decode the JSON data from the server into dicts.
359360
Only applies with ``stream=True``
360361
platform (str): Platform in the format ``os[/arch[/variant]]``
362+
all_tags (bool): Pull all image tags, the ``tag`` parameter is
363+
ignored.
361364
362365
Returns:
363366
(generator or str): The output
@@ -382,8 +385,12 @@ def pull(self, repository, tag=None, stream=False, auth_config=None,
382385
}
383386
384387
"""
385-
if not tag:
386-
repository, tag = utils.parse_repository_tag(repository)
388+
repository, image_tag = utils.parse_repository_tag(repository)
389+
tag = tag or image_tag or 'latest'
390+
391+
if all_tags:
392+
tag = None
393+
387394
registry, repo_name = auth.resolve_repository_name(repository)
388395

389396
params = {

docker/models/images.py

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -395,12 +395,13 @@ def load(self, data):
395395

396396
return [self.get(i) for i in images]
397397

398-
def pull(self, repository, tag=None, **kwargs):
398+
def pull(self, repository, tag=None, all_tags=False, **kwargs):
399399
"""
400400
Pull an image of the given name and return it. Similar to the
401401
``docker pull`` command.
402-
If no tag is specified, all tags from that repository will be
403-
pulled.
402+
If ``tag`` is ``None`` or empty, it is set to ``latest``.
403+
If ``all_tags`` is set, the ``tag`` parameter is ignored and all image
404+
tags will be pulled.
404405
405406
If you want to get the raw pull output, use the
406407
:py:meth:`~docker.api.image.ImageApiMixin.pull` method in the
@@ -413,10 +414,11 @@ def pull(self, repository, tag=None, **kwargs):
413414
config for this request. ``auth_config`` should contain the
414415
``username`` and ``password`` keys to be valid.
415416
platform (str): Platform in the format ``os[/arch[/variant]]``
417+
all_tags (bool): Pull all image tags
416418
417419
Returns:
418420
(:py:class:`Image` or list): The image that has been pulled.
419-
If no ``tag`` was specified, the method will return a list
421+
If ``all_tags`` is True, the method will return a list
420422
of :py:class:`Image` objects belonging to this repository.
421423
422424
Raises:
@@ -426,13 +428,13 @@ def pull(self, repository, tag=None, **kwargs):
426428
Example:
427429
428430
>>> # Pull the image tagged `latest` in the busybox repo
429-
>>> image = client.images.pull('busybox:latest')
431+
>>> image = client.images.pull('busybox')
430432
431433
>>> # Pull all tags in the busybox repo
432-
>>> images = client.images.pull('busybox')
434+
>>> images = client.images.pull('busybox', all_tags=True)
433435
"""
434-
if not tag:
435-
repository, tag = parse_repository_tag(repository)
436+
repository, image_tag = parse_repository_tag(repository)
437+
tag = tag or image_tag or 'latest'
436438

437439
if 'stream' in kwargs:
438440
warnings.warn(
@@ -442,14 +444,14 @@ def pull(self, repository, tag=None, **kwargs):
442444
del kwargs['stream']
443445

444446
pull_log = self.client.api.pull(
445-
repository, tag=tag, stream=True, **kwargs
447+
repository, tag=tag, stream=True, all_tags=all_tags, **kwargs
446448
)
447449
for _ in pull_log:
448450
# We don't do anything with the logs, but we need
449451
# to keep the connection alive and wait for the image
450452
# to be pulled.
451453
pass
452-
if tag:
454+
if not all_tags:
453455
return self.get('{0}{2}{1}'.format(
454456
repository, tag, '@' if tag.startswith('sha256:') else ':'
455457
))

tests/integration/api_image_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def test_pull(self):
4242
self.client.remove_image('hello-world')
4343
except docker.errors.APIError:
4444
pass
45-
res = self.client.pull('hello-world', tag='latest')
45+
res = self.client.pull('hello-world')
4646
self.tmp_imgs.append('hello-world')
4747
assert type(res) == six.text_type
4848
assert len(self.client.images('hello-world')) >= 1
@@ -55,7 +55,7 @@ def test_pull_streaming(self):
5555
except docker.errors.APIError:
5656
pass
5757
stream = self.client.pull(
58-
'hello-world', tag='latest', stream=True, decode=True)
58+
'hello-world', stream=True, decode=True)
5959
self.tmp_imgs.append('hello-world')
6060
for chunk in stream:
6161
assert isinstance(chunk, dict)

tests/integration/models_images_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def test_pull_with_sha(self):
8686

8787
def test_pull_multiple(self):
8888
client = docker.from_env(version=TEST_API_VERSION)
89-
images = client.images.pull('hello-world')
89+
images = client.images.pull('hello-world', all_tags=True)
9090
assert len(images) >= 1
9191
assert any([
9292
'hello-world:latest' in img.attrs['RepoTags'] for img in images

tests/unit/api_image_test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ def test_pull(self):
6767
args = fake_request.call_args
6868
assert args[0][1] == url_prefix + 'images/create'
6969
assert args[1]['params'] == {
70-
'tag': None, 'fromImage': 'joffrey/test001'
70+
'tag': 'latest', 'fromImage': 'joffrey/test001'
7171
}
7272
assert not args[1]['stream']
7373

@@ -77,7 +77,7 @@ def test_pull_stream(self):
7777
args = fake_request.call_args
7878
assert args[0][1] == url_prefix + 'images/create'
7979
assert args[1]['params'] == {
80-
'tag': None, 'fromImage': 'joffrey/test001'
80+
'tag': 'latest', 'fromImage': 'joffrey/test001'
8181
}
8282
assert args[1]['stream']
8383

tests/unit/models_containers_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def test_run_pull(self):
233233

234234
assert container.id == FAKE_CONTAINER_ID
235235
client.api.pull.assert_called_with(
236-
'alpine', platform=None, tag=None, stream=True
236+
'alpine', platform=None, tag='latest', all_tags=False, stream=True
237237
)
238238

239239
def test_run_with_error(self):

tests/unit/models_images_test.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,35 @@ def test_load(self):
4444

4545
def test_pull(self):
4646
client = make_fake_client()
47-
image = client.images.pull('test_image:latest')
47+
image = client.images.pull('test_image:test')
4848
client.api.pull.assert_called_with(
49-
'test_image', tag='latest', stream=True
49+
'test_image', tag='test', all_tags=False, stream=True
50+
)
51+
client.api.inspect_image.assert_called_with('test_image:test')
52+
assert isinstance(image, Image)
53+
assert image.id == FAKE_IMAGE_ID
54+
55+
def test_pull_tag_precedence(self):
56+
client = make_fake_client()
57+
image = client.images.pull('test_image:latest', tag='test')
58+
client.api.pull.assert_called_with(
59+
'test_image', tag='test', all_tags=False, stream=True
60+
)
61+
client.api.inspect_image.assert_called_with('test_image:test')
62+
63+
image = client.images.pull('test_image')
64+
client.api.pull.assert_called_with(
65+
'test_image', tag='latest', all_tags=False, stream=True
5066
)
5167
client.api.inspect_image.assert_called_with('test_image:latest')
5268
assert isinstance(image, Image)
5369
assert image.id == FAKE_IMAGE_ID
5470

5571
def test_pull_multiple(self):
5672
client = make_fake_client()
57-
images = client.images.pull('test_image')
73+
images = client.images.pull('test_image', all_tags=True)
5874
client.api.pull.assert_called_with(
59-
'test_image', tag=None, stream=True
75+
'test_image', tag='latest', all_tags=True, stream=True
6076
)
6177
client.api.images.assert_called_with(
6278
all=False, name='test_image', filters=None

0 commit comments

Comments
 (0)