New implementation of safe_mode. Now, we throw exceptions in models.py regardless...
authorJosh Imhoff <joshimhoff13@gmail.com>
Wed, 9 May 2012 18:47:29 +0000 (14:47 -0400)
committerJosh Imhoff <joshimhoff13@gmail.com>
Wed, 9 May 2012 18:47:29 +0000 (14:47 -0400)
AUTHORS.rst
requests/api.py
requests/cookies.py
requests/models.py
requests/safe_mode.py [new file with mode: 0644]

index b6002ec..d24cf21 100644 (file)
@@ -100,3 +100,4 @@ Patches and Suggestions
 - Rohan Jain (crodjer)
 - Justin Barber <barber.justin@gmail.com>
 - Roman Haritonov <@reclosedev>
+- Josh Imhoff <joshimhoff13@gmail.com>
index e0bf346..4fc3070 100644 (file)
@@ -12,7 +12,9 @@ This module implements the Requests API.
 """
 
 from . import sessions
+from .safe_mode import catch_exceptions_if_in_safe_mode
 
+@catch_exceptions_if_in_safe_mode
 def request(method, url, **kwargs):
     """Constructs and sends a :class:`Request <Request>`.
     Returns :class:`Response <Response>` object.
index 0e0dd67..41d0fab 100644 (file)
@@ -94,13 +94,10 @@ def extract_cookies_to_jar(jar, request, response):
     :param response: urllib3.HTTPResponse object
     """
     # the _original_response field is the wrapped httplib.HTTPResponse object,
-    # and in safe mode, it may be None if the request didn't actually complete.
-    # in that case, just skip the cookie extraction.
-    if response._original_response is not None:
-        req = MockRequest(request)
-        # pull out the HTTPMessage with the headers and put it in the mock:
-        res = MockResponse(response._original_response.msg)
-        jar.extract_cookies(res, req)
+    req = MockRequest(request)
+    # pull out the HTTPMessage with the headers and put it in the mock:
+    res = MockResponse(response._original_response.msg)
+    jar.extract_cookies(res, req)
 
 def get_cookie_header(jar, request):
     """Produce an appropriate Cookie header string to be sent with `request`, or None."""
index beb8f14..d9bee4e 100644 (file)
@@ -204,10 +204,8 @@ class Request(object):
                 response.cookies = self.cookies
 
                 # Save cookies in Session.
-                # (in safe mode, cookies may be None if the request didn't succeed)
-                if self.cookies is not None:
-                    for cookie in self.cookies:
-                        self.session.cookies.set_cookie(cookie)
+                for cookie in self.cookies:
+                    self.session.cookies.set_cookie(cookie)
 
                 # No exceptions were harmed in the making of this request.
                 response.error = getattr(resp, 'error', None)
@@ -587,53 +585,34 @@ class Request(object):
             r = dispatch_hook('pre_send', self.hooks, self)
             self.__dict__.update(r.__dict__)
 
+            # catch urllib3 exceptions and throw Requests exceptions
             try:
-                # The inner try .. except re-raises certain exceptions as
-                # internal exception types; the outer suppresses exceptions
-                # when safe mode is set.
-                try:
-                    # Send the request.
-                    r = conn.urlopen(
-                        method=self.method,
-                        url=self.path_url,
-                        body=body,
-                        headers=self.headers,
-                        redirect=False,
-                        assert_same_host=False,
-                        preload_content=False,
-                        decode_content=False,
-                        retries=self.config.get('max_retries', 0),
-                        timeout=self.timeout,
-                    )
-                    self.sent = True
-
-                except MaxRetryError as e:
-                    raise ConnectionError(e)
-
-                except (_SSLError, _HTTPError) as e:
-                    if self.verify and isinstance(e, _SSLError):
-                        raise SSLError(e)
-
-                    raise Timeout('Request timed out.')
-
-            except RequestException as e:
-                if self.config.get('safe_mode', False):
-                    # In safe mode, catch the exception and attach it to
-                    # a blank urllib3.HTTPResponse object.
-                    r = HTTPResponse()
-                    r.error = e
-                else:
-                    raise
+                # Send the request.
+                r = conn.urlopen(
+                    method=self.method,
+                    url=self.path_url,
+                    body=body,
+                    headers=self.headers,
+                    redirect=False,
+                    assert_same_host=False,
+                    preload_content=False,
+                    decode_content=False,
+                    retries=self.config.get('max_retries', 0),
+                    timeout=self.timeout,
+                )
+                self.sent = True
+
+            except MaxRetryError as e:
+                raise ConnectionError(e)
+
+            except (_SSLError, _HTTPError) as e:
+                if self.verify and isinstance(e, _SSLError):
+                    raise SSLError(e)
+
+                raise Timeout('Request timed out.')
 
             # build_response can throw TooManyRedirects
-            try:
-                self._build_response(r)
-            except RequestException as e:
-                if self.config.get('safe_mode', False):
-                    # In safe mode, catch the exception
-                    self.response.error = e
-                else:
-                    raise
+            self._build_response(r)
 
             # Response manipulation hook.
             self.response = dispatch_hook('response', self.hooks, self.response)
diff --git a/requests/safe_mode.py b/requests/safe_mode.py
new file mode 100644 (file)
index 0000000..7a0f218
--- /dev/null
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+
+"""
+requests.safe_mode
+~~~~~~~~~~~~
+
+This module contains a decorator that implements safe_mode.
+
+:copyright: (c) 2012 by Kenneth Reitz.
+:license: ISC, see LICENSE for more details.
+
+"""
+
+from .models import Response
+from .exceptions import RequestException, ConnectionError, HTTPError
+from .packages.urllib3.response import HTTPResponse
+
+def catch_exceptions_if_in_safe_mode(function):
+    """New implementation of safe_mode. We catch all exceptions at the API level
+    and then return a blank Response object with the error field filled. This decorator
+    wraps request() in api.py.
+    """
+    
+    def wrapped(method, url, **kwargs):
+        # if save_mode, we catch exceptions and fill error field
+        if (kwargs.get('config') and kwargs.get('config').get('safe_mode')) or (kwargs.get('session') 
+                                            and kwargs.get('session').config.get('safe_mode')):
+            try:
+                return function(method, url, **kwargs)
+            except (RequestException, ConnectionError, HTTPError) as e:
+                r = Response()
+                r.error = e
+                r.raw = HTTPResponse() # otherwise, tests fail
+                r.status_code = 0 # with this status_code, content returns None
+                return r
+        return function(method, url, **kwargs)
+    return wrapped