diff options
author | Andrew Welleck <awellec@us.ibm.com> | 2016-02-23 15:02:03 -0600 |
---|---|---|
committer | Andrew Welleck <awellec@us.ibm.com> | 2016-06-09 13:51:26 -0500 |
commit | 439330cb9caa88d455ee0770d32ad7bc77db0b2a (patch) | |
tree | 97f36b30f6724b50e61bef1df4f38eceb4fbade2 | |
parent | 3a6c14981dbd26e12b7d77ebfbb501607557b97c (diff) | |
download | python-swiftclient-439330cb9caa88d455ee0770d32ad7bc77db0b2a.tar.gz |
Query string functionality for containers
Added functionality for arbitrary query strings to be passed into container
functions. Additionally a minor typo correction in the README. Added unit
tests for query string functionality.
Closes-Bug: #1542459
Change-Id: Ica2cb3ea439632588388e748d8d2e944e9ed4fa4
-rw-r--r-- | README.rst | 2 | ||||
-rw-r--r-- | swiftclient/client.py | 34 | ||||
-rw-r--r-- | tests/unit/test_swiftclient.py | 31 |
3 files changed, 57 insertions, 10 deletions
@@ -17,7 +17,7 @@ in the `OpenStack wiki`__. __ http://docs.openstack.org/infra/manual/developers.html -This code is based on original the client previously included with +This code is based on the original client previously included with `OpenStack's Swift`__ The python-swiftclient is licensed under the Apache License like the rest of OpenStack. diff --git a/swiftclient/client.py b/swiftclient/client.py index 807cb3d..f23f917 100644 --- a/swiftclient/client.py +++ b/swiftclient/client.py @@ -804,7 +804,8 @@ def post_account(url, token, headers, http_conn=None, response_dict=None, def get_container(url, token, container, marker=None, limit=None, prefix=None, delimiter=None, end_marker=None, path=None, http_conn=None, - full_listing=False, service_token=None, headers=None): + full_listing=False, service_token=None, headers=None, + query_string=None): """ Get a listing of objects for the container. @@ -823,6 +824,7 @@ def get_container(url, token, container, marker=None, limit=None, of 10000 listings :param service_token: service auth token :param headers: additional headers to include in the request + :param query_string: if set will be appended with '?' to generated path :returns: a tuple of (response headers, a list of objects) The response headers will be a dict and all header names will be lowercase. :raises ClientException: HTTP GET request failed @@ -866,6 +868,8 @@ def get_container(url, token, container, marker=None, limit=None, qs += '&end_marker=%s' % quote(end_marker) if path: qs += '&path=%s' % quote(path) + if query_string: + qs += '&%s' % query_string.lstrip('?') if service_token: headers['X-Service-Token'] = service_token method = 'GET' @@ -927,7 +931,7 @@ def head_container(url, token, container, http_conn=None, headers=None, def put_container(url, token, container, headers=None, http_conn=None, - response_dict=None, service_token=None): + response_dict=None, service_token=None, query_string=None): """ Create a container @@ -940,6 +944,7 @@ def put_container(url, token, container, headers=None, http_conn=None, :param response_dict: an optional dictionary into which to place the response - status, reason and headers :param service_token: service auth token + :param query_string: if set will be appended with '?' to generated path :raises ClientException: HTTP PUT request failed """ if http_conn: @@ -955,6 +960,8 @@ def put_container(url, token, container, headers=None, http_conn=None, headers['X-Service-Token'] = service_token if 'content-length' not in (k.lower() for k in headers): headers['Content-Length'] = '0' + if query_string: + path += '?' + query_string.lstrip('?') conn.request(method, path, '', headers) resp = conn.getresponse() body = resp.read() @@ -1008,7 +1015,8 @@ def post_container(url, token, container, headers, http_conn=None, def delete_container(url, token, container, http_conn=None, - response_dict=None, service_token=None): + response_dict=None, service_token=None, + query_string=None): """ Delete a container @@ -1020,6 +1028,7 @@ def delete_container(url, token, container, http_conn=None, :param response_dict: an optional dictionary into which to place the response - status, reason and headers :param service_token: service auth token + :param query_string: if set will be appended with '?' to generated path :raises ClientException: HTTP DELETE request failed """ if http_conn: @@ -1030,6 +1039,8 @@ def delete_container(url, token, container, http_conn=None, headers = {'X-Auth-Token': token} if service_token: headers['X-Service-Token'] = service_token + if query_string: + path += '?' + query_string.lstrip('?') method = 'DELETE' conn.request(method, path, '', headers) resp = conn.getresponse() @@ -1592,7 +1603,7 @@ class Connection(object): def get_container(self, container, marker=None, limit=None, prefix=None, delimiter=None, end_marker=None, path=None, - full_listing=False, headers=None): + full_listing=False, headers=None, query_string=None): """Wrapper for :func:`get_container`""" # TODO(unknown): With full_listing=True this will restart the entire # listing with each retry. Need to make a better version that just @@ -1600,22 +1611,27 @@ class Connection(object): return self._retry(None, get_container, container, marker=marker, limit=limit, prefix=prefix, delimiter=delimiter, end_marker=end_marker, path=path, - full_listing=full_listing, headers=headers) + full_listing=full_listing, headers=headers, + query_string=query_string) - def put_container(self, container, headers=None, response_dict=None): + def put_container(self, container, headers=None, response_dict=None, + query_string=None): """Wrapper for :func:`put_container`""" return self._retry(None, put_container, container, headers=headers, - response_dict=response_dict) + response_dict=response_dict, + query_string=query_string) def post_container(self, container, headers, response_dict=None): """Wrapper for :func:`post_container`""" return self._retry(None, post_container, container, headers, response_dict=response_dict) - def delete_container(self, container, response_dict=None): + def delete_container(self, container, response_dict=None, + query_string=None): """Wrapper for :func:`delete_container`""" return self._retry(None, delete_container, container, - response_dict=response_dict) + response_dict=response_dict, + query_string=query_string) def head_object(self, container, obj, headers=None): """Wrapper for :func:`head_object`""" diff --git a/tests/unit/test_swiftclient.py b/tests/unit/test_swiftclient.py index a51fe1a..dda37fd 100644 --- a/tests/unit/test_swiftclient.py +++ b/tests/unit/test_swiftclient.py @@ -746,6 +746,16 @@ class TestGetContainer(MockHttpTest): }), ]) + def test_query_string(self): + c.http_connection = self.fake_http_connection( + 200, query_string="format=json&hello=20", body=b'[]') + c.get_container('http://www.test.com', 'asdf', 'asdf', + query_string="hello=20") + self.assertRequests([ + ('GET', '/asdf?format=json&hello=20', '', { + 'x-auth-token': 'asdf'}), + ]) + class TestHeadContainer(MockHttpTest): @@ -805,6 +815,17 @@ class TestPutContainer(MockHttpTest): 'content-length': '0'}), ]) + def test_query_string(self): + c.http_connection = self.fake_http_connection(200, + query_string="hello=20") + c.put_container('http://www.test.com', 'asdf', 'asdf', + query_string="hello=20") + for req in self.iter_request_log(): + self.assertEqual(req['method'], 'PUT') + self.assertEqual(req['parsed_path'].path, '/asdf') + self.assertEqual(req['parsed_path'].query, 'hello=20') + self.assertEqual(req['headers']['x-auth-token'], 'asdf') + class TestDeleteContainer(MockHttpTest): @@ -817,6 +838,16 @@ class TestDeleteContainer(MockHttpTest): 'x-auth-token': 'token'}), ]) + def test_query_string(self): + c.http_connection = self.fake_http_connection(200, + query_string="hello=20") + c.delete_container('http://www.test.com', 'token', 'container', + query_string="hello=20") + self.assertRequests([ + ('DELETE', 'http://www.test.com/container?hello=20', '', { + 'x-auth-token': 'token'}) + ]) + class TestGetObject(MockHttpTest): |