From 589e7006d59273dcc122d9d0bf2c73aa7190832d Mon Sep 17 00:00:00 2001 From: Huayi Zhang Date: Sun, 5 Oct 2014 23:06:42 +0800 Subject: [PATCH] Add support for filtering images and containers [`filters` is a json encoded value of the filters (a map[string][string]) to process on the images list. ][1] The tricky thing is that we must convert boolean value to string and any filter value to list to make a `map[string][string]` json format [1]: https://docs.docker.com/reference/api/docker_remote_api_v1.14/#list-images --- docker/client.py | 10 ++++++++-- docker/utils/__init__.py | 3 ++- docker/utils/utils.py | 12 ++++++++++++ tests/test.py | 13 +++++++++++++ tests/utils_test.py | 16 +++++++++++++++- 5 files changed, 50 insertions(+), 4 deletions(-) diff --git a/docker/client.py b/docker/client.py index 1ff43cc4..d4f81cbd 100644 --- a/docker/client.py +++ b/docker/client.py @@ -469,7 +469,8 @@ class Client(requests.Session): json=True) def containers(self, quiet=False, all=False, trunc=True, latest=False, - since=None, before=None, limit=-1, size=False): + since=None, before=None, limit=-1, size=False, + filters=None): params = { 'limit': 1 if latest else limit, 'all': 1 if all else 0, @@ -478,6 +479,8 @@ class Client(requests.Session): 'since': since, 'before': before } + if filters: + params['filters'] = utils.convert_filters(filters) u = self._url("/containers/json") res = self._result(self._get(u, params=params), True) @@ -550,7 +553,8 @@ class Client(requests.Session): self._raise_for_status(res) return self._result(res) - def images(self, name=None, quiet=False, all=False, viz=False): + def images(self, name=None, quiet=False, all=False, viz=False, + filters=None): if viz: if utils.compare_version('1.7', self._version) >= 0: raise Exception('Viz output is not supported in API >= 1.7!') @@ -560,6 +564,8 @@ class Client(requests.Session): 'only_ids': 1 if quiet else 0, 'all': 1 if all else 0, } + if filters: + params['filters'] = utils.convert_filters(filters) res = self._result(self._get(self._url("/images/json"), params=params), True) if quiet: diff --git a/docker/utils/__init__.py b/docker/utils/__init__.py index 5d2c1b87..ade4f0bd 100644 --- a/docker/utils/__init__.py +++ b/docker/utils/__init__.py @@ -1,4 +1,5 @@ from .utils import ( compare_version, convert_port_bindings, convert_volume_binds, - mkbuildcontext, ping, tar, parse_repository_tag, parse_host + mkbuildcontext, ping, tar, parse_repository_tag, parse_host, + convert_filters ) # flake8: noqa diff --git a/docker/utils/utils.py b/docker/utils/utils.py index fb05a1ea..514a75b8 100644 --- a/docker/utils/utils.py +++ b/docker/utils/utils.py @@ -14,6 +14,7 @@ import io import os +import json import tarfile import tempfile from distutils.version import StrictVersion @@ -233,3 +234,14 @@ def parse_host(addr): if proto == "http+unix": return "%s://%s" % (proto, host) return "%s://%s:%d" % (proto, host, port) + + +def convert_filters(filters): + result = {} + for k, v in six.iteritems(filters): + if isinstance(v, bool): + v = 'true' if v else 'false' + if not isinstance(v, list): + v = [v, ] + result[k] = v + return json.dumps(result) diff --git a/tests/test.py b/tests/test.py index 984e350e..727d47a8 100644 --- a/tests/test.py +++ b/tests/test.py @@ -181,6 +181,19 @@ class DockerClientTest(Cleanup, unittest.TestCase): timeout=docker.client.DEFAULT_TIMEOUT_SECONDS ) + def test_images_filters(self): + try: + self.client.images(filters={'dangling': True}) + except Exception as e: + self.fail('Command should not raise exception: {0}'.format(e)) + + fake_request.assert_called_with( + url_prefix + 'images/json', + params={'filter': None, 'only_ids': 0, 'all': 0, + 'filters': '{"dangling": ["true"]}'}, + timeout=docker.client.DEFAULT_TIMEOUT_SECONDS + ) + def test_list_containers(self): try: self.client.containers(all=True) diff --git a/tests/utils_test.py b/tests/utils_test.py index 277781b8..98e82259 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -1,7 +1,9 @@ import unittest from docker.errors import DockerException -from docker.utils import parse_repository_tag, parse_host +from docker.utils import ( + parse_repository_tag, parse_host, convert_filters +) class UtilsTest(unittest.TestCase): @@ -53,5 +55,17 @@ class UtilsTest(unittest.TestCase): for host, expected in valid_hosts.items(): self.assertEqual(parse_host(host), expected, msg=host) + def test_convert_filters(self): + tests = [ + ({'dangling': True}, '{"dangling": ["true"]}'), + ({'dangling': "true"}, '{"dangling": ["true"]}'), + ({'exited': 0}, '{"exited": [0]}'), + ({'exited': [0, 1]}, '{"exited": [0, 1]}'), + ] + + for filters, expected in tests: + self.assertEqual(convert_filters(filters), expected) + + if __name__ == '__main__': unittest.main()