summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--docker/api/client.py49
-rw-r--r--docker/models/images.py8
-rw-r--r--docker/models/resource.py3
-rw-r--r--docs/index.rst2
-rw-r--r--setup.py10
-rw-r--r--tests/unit/models_images_test.py5
-rw-r--r--tests/unit/models_resources_test.py14
8 files changed, 61 insertions, 32 deletions
diff --git a/README.md b/README.md
index d80d930..38963b3 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ A Python library for the Docker Engine API. It lets you do anything the `docker`
## Installation
-The latest stable version [is available on PyPi](https://pypi.python.org/pypi/docker/). Either add `docker` to your `requirements.txt` file or install with pip:
+The latest stable version [is available on PyPI](https://pypi.python.org/pypi/docker/). Either add `docker` to your `requirements.txt` file or install with pip:
pip install docker
diff --git a/docker/api/client.py b/docker/api/client.py
index a9fe7d0..22c32b4 100644
--- a/docker/api/client.py
+++ b/docker/api/client.py
@@ -18,16 +18,20 @@ from .service import ServiceApiMixin
from .swarm import SwarmApiMixin
from .volume import VolumeApiMixin
from .. import auth
-from ..constants import (DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT,
- IS_WINDOWS_PLATFORM, DEFAULT_DOCKER_API_VERSION,
- STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
- MINIMUM_DOCKER_API_VERSION)
-from ..errors import (DockerException, TLSParameterError,
- create_api_error_from_http_exception)
+from ..constants import (
+ DEFAULT_TIMEOUT_SECONDS, DEFAULT_USER_AGENT, IS_WINDOWS_PLATFORM,
+ DEFAULT_DOCKER_API_VERSION, STREAM_HEADER_SIZE_BYTES, DEFAULT_NUM_POOLS,
+ MINIMUM_DOCKER_API_VERSION
+)
+from ..errors import (
+ DockerException, TLSParameterError,
+ create_api_error_from_http_exception
+)
from ..tls import TLSConfig
from ..transport import SSLAdapter, UnixAdapter
from ..utils import utils, check_resource, update_headers
from ..utils.socket import frames_iter
+from ..utils.json_stream import json_stream
try:
from ..transport import NpipeAdapter
except ImportError:
@@ -274,27 +278,20 @@ class APIClient(
def _stream_helper(self, response, decode=False):
"""Generator for data coming from a chunked-encoded HTTP response."""
+
if response.raw._fp.chunked:
- reader = response.raw
- while not reader.closed:
- # this read call will block until we get a chunk
- data = reader.read(1)
- if not data:
- break
- if reader._fp.chunk_left:
- data += reader.read(reader._fp.chunk_left)
- if decode:
- if six.PY3:
- data = data.decode('utf-8')
- # remove the trailing newline
- data = data.strip()
- # split the data at any newlines
- data_list = data.split("\r\n")
- # load and yield each line seperately
- for data in data_list:
- data = json.loads(data)
- yield data
- else:
+ if decode:
+ for chunk in json_stream(self._stream_helper(response, False)):
+ yield chunk
+ else:
+ reader = response.raw
+ while not reader.closed:
+ # this read call will block until we get a chunk
+ data = reader.read(1)
+ if not data:
+ break
+ if reader._fp.chunk_left:
+ data += reader.read(reader._fp.chunk_left)
yield data
else:
# Response isn't chunked, meaning we probably
diff --git a/docker/models/images.py b/docker/models/images.py
index 32068e6..6f8f4fe 100644
--- a/docker/models/images.py
+++ b/docker/models/images.py
@@ -30,10 +30,10 @@ class Image(Model):
"""
The image's tags.
"""
- return [
- tag for tag in self.attrs.get('RepoTags', [])
- if tag != '<none>:<none>'
- ]
+ tags = self.attrs.get('RepoTags')
+ if tags is None:
+ tags = []
+ return [tag for tag in tags if tag != '<none>:<none>']
def history(self):
"""
diff --git a/docker/models/resource.py b/docker/models/resource.py
index 95712ae..ed3900a 100644
--- a/docker/models/resource.py
+++ b/docker/models/resource.py
@@ -23,6 +23,9 @@ class Model(object):
def __eq__(self, other):
return isinstance(other, self.__class__) and self.id == other.id
+ def __hash__(self):
+ return hash("%s:%s" % (self.__class__.__name__, self.id))
+
@property
def id(self):
"""
diff --git a/docs/index.rst b/docs/index.rst
index 9f484cd..8a86cc6 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -8,7 +8,7 @@ For more information about the Remote API, `see its documentation <https://docs.
Installation
------------
-The latest stable version `is available on PyPi <https://pypi.python.org/pypi/docker/>`_. Either add ``docker`` to your ``requirements.txt`` file or install with pip::
+The latest stable version `is available on PyPI <https://pypi.python.org/pypi/docker/>`_. Either add ``docker`` to your ``requirements.txt`` file or install with pip::
pip install docker
diff --git a/setup.py b/setup.py
index b82a74f..9fc4ad6 100644
--- a/setup.py
+++ b/setup.py
@@ -1,10 +1,20 @@
#!/usr/bin/env python
+from __future__ import print_function
+
import codecs
import os
import sys
+import pip
+
from setuptools import setup, find_packages
+if 'docker-py' in [x.project_name for x in pip.get_installed_distributions()]:
+ print(
+ 'ERROR: "docker-py" needs to be uninstalled before installing this'
+ ' package:\npip uninstall docker-py', file=sys.stderr
+ )
+ sys.exit(1)
ROOT_DIR = os.path.dirname(__file__)
SOURCE_DIR = os.path.join(ROOT_DIR)
diff --git a/tests/unit/models_images_test.py b/tests/unit/models_images_test.py
index 392c58d..efb2116 100644
--- a/tests/unit/models_images_test.py
+++ b/tests/unit/models_images_test.py
@@ -83,6 +83,11 @@ class ImageTest(unittest.TestCase):
})
assert image.tags == []
+ image = Image(attrs={
+ 'RepoTags': None
+ })
+ assert image.tags == []
+
def test_history(self):
client = make_fake_client()
image = client.images.get(FAKE_IMAGE_ID)
diff --git a/tests/unit/models_resources_test.py b/tests/unit/models_resources_test.py
index 25c6a3e..5af24ee 100644
--- a/tests/unit/models_resources_test.py
+++ b/tests/unit/models_resources_test.py
@@ -12,3 +12,17 @@ class ModelTest(unittest.TestCase):
container.reload()
assert client.api.inspect_container.call_count == 2
assert container.attrs['Name'] == "foobar"
+
+ def test_hash(self):
+ client = make_fake_client()
+ container1 = client.containers.get(FAKE_CONTAINER_ID)
+ my_set = set([container1])
+ assert len(my_set) == 1
+
+ container2 = client.containers.get(FAKE_CONTAINER_ID)
+ my_set.add(container2)
+ assert len(my_set) == 1
+
+ image1 = client.images.get(FAKE_CONTAINER_ID)
+ my_set.add(image1)
+ assert len(my_set) == 2