diff --git a/slumber/__init__.py b/slumber/__init__.py index 586ebca..7aba466 100644 --- a/slumber/__init__.py +++ b/slumber/__init__.py @@ -86,6 +86,7 @@ def __call__(self, id=None, format=None, url_override=None): def _request(self, method, data=None, files=None, params=None): serializer = self._store["serializer"] url = self.url() + timeout = self._store.get("timeout", None) headers = {"accept": serializer.get_content_type()} @@ -94,7 +95,7 @@ def _request(self, method, data=None, files=None, params=None): if data is not None: data = serializer.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: exception_class = exceptions.HttpNotFoundError if resp.status_code == 404 else exceptions.HttpClientError @@ -193,7 +194,7 @@ class API(ResourceAttributesMixin, object): resource_class = Resource - 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) @@ -209,6 +210,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 ba3e977..01ac710 100644 --- a/tests/resource.py +++ b/tests/resource.py @@ -37,7 +37,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() @@ -66,7 +67,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() @@ -163,7 +165,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'}) @@ -192,7 +195,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'}) @@ -226,7 +230,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'}) @@ -255,7 +260,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'}) @@ -289,7 +295,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'}) @@ -318,7 +325,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'}) @@ -377,7 +385,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() @@ -543,3 +552,19 @@ def test_unicode_decodable_response(self): resp = self.base_resource.post(data={'foo': 'bar'}) expected = b'Pr\xc3\xa9paratoire'.decode('utf8') self.assertEqual(resp['result'], expected) + + def test_connect_timeout(self): + + client = slumber.API(base_url='http://httpbin.org/', append_slash=False, timeout=(0.00000000001, None)) + + with self.assertRaises(requests.exceptions.ConnectTimeout): + client.delay(10).get() + assert False, "The connect() request should time out." + + def test_read_timeout(self): + + client = slumber.API(base_url='http://httpbin.org/', append_slash=False, timeout=(None, 0.01)) + + with self.assertRaises(requests.exceptions.ReadTimeout): + client.delay(10).get() + assert False, "The recv() request should time out."