Skip to content

Commit 67abd3e

Browse files
committed
Merge pull request #5 from ardeois/master
Ability to use `POST` as default request method
2 parents 8fe8e96 + 400c49c commit 67abd3e

File tree

5 files changed

+107
-35
lines changed

5 files changed

+107
-35
lines changed

README.rst

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,39 @@
1-
# Ubersmith API Client for Python
1+
Ubersmith API Client for Python
2+
===============================
23

34
.. image:: https://travis-ci.org/internap/python-ubersmithclient.svg?branch=master
45
:target: https://travis-ci.org/internap/python-ubersmithclient
56

67
.. image:: https://img.shields.io/pypi/v/ubersmith_client.svg?style=flat
78
:target: https://pypi.python.org/pypi/ubersmith_client
89

9-
# Usage
10+
Usage
11+
-----
12+
.. code:: python
1013
11-
>>> import ubersmith_client
12-
>>> api = ubersmith_client.api.init('http://ubersmith.com/api/2.0/', 'username', 'password')
13-
>>> api.client.count()
14-
u'264'
15-
>>> api.client.latest_client()
16-
1265
14+
import ubersmith_client
15+
16+
api = ubersmith_client.api.init('http://ubersmith.com/api/2.0/', 'username', 'password')
17+
api.client.count()
18+
>>> u'264'
19+
api.client.latest_client()
20+
>>> 1265
21+
22+
API
23+
---------
24+
25+
**ubersmith_client.api.init(url, user, password, timeout, use_http_post)**
26+
:url:
27+
URL of your API
28+
29+
*Example:* ``http://ubersmith.example.org/api/2.0/``
30+
31+
:user: API username
32+
:password: API Password or token
33+
:timeout: api timeout given to requests
34+
35+
*Default:* ``60``
36+
:use_http_post:
37+
Use `POST` requests instead of `GET`
38+
39+
*Default:* ``False``

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
requests<=2.9.1
2+
six>=1.10.0

tests/api_test.py

Lines changed: 61 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,17 @@
1313
# limitations under the License.
1414
import base64
1515
import unittest
16+
import six.moves.urllib.parse as urllib_parse
17+
1618
import requests
1719

1820
from flexmock import flexmock, flexmock_teardown
1921
from hamcrest import assert_that, equal_to, raises, calling
2022
import requests_mock
2123
from requests_mock.exceptions import NoMockAddress
24+
import ubersmith_client
2225
from ubersmith_client import api
23-
from ubersmith_client.exceptions import UbersmithException, BadRequest, UnknownError, Forbidden, NotFound, Unauthorized
26+
from ubersmith_client.exceptions import BadRequest, UnknownError, Forbidden, NotFound, Unauthorized
2427
from tests.ubersmith_json.response_data_structure import a_response_data
2528

2629

@@ -62,7 +65,7 @@ def test_api_method_returns_with_arguments(self, request_mock):
6265
self.expect_a_ubersmith_call(request_mock, method="device.ip_group_list", fac_id='1', client_id='30001',
6366
data=data)
6467

65-
ubersmith_api = api.init(self.url, self.username, self.password)
68+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
6669
response = ubersmith_api.device.ip_group_list(fac_id=1, client_id=30001)
6770

6871
assert_that(response, equal_to(json_data))
@@ -71,15 +74,15 @@ def test_api_method_returns_with_arguments(self, request_mock):
7174
def test_api_raises_exception_with_if_data_status_is_false(self, request_mock):
7275
data = a_response_data(status=False, error_code=1, error_message="invalid method specified: client.miss",
7376
data=None)
74-
ubersmith_api = api.init(self.url, self.username, self.password)
77+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
7578

7679
self.expect_a_ubersmith_call(request_mock, method="client.miss", data=data)
77-
assert_that(calling(ubersmith_api.client.miss), raises(UbersmithException))
80+
assert_that(calling(ubersmith_api.client.miss), raises(ubersmith_client.exceptions.UbersmithException))
7881

7982
@requests_mock.mock()
8083
def test_api_raises_exception_for_invalid_status_code(self, request_mock):
8184
method = "client.list"
82-
ubersmith_api = api.init(self.url, self.username, self.password)
85+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
8386

8487
self.expect_a_ubersmith_call(request_mock, method=method, status_code=400)
8588

@@ -101,7 +104,7 @@ def test_api_raises_exception_for_invalid_status_code(self, request_mock):
101104
def test_api_with_a_false_identifier(self, request_mock):
102105
method = "client.list"
103106
self.expect_a_ubersmith_call(request_mock, method=method)
104-
ubersmith_api = api.init(self.url, 'not_hapi', 'lol')
107+
ubersmith_api = ubersmith_client.api.init(self.url, 'not_hapi', 'lol')
105108

106109
with self.assertRaises(NoMockAddress) as ube:
107110
ubersmith_api.client.list()
@@ -119,7 +122,7 @@ def test_api_http_get_method(self, request_mock):
119122
self.expect_a_ubersmith_call(request_mock, method="device.ip_group_list", fac_id='666', client_id='30666',
120123
data=data)
121124

122-
ubersmith_api = api.init(self.url, self.username, self.password)
125+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
123126
response = ubersmith_api.device.ip_group_list.http_get(fac_id=666, client_id=30666)
124127

125128
assert_that(response, equal_to(json_data))
@@ -135,7 +138,23 @@ def test_api_http_get_method_default(self, request_mock):
135138
self.expect_a_ubersmith_call(request_mock, method="device.ip_group_list", fac_id='666', client_id='30666',
136139
data=data)
137140

138-
ubersmith_api = api.init(self.url, self.username, self.password)
141+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
142+
response = ubersmith_api.device.ip_group_list(fac_id=666, client_id=30666)
143+
144+
assert_that(response, equal_to(json_data))
145+
146+
@requests_mock.mock()
147+
def test_api_http_post_method_default(self, request_mock):
148+
json_data = {
149+
'group_id': '666',
150+
'client_id': '30666',
151+
'assignment_count': '1'
152+
}
153+
data = a_response_data(data=json_data)
154+
self.expect_a_ubersmith_call_post(request_mock, method='device.ip_group_list', fac_id='666', client_id='30666',
155+
response_body=data)
156+
157+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password, use_http_post=True)
139158
response = ubersmith_api.device.ip_group_list(fac_id=666, client_id=30666)
140159

141160
assert_that(response, equal_to(json_data))
@@ -151,10 +170,13 @@ def test_api_http_post_method_result_200(self, request_mock):
151170

152171
self.expect_a_ubersmith_call_post(
153172
request_mock,
173+
method='support.ticket_submit',
174+
body='ticket body',
175+
subject='ticket subject',
154176
response_body=json_data,
155177
)
156178

157-
ubersmith_api = api.init(self.url, self.username, self.password)
179+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
158180
response = ubersmith_api.support.ticket_submit.http_post(body='ticket body', subject='ticket subject')
159181

160182
assert_that(response, equal_to(json_data.get('data')))
@@ -170,18 +192,19 @@ def test_api_http_post_method_raises_on_result_414(self, request_mock):
170192

171193
self.expect_a_ubersmith_call_post(
172194
request_mock,
195+
method='support.ticket_submit',
173196
response_body=json_data,
174197
status_code=414
175198
)
176199

177-
ubersmith_api = api.init(self.url, self.username, self.password)
200+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
178201

179202
assert_that(calling(ubersmith_api.support.ticket_submit.http_post), raises(UnknownError))
180203

181204
def test_api_http_timeout(self):
182205
payload = dict(status=True, data="plop")
183206
response = flexmock(status_code=200, json=lambda: payload)
184-
ubersmith_api = api.init(self.url, self.username, self.password, 666)
207+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password, 666)
185208

186209
flexmock(requests).should_receive("get").with_args(
187210
url=self.url, auth=(self.username, self.password), timeout=666, params={'method': 'uber.method_list'}
@@ -192,7 +215,7 @@ def test_api_http_timeout(self):
192215
def test_api_http_default_timeout(self):
193216
payload = dict(status=True, data="plop")
194217
response = flexmock(status_code=200, json=lambda: payload)
195-
ubersmith_api = api.init(self.url, self.username, self.password)
218+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
196219

197220
flexmock(requests).should_receive("get").with_args(
198221
url=self.url, auth=(self.username, self.password), timeout=60, params={'method': 'uber.method_list'}
@@ -211,28 +234,46 @@ def test_api_http_post_method_raises_on_result_500(self, request_mock):
211234

212235
self.expect_a_ubersmith_call_post(
213236
request_mock,
237+
method='support.ticket_submit',
214238
response_body=json_data,
215239
)
216240

217-
ubersmith_api = api.init(self.url, self.username, self.password)
241+
ubersmith_api = ubersmith_client.api.init(self.url, self.username, self.password)
218242

219-
assert_that(calling(ubersmith_api.support.ticket_submit.http_post), raises(UbersmithException))
243+
assert_that(calling(ubersmith_api.support.ticket_submit.http_post),
244+
raises(ubersmith_client.exceptions.UbersmithException))
220245

221246
def expect_a_ubersmith_call(self, request_mock, method, data=None, status_code=200, **kwargs):
222-
url = self.url + '?method=' + method
223-
if kwargs:
224-
for key, value in kwargs.items():
225-
url += '&' + key + '=' + value
247+
url = self.url + '?' + get_url_params(method, **kwargs)
226248
headers = {
227249
'Content-Type': 'application/json',
228250
}
229251
request_mock.get(url, json=data, headers=headers, request_headers={
230252
'Authorization': self.get_auth_header()
231253
}, status_code=status_code)
232254

233-
def expect_a_ubersmith_call_post(self, request_mock, response_body=None, status_code=200):
234-
request_mock.post(self.url, json=response_body, status_code=status_code)
255+
def expect_a_ubersmith_call_post(self, request_mock, method, response_body=None, status_code=200, **kwargs):
256+
headers = {
257+
'Content-Type': 'application/json',
258+
}
259+
expected_text = get_url_params(method, **kwargs)
260+
261+
def response_callback(request, context):
262+
expected_params = urllib_parse.parse_qs(expected_text)
263+
parsed_params = urllib_parse.parse_qs(request.text)
264+
assert_that(parsed_params, equal_to(expected_params))
265+
return response_body
266+
267+
request_mock.post(self.url, json=response_callback, headers=headers, request_headers={
268+
'Authorization': self.get_auth_header(),
269+
'Content-Type': 'application/x-www-form-urlencoded'
270+
}, status_code=status_code)
235271

236272
def get_auth_header(self):
237273
auth = base64.b64encode((self.username + ':' + self.password).encode('utf-8'))
238274
return 'Basic ' + auth.decode('utf-8')
275+
276+
277+
def get_url_params(method, **kwargs):
278+
kwargs['method'] = method
279+
return urllib_parse.urlencode(kwargs)

ubersmith_client/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@
1010
# distributed under the License is distributed on an "AS IS" BASIS,
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
13-
# limitations under the License.
13+
14+
from . import api
15+
from . import exceptions

ubersmith_client/api.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,42 @@
1616
from ubersmith_client.exceptions import UbersmithException, get_exception_for
1717

1818

19-
def init(url, user, password, timeout=60):
20-
return UbersmithApi(url, user, password, timeout)
19+
def init(url, user, password, timeout=60, use_http_post=False):
20+
return UbersmithApi(url, user, password, timeout, use_http_post)
2121

2222

2323
class UbersmithApi(object):
24-
def __init__(self, url, user, password, timeout):
24+
def __init__(self, url, user, password, timeout, use_http_post):
2525
self.url = url
2626
self.user = user
2727
self.password = password
2828
self.timeout = timeout
29+
self.use_http_post = use_http_post
2930

3031
def __getattr__(self, module):
31-
return UbersmithRequest(self.url, self.user, self.password, module, self.timeout)
32+
return UbersmithRequest(self.url, self.user, self.password, module, self.timeout, self.use_http_post)
3233

3334

3435
class UbersmithRequest(object):
35-
def __init__(self, url, user, password, module, timeout):
36+
def __init__(self, url, user, password, module, timeout, use_http_post):
3637
self.url = url
3738
self.user = user
3839
self.password = password
3940
self.module = module
4041
self.methods = []
4142
self.http_methods = {'GET': 'get', 'POST': 'post'}
4243
self.timeout = timeout
44+
self.use_http_post = use_http_post
4345

4446
def __getattr__(self, function):
4547
self.methods.append(function)
4648
return self
4749

4850
def __call__(self, **kwargs):
49-
return self.http_get(**kwargs)
51+
if self.use_http_post:
52+
return self.http_post(**kwargs)
53+
else:
54+
return self.http_get(**kwargs)
5055

5156
def process_request(self, http_method, **kwargs):
5257
callable_http_method = getattr(requests, http_method)

0 commit comments

Comments
 (0)