From e00e3d8b67e960288efdc443b0a3100c8e1f8fe8 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Wed, 18 May 2016 17:04:59 +0200 Subject: [PATCH 1/5] added test + fixes --- lib/vsc/utils/rest.py | 22 +++++++++++++++++----- setup.py | 2 +- test/rest.py | 21 +++++++++++++++------ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/lib/vsc/utils/rest.py b/lib/vsc/utils/rest.py index 7dcff2dd..10db7545 100644 --- a/lib/vsc/utils/rest.py +++ b/lib/vsc/utils/rest.py @@ -70,7 +70,8 @@ class Client(object): USER_AGENT = 'vsc-rest-client' - def __init__(self, url, username=None, password=None, token=None, token_type='Token', user_agent=None, append_slash=False): + def __init__(self, url, username=None, password=None, token=None, token_type='Token', user_agent=None, + append_slash=False): """ Create a Client object, this client can consume a REST api hosted at host/endpoint @@ -124,15 +125,18 @@ def head(self, url, headers=None, **params): url += self.urlencode(params) return self.request(self.HEAD, url, None, headers) - def delete(self, url, headers=None, **params): + def delete(self, url, headers=None, body=None, **params): """ - Do a http delete request on the given url with given headers and parameters + Do a http delete request on the given url with given headers, body and parameters Parameters is a dictionary that will will be urlencoded """ if self.append_slash: url += '/' url += self.urlencode(params) - return self.request(self.DELETE, url, None, headers) + if headers is None: + headers = {} + headers['Content-Type'] = 'application/json' + return self.request(self.DELETE, url, json.dumps(body), headers) def post(self, url, body=None, headers=None, **params): """ @@ -142,6 +146,8 @@ def post(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) + if headers is None: + headers = {} headers['Content-Type'] = 'application/json' return self.request(self.POST, url, json.dumps(body), headers) @@ -153,6 +159,8 @@ def put(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) + if headers is None: + headers = {} headers['Content-Type'] = 'application/json' return self.request(self.PUT, url, json.dumps(body), headers) @@ -164,6 +172,8 @@ def patch(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) + if headers is None: + headers = {} headers['Content-Type'] = 'application/json' return self.request(self.PATCH, url, json.dumps(body), headers) @@ -175,7 +185,7 @@ def request(self, method, url, body, headers): headers['Authorization'] = self.auth_header headers['User-Agent'] = self.user_agent fancylogger.getLogger().debug('cli request: %s, %s, %s, %s', method, url, body, headers) - #TODO: in recent python: Context manager + # TODO: in recent python: Context manager conn = self.get_connection(method, url, body, headers) status = conn.code body = conn.read() @@ -290,3 +300,5 @@ def __init__(self, *args, **kwargs): def __getattr__(self, key): """Get an attribute, we will build a request with it""" return RequestBuilder(self.client).__getattr__(key) + + __getitem__ = __getattr__ diff --git a/setup.py b/setup.py index c4c51096..eb990a76 100755 --- a/setup.py +++ b/setup.py @@ -39,7 +39,7 @@ VSC_INSTALL_REQ_VERSION = '0.10.1' PACKAGE = { - 'version': '2.5.0', + 'version': '2.5.1', 'author': [sdw, jt, ag, kh], 'maintainer': [sdw, jt, ag, kh], # as long as 1.0.0 is not out, vsc-base should still provide vsc.fancylogger diff --git a/test/rest.py b/test/rest.py index 1c3bfc71..eb5ee84d 100644 --- a/test/rest.py +++ b/test/rest.py @@ -29,6 +29,7 @@ @author: Jens Timmerman (Ghent University) """ import os +from urllib2 import HTTPError from vsc.install.testing import TestCase @@ -68,9 +69,17 @@ def test_client(self): self.assertEqual(status, 200) self.assertEqual(body['merge_commit_sha'], u'fba3e13815f3d2a9dfbd2f89f1cf678dd58bb1f1') -def suite(): - """ returns all the testcases in this module """ - return TestLoader().loadTestsFromTestCase(RestClientTest) - -if __name__ == '__main__': - main() + def test_request_methods(self): + """Test all request methods""" + status, body = self.client.head() + self.assertEqual(status, 200) + try: + status, body = self.client.user.emails.post(body='jens.timmerman@ugent.be') + self.assertTrue(False, 'posting to unauthorized endpoint did not trhow a http error') + except HTTPError: + pass + try: + status, body = self.client.user.emails.delete(body='jens.timmerman@ugent.be') + self.assertTrue(False, 'deleting to unauthorized endpoint did not trhow a http error') + except HTTPError: + pass From 09e9d61983fa3d3e91f922dc4b50d93d140e81d6 Mon Sep 17 00:00:00 2001 From: Jens Timmerman Date: Wed, 18 May 2016 17:10:15 +0200 Subject: [PATCH 2/5] don't do the getittem thingy --- lib/vsc/utils/rest.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/vsc/utils/rest.py b/lib/vsc/utils/rest.py index 10db7545..4dc68cd0 100644 --- a/lib/vsc/utils/rest.py +++ b/lib/vsc/utils/rest.py @@ -300,5 +300,3 @@ def __init__(self, *args, **kwargs): def __getattr__(self, key): """Get an attribute, we will build a request with it""" return RequestBuilder(self.client).__getattr__(key) - - __getitem__ = __getattr__ From 05dbd75be5b62a267a4065a3e380ee58100ffb69 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Thu, 19 May 2016 11:43:55 +0200 Subject: [PATCH 3/5] fix remarks --- lib/vsc/utils/rest.py | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/lib/vsc/utils/rest.py b/lib/vsc/utils/rest.py index 4dc68cd0..b13d4449 100644 --- a/lib/vsc/utils/rest.py +++ b/lib/vsc/utils/rest.py @@ -110,7 +110,7 @@ def get(self, url, headers=None, **params): Do a http get request on the given url with given headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: + if self.append_slash and not url.endswith('/'): url += '/' url += self.urlencode(params) return self.request(self.GET, url, None, headers) @@ -133,10 +133,7 @@ def delete(self, url, headers=None, body=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) - if headers is None: - headers = {} - headers['Content-Type'] = 'application/json' - return self.request(self.DELETE, url, json.dumps(body), headers) + return self.request(self.DELETE, url, json.dumps(body), headers, content_type='application/json') def post(self, url, body=None, headers=None, **params): """ @@ -146,10 +143,7 @@ def post(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) - if headers is None: - headers = {} - headers['Content-Type'] = 'application/json' - return self.request(self.POST, url, json.dumps(body), headers) + return self.request(self.POST, url, json.dumps(body), headers, content_type='application/json') def put(self, url, body=None, headers=None, **params): """ @@ -159,10 +153,7 @@ def put(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) - if headers is None: - headers = {} - headers['Content-Type'] = 'application/json' - return self.request(self.PUT, url, json.dumps(body), headers) + return self.request(self.PUT, url, json.dumps(body), headers, content_type='application/json') def patch(self, url, body=None, headers=None, **params): """ @@ -172,15 +163,16 @@ def patch(self, url, body=None, headers=None, **params): if self.append_slash: url += '/' url += self.urlencode(params) - if headers is None: - headers = {} - headers['Content-Type'] = 'application/json' - return self.request(self.PATCH, url, json.dumps(body), headers) + return self.request(self.PATCH, url, json.dumps(body), headers, content_type='application/json') - def request(self, method, url, body, headers): + def request(self, method, url, body, headers, content_type=None): """Low-level networking. All HTTP-method methods call this""" if headers is None: headers = {} + + if content_type is not None: + headers['Content-Type'] = content_type + if self.auth_header is not None: headers['Authorization'] = self.auth_header headers['User-Agent'] = self.user_agent From 080cc376b244af75455a0f096a0519f5bd3065d7 Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Thu, 19 May 2016 11:55:49 +0200 Subject: [PATCH 4/5] flesh out append_slash --- lib/vsc/utils/rest.py | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/vsc/utils/rest.py b/lib/vsc/utils/rest.py index b13d4449..e6ce35a4 100644 --- a/lib/vsc/utils/rest.py +++ b/lib/vsc/utils/rest.py @@ -105,14 +105,18 @@ def __init__(self, url, username=None, password=None, token=None, token_type='To elif token is not None: self.auth_header = '%s %s' % (token_type, token) + def _append_slash_to(self, url): + """Append slash to specified URL, if desired and needed.""" + if self.append_slash and not url.endswith('/'): + url += '/' + return url + def get(self, url, headers=None, **params): """ Do a http get request on the given url with given headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash and not url.endswith('/'): - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.GET, url, None, headers) def head(self, url, headers=None, **params): @@ -120,9 +124,7 @@ def head(self, url, headers=None, **params): Do a http head request on the given url with given headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.HEAD, url, None, headers) def delete(self, url, headers=None, body=None, **params): @@ -130,9 +132,7 @@ def delete(self, url, headers=None, body=None, **params): Do a http delete request on the given url with given headers, body and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.DELETE, url, json.dumps(body), headers, content_type='application/json') def post(self, url, body=None, headers=None, **params): @@ -140,9 +140,7 @@ def post(self, url, body=None, headers=None, **params): Do a http post request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.POST, url, json.dumps(body), headers, content_type='application/json') def put(self, url, body=None, headers=None, **params): @@ -150,9 +148,7 @@ def put(self, url, body=None, headers=None, **params): Do a http put request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.PUT, url, json.dumps(body), headers, content_type='application/json') def patch(self, url, body=None, headers=None, **params): @@ -160,9 +156,7 @@ def patch(self, url, body=None, headers=None, **params): Do a http patch request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - if self.append_slash: - url += '/' - url += self.urlencode(params) + url = self._append_slash_to(url) + self.urlencoded(params) return self.request(self.PATCH, url, json.dumps(body), headers, content_type='application/json') def request(self, method, url, body, headers, content_type=None): From f86871e09f7fa35ab02ad19c15016dd0f03fde7e Mon Sep 17 00:00:00 2001 From: Kenneth Hoste Date: Thu, 19 May 2016 12:02:31 +0200 Subject: [PATCH 5/5] fix typo --- lib/vsc/utils/rest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/vsc/utils/rest.py b/lib/vsc/utils/rest.py index e6ce35a4..9db99899 100644 --- a/lib/vsc/utils/rest.py +++ b/lib/vsc/utils/rest.py @@ -116,7 +116,7 @@ def get(self, url, headers=None, **params): Do a http get request on the given url with given headers and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.GET, url, None, headers) def head(self, url, headers=None, **params): @@ -124,7 +124,7 @@ def head(self, url, headers=None, **params): Do a http head request on the given url with given headers and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.HEAD, url, None, headers) def delete(self, url, headers=None, body=None, **params): @@ -132,7 +132,7 @@ def delete(self, url, headers=None, body=None, **params): Do a http delete request on the given url with given headers, body and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.DELETE, url, json.dumps(body), headers, content_type='application/json') def post(self, url, body=None, headers=None, **params): @@ -140,7 +140,7 @@ def post(self, url, body=None, headers=None, **params): Do a http post request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.POST, url, json.dumps(body), headers, content_type='application/json') def put(self, url, body=None, headers=None, **params): @@ -148,7 +148,7 @@ def put(self, url, body=None, headers=None, **params): Do a http put request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.PUT, url, json.dumps(body), headers, content_type='application/json') def patch(self, url, body=None, headers=None, **params): @@ -156,7 +156,7 @@ def patch(self, url, body=None, headers=None, **params): Do a http patch request on the given url with given body, headers and parameters Parameters is a dictionary that will will be urlencoded """ - url = self._append_slash_to(url) + self.urlencoded(params) + url = self._append_slash_to(url) + self.urlencode(params) return self.request(self.PATCH, url, json.dumps(body), headers, content_type='application/json') def request(self, method, url, body, headers, content_type=None):