New Response property, .is_redirect.
authorZack Weinberg <zackw@panix.com>
Thu, 13 Feb 2014 19:27:42 +0000 (14:27 -0500)
committerZack Weinberg <zackw@panix.com>
Thu, 13 Feb 2014 19:27:42 +0000 (14:27 -0500)
HISTORY.rst
requests/__init__.py
requests/models.py
requests/sessions.py
test_requests.py

index 90ea6146b5b7a4af722ad9cfe1a161acc5599bd7..9625b95c97b9bcb87d1088e3ff0d01e72b7192a3 100644 (file)
@@ -3,6 +3,15 @@
 Release History
 ---------------
 
+2.3.0 (YYYY-MM-DD)
+++++++++++++++++++
+
+**API Changes**
+
+- New ``Response`` property ``is_redirect``, which is true when the
+  library could have processed this response as a redirection (whether
+  or not it actually did).
+
 2.2.1 (2014-01-23)
 ++++++++++++++++++
 
index 2e9f3a0bb0004b42d73c9f39480f0db8afbf67d2..bba190029e71b1f143e7de71e849051cb2ff37a7 100644 (file)
@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
 """
 
 __title__ = 'requests'
-__version__ = '2.2.1'
-__build__ = 0x020201
+__version__ = '2.3.0'
+__build__ = 0x020300
 __author__ = 'Kenneth Reitz'
 __license__ = 'Apache 2.0'
 __copyright__ = 'Copyright 2014 Kenneth Reitz'
index 25956be53687103a06234c16e229541465669fe7..cd232e68094869a68bde81c729cf2e42fb9e6039 100644 (file)
@@ -30,7 +30,17 @@ from .utils import (
 from .compat import (
     cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
     is_py2, chardet, json, builtin_str, basestring, IncompleteRead)
-
+from .status_codes import codes
+
+#: The set of HTTP status codes that indicate an automatically
+#: processable redirect.
+REDIRECT_STATI = (
+    codes.moved,  # 301
+    codes.found,  # 302
+    codes.other,  # 303
+    codes.temporary_moved,  # 307
+)
+DEFAULT_REDIRECT_LIMIT = 30
 CONTENT_CHUNK_SIZE = 10 * 1024
 ITER_CHUNK_SIZE = 512
 
@@ -589,6 +599,13 @@ class Response(object):
             return False
         return True
 
+    @property
+    def is_redirect(self):
+        """True if this Response is a well-formed HTTP redirect that could have
+        been processed automatically (by :meth:`Session.resolve_redirects`).
+        """
+        return ('location' in self.headers and self.status_code in REDIRECT_STATI)
+
     @property
     def apparent_encoding(self):
         """The apparent encoding, provided by the chardet library"""
index 2236e83f6be160c6c83f858cc8dac5ec2bc3c99b..a023e4eca6b8f658142819febb74496ef60f34f0 100644 (file)
@@ -15,7 +15,7 @@ from datetime import datetime
 from .compat import cookielib, OrderedDict, urljoin, urlparse, builtin_str
 from .cookies import (
     cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
-from .models import Request, PreparedRequest
+from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
 from .hooks import default_hooks, dispatch_hook
 from .utils import to_key_val_list, default_headers, to_native_string
 from .exceptions import TooManyRedirects, InvalidSchema
@@ -26,13 +26,9 @@ from .adapters import HTTPAdapter
 from .utils import requote_uri, get_environ_proxies, get_netrc_auth
 
 from .status_codes import codes
-REDIRECT_STATI = (
-    codes.moved,  # 301
-    codes.found,  # 302
-    codes.other,  # 303
-    codes.temporary_moved,  # 307
-)
-DEFAULT_REDIRECT_LIMIT = 30
+
+# formerly defined here, reexposed here for backward compatibility
+from .models import REDIRECT_STATI
 
 
 def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
@@ -89,8 +85,7 @@ class SessionRedirectMixin(object):
 
         i = 0
 
-        # ((resp.status_code is codes.see_other))
-        while ('location' in resp.headers and resp.status_code in REDIRECT_STATI):
+        while resp.is_redirect:
             prepared_request = req.copy()
 
             resp.content  # Consume socket so it can be released
index ee9c7b7881a877d95e32115cd0b322ef2e634ae4..3d7cdaaf78fd81f3dbf2d42fa6cf3761b1a0514e 100755 (executable)
@@ -115,6 +115,8 @@ class RequestsTestCase(unittest.TestCase):
     def test_HTTP_302_ALLOW_REDIRECT_GET(self):
         r = requests.get(httpbin('redirect', '1'))
         assert r.status_code == 200
+        assert r.history[0].status_code == 302
+        assert r.history[0].is_redirect
 
     # def test_HTTP_302_ALLOW_REDIRECT_POST(self):
     #     r = requests.post(httpbin('status', '302'), data={'some': 'data'})