Browse files

New implementation of safe_mode. Now, we throw exceptions in models.p…

…y regardless of safe_mode. We catch those exceptions at the API level and return a blank Response. See safe_mode.py for details.
  • Loading branch information...
1 parent 2d328d8 commit cff70e75b77ab61a8a57a25a4921acc5a5ef6ce1 @joshimhoff joshimhoff committed May 9, 2012
Showing with 71 additions and 55 deletions.
  1. +1 −0 AUTHORS.rst
  2. +2 −0 requests/api.py
  3. +4 −7 requests/cookies.py
  4. +27 −48 requests/models.py
  5. +37 −0 requests/safe_mode.py
View
1 AUTHORS.rst
@@ -100,3 +100,4 @@ Patches and Suggestions
- Rohan Jain (crodjer)
- Justin Barber <barber.justin@gmail.com>
- Roman Haritonov <@reclosedev>
+- Josh Imhoff <joshimhoff13@gmail.com>
View
2 requests/api.py
@@ -12,7 +12,9 @@
"""
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.
View
11 requests/cookies.py
@@ -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."""
View
75 requests/models.py
@@ -204,10 +204,8 @@ def build(resp):
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 @@ def send(self, anyway=False, prefetch=False):
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)
View
37 requests/safe_mode.py
@@ -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

0 comments on commit cff70e7

Please sign in to comment.