mirror of https://github.com/docker/docker-py.git
Merge remote-tracking branch 'upstream/main' into ruffify
This commit is contained in:
commit
6d2b1772aa
|
|
@ -1,6 +1,6 @@
|
||||||
# Docker SDK for Python
|
# Docker SDK for Python
|
||||||
|
|
||||||
[](https://github.com/docker/docker-py/actions/workflows/ci.yml/)
|
[](https://github.com/docker/docker-py/actions/workflows/ci.yml)
|
||||||
|
|
||||||
A Python library for the Docker Engine API. It lets you do anything the `docker` command does, but from within Python apps – run containers, manage containers, manage Swarms, etc.
|
A Python library for the Docker Engine API. It lets you do anything the `docker` command does, but from within Python apps – run containers, manage containers, manage Swarms, etc.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ class ContainerApiMixin:
|
||||||
|
|
||||||
@utils.check_resource('container')
|
@utils.check_resource('container')
|
||||||
def commit(self, container, repository=None, tag=None, message=None,
|
def commit(self, container, repository=None, tag=None, message=None,
|
||||||
author=None, changes=None, conf=None):
|
author=None, pause=True, changes=None, conf=None):
|
||||||
"""
|
"""
|
||||||
Commit a container to an image. Similar to the ``docker commit``
|
Commit a container to an image. Similar to the ``docker commit``
|
||||||
command.
|
command.
|
||||||
|
|
@ -123,6 +123,7 @@ class ContainerApiMixin:
|
||||||
tag (str): The tag to push
|
tag (str): The tag to push
|
||||||
message (str): A commit message
|
message (str): A commit message
|
||||||
author (str): The name of the author
|
author (str): The name of the author
|
||||||
|
pause (bool): Whether to pause the container before committing
|
||||||
changes (str): Dockerfile instructions to apply while committing
|
changes (str): Dockerfile instructions to apply while committing
|
||||||
conf (dict): The configuration for the container. See the
|
conf (dict): The configuration for the container. See the
|
||||||
`Engine API documentation
|
`Engine API documentation
|
||||||
|
|
@ -139,6 +140,7 @@ class ContainerApiMixin:
|
||||||
'tag': tag,
|
'tag': tag,
|
||||||
'comment': message,
|
'comment': message,
|
||||||
'author': author,
|
'author': author,
|
||||||
|
'pause': pause,
|
||||||
'changes': changes
|
'changes': changes
|
||||||
}
|
}
|
||||||
u = self._url("/commit")
|
u = self._url("/commit")
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ def create_api_error_from_http_exception(e):
|
||||||
try:
|
try:
|
||||||
explanation = response.json()['message']
|
explanation = response.json()['message']
|
||||||
except ValueError:
|
except ValueError:
|
||||||
explanation = (response.content or '').strip()
|
explanation = (response.text or '').strip()
|
||||||
cls = APIError
|
cls = APIError
|
||||||
if response.status_code == 404:
|
if response.status_code == 404:
|
||||||
explanation_msg = (explanation or '').lower()
|
explanation_msg = (explanation or '').lower()
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ class Container(Model):
|
||||||
tag (str): The tag to push
|
tag (str): The tag to push
|
||||||
message (str): A commit message
|
message (str): A commit message
|
||||||
author (str): The name of the author
|
author (str): The name of the author
|
||||||
|
pause (bool): Whether to pause the container before committing
|
||||||
changes (str): Dockerfile instructions to apply while committing
|
changes (str): Dockerfile instructions to apply while committing
|
||||||
conf (dict): The configuration for the container. See the
|
conf (dict): The configuration for the container. See the
|
||||||
`Engine API documentation
|
`Engine API documentation
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,13 @@ Prepare the command we are going to use. It prints "hello stdout"
|
||||||
in `stdout`, followed by "hello stderr" in `stderr`:
|
in `stdout`, followed by "hello stderr" in `stderr`:
|
||||||
|
|
||||||
>>> cmd = '/bin/sh -c "echo hello stdout ; echo hello stderr >&2"'
|
>>> cmd = '/bin/sh -c "echo hello stdout ; echo hello stderr >&2"'
|
||||||
|
|
||||||
We'll run this command with all four the combinations of ``stream``
|
We'll run this command with all four the combinations of ``stream``
|
||||||
and ``demux``.
|
and ``demux``.
|
||||||
|
|
||||||
With ``stream=False`` and ``demux=False``, the output is a string
|
With ``stream=False`` and ``demux=False``, the output is a string
|
||||||
that contains both the `stdout` and the `stderr` output:
|
that contains both the `stdout` and the `stderr` output:
|
||||||
|
|
||||||
>>> res = container.exec_run(cmd, stream=False, demux=False)
|
>>> res = container.exec_run(cmd, stream=False, demux=False)
|
||||||
>>> res.output
|
>>> res.output
|
||||||
b'hello stderr\nhello stdout\n'
|
b'hello stderr\nhello stdout\n'
|
||||||
|
|
@ -52,15 +55,8 @@ Traceback (most recent call last):
|
||||||
File "<stdin>", line 1, in <module>
|
File "<stdin>", line 1, in <module>
|
||||||
StopIteration
|
StopIteration
|
||||||
|
|
||||||
Finally, with ``stream=False`` and ``demux=True``, the whole output
|
Finally, with ``stream=False`` and ``demux=True``, the output is a tuple ``(stdout, stderr)``:
|
||||||
is returned, but the streams are still separated:
|
|
||||||
|
|
||||||
>>> res = container.exec_run(cmd, stream=True, demux=True)
|
>>> res = container.exec_run(cmd, stream=False, demux=True)
|
||||||
>>> next(res.output)
|
>>> res.output
|
||||||
(b'hello stdout\n', None)
|
(b'hello stdout\n', b'hello stderr\n')
|
||||||
>>> next(res.output)
|
|
||||||
(None, b'hello stderr\n')
|
|
||||||
>>> next(res.output)
|
|
||||||
Traceback (most recent call last):
|
|
||||||
File "<stdin>", line 1, in <module>
|
|
||||||
StopIteration
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
packaging==21.3
|
packaging==21.3
|
||||||
paramiko==2.11.0
|
paramiko==2.11.0
|
||||||
pywin32==304; sys_platform == 'win32'
|
pywin32==304; sys_platform == 'win32'
|
||||||
requests==2.28.1
|
requests==2.31.0
|
||||||
urllib3==1.26.11
|
urllib3==1.26.11
|
||||||
websocket-client==1.3.3
|
websocket-client==1.3.3
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,6 @@ ARG PYTHON_VERSION=3.10
|
||||||
|
|
||||||
FROM python:${PYTHON_VERSION}
|
FROM python:${PYTHON_VERSION}
|
||||||
|
|
||||||
ARG APT_MIRROR
|
|
||||||
RUN sed -ri "s/(httpredir|deb).debian.org/${APT_MIRROR:-deb.debian.org}/g" /etc/apt/sources.list \
|
|
||||||
&& sed -ri "s/(security).debian.org/${APT_MIRROR:-security.debian.org}/g" /etc/apt/sources.list
|
|
||||||
|
|
||||||
RUN apt-get update && apt-get -y install --no-install-recommends \
|
RUN apt-get update && apt-get -y install --no-install-recommends \
|
||||||
gnupg2 \
|
gnupg2 \
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -122,8 +122,8 @@ class CreateContainerTest(BaseAPIIntegrationTest):
|
||||||
self.client.wait(id)
|
self.client.wait(id)
|
||||||
with pytest.raises(docker.errors.APIError) as exc:
|
with pytest.raises(docker.errors.APIError) as exc:
|
||||||
self.client.remove_container(id)
|
self.client.remove_container(id)
|
||||||
err = exc.value.explanation
|
err = exc.value.explanation.lower()
|
||||||
assert 'You cannot remove ' in err
|
assert 'stop the container before' in err
|
||||||
self.client.remove_container(id, force=True)
|
self.client.remove_container(id, force=True)
|
||||||
|
|
||||||
def test_create_container_with_volumes_from(self):
|
def test_create_container_with_volumes_from(self):
|
||||||
|
|
@ -1390,7 +1390,7 @@ class GetContainerStatsTest(BaseAPIIntegrationTest):
|
||||||
response = self.client.stats(container, stream=0)
|
response = self.client.stats(container, stream=0)
|
||||||
self.client.kill(container)
|
self.client.kill(container)
|
||||||
|
|
||||||
assert type(response) == dict
|
assert isinstance(response, dict)
|
||||||
for key in ['read', 'networks', 'precpu_stats', 'cpu_stats',
|
for key in ['read', 'networks', 'precpu_stats', 'cpu_stats',
|
||||||
'memory_stats', 'blkio_stats']:
|
'memory_stats', 'blkio_stats']:
|
||||||
assert key in response
|
assert key in response
|
||||||
|
|
@ -1403,7 +1403,7 @@ class GetContainerStatsTest(BaseAPIIntegrationTest):
|
||||||
self.client.start(container)
|
self.client.start(container)
|
||||||
stream = self.client.stats(container)
|
stream = self.client.stats(container)
|
||||||
for chunk in stream:
|
for chunk in stream:
|
||||||
assert type(chunk) == dict
|
assert isinstance(chunk, dict)
|
||||||
for key in ['read', 'network', 'precpu_stats', 'cpu_stats',
|
for key in ['read', 'network', 'precpu_stats', 'cpu_stats',
|
||||||
'memory_stats', 'blkio_stats']:
|
'memory_stats', 'blkio_stats']:
|
||||||
assert key in chunk
|
assert key in chunk
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ class ListImagesTest(BaseAPIIntegrationTest):
|
||||||
|
|
||||||
def test_images_quiet(self):
|
def test_images_quiet(self):
|
||||||
res1 = self.client.images(quiet=True)
|
res1 = self.client.images(quiet=True)
|
||||||
assert type(res1[0]) == str
|
assert isinstance(res1[0], str)
|
||||||
|
|
||||||
|
|
||||||
class PullImageTest(BaseAPIIntegrationTest):
|
class PullImageTest(BaseAPIIntegrationTest):
|
||||||
|
|
@ -43,7 +43,7 @@ class PullImageTest(BaseAPIIntegrationTest):
|
||||||
pass
|
pass
|
||||||
res = self.client.pull('hello-world')
|
res = self.client.pull('hello-world')
|
||||||
self.tmp_imgs.append('hello-world')
|
self.tmp_imgs.append('hello-world')
|
||||||
assert type(res) == str
|
assert isinstance(res, str)
|
||||||
assert len(self.client.images('hello-world')) >= 1
|
assert len(self.client.images('hello-world')) >= 1
|
||||||
img_info = self.client.inspect_image('hello-world')
|
img_info = self.client.inspect_image('hello-world')
|
||||||
assert 'Id' in img_info
|
assert 'Id' in img_info
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ class ErrorsTest(BaseAPIIntegrationTest):
|
||||||
self.client.start(container['Id'])
|
self.client.start(container['Id'])
|
||||||
with pytest.raises(APIError) as cm:
|
with pytest.raises(APIError) as cm:
|
||||||
self.client.remove_container(container['Id'])
|
self.client.remove_container(container['Id'])
|
||||||
explanation = cm.value.explanation
|
explanation = cm.value.explanation.lower()
|
||||||
assert 'You cannot remove a running container' in explanation
|
assert 'stop the container before' in explanation
|
||||||
assert '{"message":' not in explanation
|
assert '{"message":' not in explanation
|
||||||
self.client.remove_container(container['Id'], force=True)
|
self.client.remove_container(container['Id'], force=True)
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,7 @@ class ImageTest(BaseAPIClientTest):
|
||||||
'tag': None,
|
'tag': None,
|
||||||
'container': fake_api.FAKE_CONTAINER_ID,
|
'container': fake_api.FAKE_CONTAINER_ID,
|
||||||
'author': None,
|
'author': None,
|
||||||
|
'pause': True,
|
||||||
'changes': None
|
'changes': None
|
||||||
},
|
},
|
||||||
timeout=DEFAULT_TIMEOUT_SECONDS
|
timeout=DEFAULT_TIMEOUT_SECONDS
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue