From 34c171c87a5dfe43e9c0c9f5c7f819ed2c6fc710 Mon Sep 17 00:00:00 2001 From: Josh Rowe Date: Tue, 2 Dec 2014 09:56:46 +0000 Subject: [PATCH] Add timeout to pass through to requests and add test --- slumber/__init__.py | 6 ++++-- tests/resource.py | 49 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 43 insertions(+), 12 deletions(-) diff --git a/slumber/__init__.py b/slumber/__init__.py index 3fc7fec..faf7dce 100644 --- a/slumber/__init__.py +++ b/slumber/__init__.py @@ -84,6 +84,7 @@ def __call__(self, id=None, format=None, url_override=None): def _request(self, method, data=None, files=None, params=None): s = self._store["serializer"] url = self.url() + timeout = self._store.get("timeout", None) headers = {"accept": s.get_content_type()} @@ -92,7 +93,7 @@ def _request(self, method, data=None, files=None, params=None): if data is not None: data = s.dumps(data) - resp = self._store["session"].request(method, url, data=data, params=params, files=files, headers=headers) + resp = self._store["session"].request(method, url, data=data, params=params, files=files, headers=headers, timeout=timeout) if 400 <= resp.status_code <= 499: raise exceptions.HttpClientError("Client Error %s: %s" % (resp.status_code, url), response=resp, content=resp.content) @@ -179,7 +180,7 @@ def delete(self, **kwargs): class API(ResourceAttributesMixin, object): - def __init__(self, base_url=None, auth=None, format=None, append_slash=True, session=None, serializer=None): + def __init__(self, base_url=None, auth=None, format=None, append_slash=True, session=None, serializer=None, timeout=None): if serializer is None: serializer = Serializer(default=format) @@ -193,6 +194,7 @@ def __init__(self, base_url=None, auth=None, format=None, append_slash=True, ses "append_slash": append_slash, "session": session, "serializer": serializer, + "timeout": timeout, } # Do some Checks for Required Values diff --git a/tests/resource.py b/tests/resource.py index c682e64..01e9b94 100644 --- a/tests/resource.py +++ b/tests/resource.py @@ -1,9 +1,11 @@ -import sys import mock import requests import slumber import slumber.serialize import unittest2 as unittest +import SimpleHTTPServer +import SocketServer +import threading from slumber import exceptions @@ -36,7 +38,8 @@ def test_get_200_json(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.get() @@ -65,7 +68,8 @@ def test_get_200_text(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.get() @@ -99,7 +103,8 @@ def test_post_201_redirect(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.post(data={'foo': 'bar'}) @@ -128,7 +133,8 @@ def test_post_decodable_response(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.post(data={'foo': 'bar'}) @@ -162,7 +168,8 @@ def test_patch_201_redirect(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.patch(data={'foo': 'bar'}) @@ -191,7 +198,8 @@ def test_patch_decodable_response(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.patch(data={'foo': 'bar'}) @@ -225,7 +233,8 @@ def test_put_201_redirect(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.put(data={'foo': 'bar'}) @@ -254,7 +263,8 @@ def test_put_decodable_response(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.put(data={'foo': 'bar'}) @@ -297,7 +307,8 @@ def test_get_200_subresource_json(self): data=None, files=None, params=None, - headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()} + headers={"content-type": self.base_resource._store["serializer"].get_content_type(), "accept": self.base_resource._store["serializer"].get_content_type()}, + timeout=None ) resp = self.base_resource.get() @@ -355,3 +366,21 @@ def test_api(self): def test_url(self): self.assertEqual(self.base_resource.url(), "http://example/api/v1/test") + + def test_timeout(self): + handler = SimpleHTTPServer.SimpleHTTPRequestHandler + httpd = TestTCPServer(("", 8001), handler) + httpd_thread = threading.Thread(target=httpd.serve_forever) + httpd_thread.setDaemon(True) + httpd_thread.start() + + client = slumber.API(base_url="http://localhost:8001", timeout=(0.000000000000001, 0.000000000000001)) + + with self.assertRaises(requests.exceptions.ConnectTimeout): + client.test.get() + + httpd.shutdown() + + +class TestTCPServer(SocketServer.TCPServer): + allow_reuse_address = True