From 2bb49ff386deab4e67e199450085720c1521411a Mon Sep 17 00:00:00 2001 From: Matt Sweeney Date: Tue, 25 Sep 2012 15:35:30 -0700 Subject: [PATCH 01/15] Handle encoding of `None` when decoding unicode If encoding is None, decoding will throw the following TypeError: TypeError: unicode() argument 2 must be string, not None If this is the case, attempt to run without any set encoding --- requests/models.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/requests/models.py b/requests/models.py index f33c3c3e..305e615e 100644 --- a/requests/models.py +++ b/requests/models.py @@ -834,6 +834,11 @@ class Response(object): # # So we try blindly encoding. content = str(self.content, errors='replace') + except TypeError: + # A TypeError can be raised if encoding is None + # + # So we try blindly encoding. + content = str(self.content, errors='replace') return content From eb6a6b1a234e520d9ef6263fc1f35758ca1b662a Mon Sep 17 00:00:00 2001 From: Matt Sweeney Date: Wed, 26 Sep 2012 12:38:36 -0700 Subject: [PATCH 02/15] Simplify error handling when decoding unicode --- requests/models.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/requests/models.py b/requests/models.py index 305e615e..2193c6e5 100644 --- a/requests/models.py +++ b/requests/models.py @@ -828,13 +828,10 @@ class Response(object): # Decode unicode from given encoding. try: content = str(self.content, encoding, errors='replace') - except LookupError: + except (LookupError, TypeError): # A LookupError is raised if the encoding was not found which could # indicate a misspelling or similar mistake. # - # So we try blindly encoding. - content = str(self.content, errors='replace') - except TypeError: # A TypeError can be raised if encoding is None # # So we try blindly encoding. From e656222188475369ec3493cdeb37d398a7e7e1c5 Mon Sep 17 00:00:00 2001 From: yegle Date: Sat, 29 Sep 2012 18:28:53 -0400 Subject: [PATCH 03/15] Python 3.3 compatible update httplib.cookiejar.DefaultCookiePolicy changed its implementation of set_ok_verifiability. --- requests/cookies.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/requests/cookies.py b/requests/cookies.py index bd2d6654..83f6bb60 100644 --- a/requests/cookies.py +++ b/requests/cookies.py @@ -67,6 +67,10 @@ class MockRequest(object): def get_new_headers(self): return self._new_headers + def __getattr__(self, name): + if name == 'unverifiable': + return self.is_unverifiable() + class MockResponse(object): """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. From 4f9e5521480e5b9fa760e0f19274441c363aca5e Mon Sep 17 00:00:00 2001 From: Kunal Mehta Date: Sun, 30 Sep 2012 19:24:56 -0500 Subject: [PATCH 04/15] Use __iter__ rather than the inefficient nested for loops --- requests/utils.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index eb146000..63b281a2 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -311,11 +311,8 @@ def dict_from_cookiejar(cj): cookie_dict = {} - for _, cookies in list(cj._cookies.items()): - for _, cookies in list(cookies.items()): - for cookie in list(cookies.values()): - # print cookie - cookie_dict[cookie.name] = cookie.value + for cookie in cj: + cookie_dict[cookie.name] = cookie.value return cookie_dict From 22fdecba521610466f4316ad4a22c6f25870b46f Mon Sep 17 00:00:00 2001 From: yegle Date: Mon, 1 Oct 2012 13:13:12 -0400 Subject: [PATCH 05/15] Update: @property decorator instead of __getattr__ --- requests/cookies.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/requests/cookies.py b/requests/cookies.py index 83f6bb60..101e617d 100644 --- a/requests/cookies.py +++ b/requests/cookies.py @@ -67,9 +67,9 @@ class MockRequest(object): def get_new_headers(self): return self._new_headers - def __getattr__(self, name): - if name == 'unverifiable': - return self.is_unverifiable() + @property + def unverifiable(self): + return self.is_unverifiable() class MockResponse(object): From ed8a3f319958844870bb071db7a185fb66d25171 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 1 Oct 2012 13:29:38 -0400 Subject: [PATCH 06/15] v0.14.1 --- HISTORY.rst | 8 ++++++++ requests/__init__.py | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 1416c463..0a83006b 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,14 @@ History ------- +0.14.1 (2012-10-01) ++++++++++++++++++++ + +- Python 3.3 Compatibility +- Simply default accept-encoding +- Bugfixes + + 0.14.0 (2012-09-02) ++++++++++++++++++++ diff --git a/requests/__init__.py b/requests/__init__.py index 50953f86..2e33412b 100644 --- a/requests/__init__.py +++ b/requests/__init__.py @@ -42,8 +42,8 @@ is at . """ __title__ = 'requests' -__version__ = '0.14.0' -__build__ = 0x001400 +__version__ = '0.14.1' +__build__ = 0x001401 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2012 Kenneth Reitz' From 46fd297c3ac903793a99fd9712f04d747a027538 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Mon, 1 Oct 2012 13:30:41 -0400 Subject: [PATCH 07/15] new classifiers for 3.2+ --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 35c87cef..9844ab1b 100755 --- a/setup.py +++ b/setup.py @@ -65,6 +65,8 @@ setup( 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', ), ) From 4e6cf21d8231b28a9bbfdd94392137255e434033 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Mon, 1 Oct 2012 13:09:02 -0400 Subject: [PATCH 08/15] Only register callable items in lists Prior to this, you could sneak a list of anything to register_hook and it would accept it. This will check if the items in the list are callable before registering them. Also added a regression test to make sure if this gets changed it will be noticed. --- requests/models.py | 6 +++--- tests/test_requests.py | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/requests/models.py b/requests/models.py index 2193c6e5..78311491 100644 --- a/requests/models.py +++ b/requests/models.py @@ -462,10 +462,10 @@ class Request(object): def register_hook(self, event, hook): """Properly register a hook.""" - if isinstance(hook, (list, tuple, set)): - self.hooks[event].extend(hook) - else: + if callable(hook): self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if callable(h)) def deregister_hook(self, event, hook): """Deregister a previously registered hook. diff --git a/tests/test_requests.py b/tests/test_requests.py index 0f67618a..3d6f49c2 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -778,6 +778,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): r = requests.models.Request(hooks={'args': hooks}) assert_hooks_are_callable(r.hooks) + hooks.append('string that should not be registered') + r = requests.models.Request(hooks={'args': hooks}) + assert_hooks_are_callable(r.hooks) + def test_session_persistent_cookies(self): s = requests.session() From 582a53f3f4b7cf539dfa61e83994ca9f2b5ef2ff Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 2 Oct 2012 00:43:21 -0400 Subject: [PATCH 09/15] why not --- docs/_templates/sidebarintro.html | 6 ++++++ docs/_templates/sidebarlogo.html | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html index 4d341223..14987f78 100644 --- a/docs/_templates/sidebarintro.html +++ b/docs/_templates/sidebarintro.html @@ -20,6 +20,12 @@

If you love Requests, consider supporting the author on Gittip:

+

+ Or, if your company uses Requests, consider purchasing a copy: + + Requests + +

+

+

Or, if your company uses Requests, consider purchasing a copy: Requests

-

- -

+

Feedback

Feedback is greatly appreciated. If you have any questions, comments, diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html index 858e5625..92ad1e9f 100644 --- a/docs/_templates/sidebarlogo.html +++ b/docs/_templates/sidebarlogo.html @@ -18,14 +18,15 @@

If you love Requests, consider supporting the author on Gittip:

+

+ +

+

Or, if your company uses Requests, consider purchasing a copy: Requests

-

- -

\ No newline at end of file From 1444d9033a11f6aed8d53333c4b93c72a4b91411 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 2 Oct 2012 00:44:57 -0400 Subject: [PATCH 11/15] padding --- docs/_templates/sidebarintro.html | 3 +-- docs/_templates/sidebarlogo.html | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html index d83d5406..e4d43866 100644 --- a/docs/_templates/sidebarintro.html +++ b/docs/_templates/sidebarintro.html @@ -29,9 +29,8 @@

Or, if your company uses Requests, consider purchasing a copy: - Requests -

+ Requests

Feedback

diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html index 92ad1e9f..8a427b9c 100644 --- a/docs/_templates/sidebarlogo.html +++ b/docs/_templates/sidebarlogo.html @@ -27,6 +27,8 @@

Or, if your company uses Requests, consider purchasing a copy: - Requests +

+ + Requests From cc1b9da2351a3b93e3a1bfc95676ffc74cebb45b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 2 Oct 2012 01:01:28 -0400 Subject: [PATCH 12/15] wording --- docs/_templates/sidebarintro.html | 5 +++-- docs/_templates/sidebarlogo.html | 6 ++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html index e4d43866..1fa949bb 100644 --- a/docs/_templates/sidebarintro.html +++ b/docs/_templates/sidebarintro.html @@ -27,10 +27,11 @@

- Or, if your company uses Requests, consider purchasing a copy: + If your organization uses Requests, consider financial support:

- Requests + + Requests Pro

Feedback

diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html index 8a427b9c..21a2a6b3 100644 --- a/docs/_templates/sidebarlogo.html +++ b/docs/_templates/sidebarlogo.html @@ -25,10 +25,8 @@

- Or, if your company uses Requests, consider purchasing a copy: - - + If your organization uses Requests, consider financial support:

- Requests + Requests Pro From 3e3019691734a8867370bb6dee54559b4a747679 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 2 Oct 2012 01:02:32 -0400 Subject: [PATCH 13/15] update --- docs/_templates/sidebarintro.html | 5 +++-- docs/_templates/sidebarlogo.html | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html index 1fa949bb..f2b0d7a0 100644 --- a/docs/_templates/sidebarintro.html +++ b/docs/_templates/sidebarintro.html @@ -30,8 +30,9 @@ If your organization uses Requests, consider financial support:

- - Requests Pro +

+ Requests Pro +

Feedback

diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html index 21a2a6b3..34b9d421 100644 --- a/docs/_templates/sidebarlogo.html +++ b/docs/_templates/sidebarlogo.html @@ -29,4 +29,6 @@

- Requests Pro +

+ Requests Pro +

From 5ec2c96f0298d2bbac523396683cfb9f3ce971f9 Mon Sep 17 00:00:00 2001 From: tokuda109 Date: Tue, 2 Oct 2012 23:26:10 +0900 Subject: [PATCH 14/15] declare the encoding --- requests/cookies.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requests/cookies.py b/requests/cookies.py index 101e617d..241ca679 100644 --- a/requests/cookies.py +++ b/requests/cookies.py @@ -1,3 +1,5 @@ +# -*- coding: utf-8 -*- + """ Compatibility code to be able to use `cookielib.CookieJar` with requests. From 820dfb0495ef379f140ad3c78c30e0a16c7e9fa8 Mon Sep 17 00:00:00 2001 From: Radu Voicilas Date: Tue, 9 Oct 2012 00:41:42 +0300 Subject: [PATCH 15/15] Making the code more PEP8 compliant --- requests/auth.py | 2 +- requests/compat.py | 2 +- requests/cookies.py | 10 ++++------ requests/hooks.py | 1 - requests/models.py | 2 +- requests/utils.py | 5 ++++- tests/informal/test_leaked_connections.py | 6 +++++- tests/test_proxies.py | 12 +++++++----- tests/test_requests.py | 5 +++-- tests/test_requests_ext.py | 3 ++- tests/test_requests_https.py | 4 ++-- 11 files changed, 30 insertions(+), 22 deletions(-) diff --git a/requests/auth.py b/requests/auth.py index 6c5264e4..65568f52 100644 --- a/requests/auth.py +++ b/requests/auth.py @@ -94,7 +94,7 @@ class OAuth1(AuthBase): # to preserve body. r.url, r.headers, _ = self.client.sign( unicode(r.full_url), unicode(r.method), None, r.headers) - elif decoded_body != None and contenttype in (CONTENT_TYPE_FORM_URLENCODED, ''): + elif decoded_body is not None and contenttype in (CONTENT_TYPE_FORM_URLENCODED, ''): # Normal signing if not contenttype: r.headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED diff --git a/requests/compat.py b/requests/compat.py index 351b7c6e..69dd25c5 100644 --- a/requests/compat.py +++ b/requests/compat.py @@ -115,5 +115,5 @@ elif is_py3: builtin_str = str str = str bytes = bytes - basestring = (str,bytes) + basestring = (str, bytes) numeric_types = (int, float) diff --git a/requests/cookies.py b/requests/cookies.py index 241ca679..c3c2debb 100644 --- a/requests/cookies.py +++ b/requests/cookies.py @@ -235,7 +235,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): Python dict of name-value pairs of cookies that meet the requirements.""" dictionary = {} for cookie in iter(self): - if (domain == None or cookie.domain == domain) and (path == None + if (domain is None or cookie.domain == domain) and (path is None or cookie.path == path): dictionary[cookie.name] = cookie.value return dictionary @@ -279,7 +279,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping): if cookie.name == name: if domain is None or cookie.domain == domain: if path is None or cookie.path == path: - if toReturn != None: # if there are multiple cookies that meet passed in criteria + if toReturn is not None: # if there are multiple cookies that meet passed in criteria raise CookieConflictError('There are multiple cookies with name, %r' % (name)) toReturn = cookie.value # we will eventually return this as long as no cookie conflict @@ -324,8 +324,7 @@ def create_cookie(name, value, **kwargs): comment=None, comment_url=None, rest={'HttpOnly': None}, - rfc2109=False, - ) + rfc2109=False,) badargs = set(kwargs) - set(result) if badargs: @@ -360,8 +359,7 @@ def morsel_to_cookie(morsel): comment=morsel['comment'], comment_url=bool(morsel['comment']), rest={'HttpOnly': morsel['httponly']}, - rfc2109=False, - ) + rfc2109=False,) return c diff --git a/requests/hooks.py b/requests/hooks.py index 9e0ce346..9a35fb16 100644 --- a/requests/hooks.py +++ b/requests/hooks.py @@ -45,5 +45,4 @@ def dispatch_hook(key, hooks, hook_data): if _hook_data is not None: hook_data = _hook_data - return hook_data diff --git a/requests/models.py b/requests/models.py index 78311491..f02cec33 100644 --- a/requests/models.py +++ b/requests/models.py @@ -111,7 +111,7 @@ class Request(object): # Dictionary mapping protocol to the URL of the proxy (e.g. {'http': 'foo.bar:3128'}) self.proxies = dict(proxies or []) - for proxy_type,uri_ref in list(self.proxies.items()): + for proxy_type, uri_ref in list(self.proxies.items()): if not uri_ref: del self.proxies[proxy_type] diff --git a/requests/utils.py b/requests/utils.py index 63b281a2..7c895c4b 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -378,13 +378,15 @@ def stream_decode_response_unicode(iterator, r): if rv: yield rv + def iter_slices(string, slice_length): """Iterate over slices of a string.""" pos = 0 while pos < len(string): - yield string[pos:pos+slice_length] + yield string[pos:pos + slice_length] pos += slice_length + def get_unicode_from_response(r): """Returns the requested content back in unicode. @@ -543,6 +545,7 @@ def default_user_agent(): '%s/%s' % (platform.system(), platform.release()), ]) + def parse_header_links(value): """Return a dict of parsed link headers proxies. diff --git a/tests/informal/test_leaked_connections.py b/tests/informal/test_leaked_connections.py index 438a6cee..37d964cf 100644 --- a/tests/informal/test_leaked_connections.py +++ b/tests/informal/test_leaked_connections.py @@ -4,7 +4,11 @@ it verifies that Requests does not leak connections when the body of the request is not read. """ -import gc, os, subprocess, requests, sys +import gc +import os +import requests +import subprocess +import sys def main(): diff --git a/tests/test_proxies.py b/tests/test_proxies.py index 8ab124b2..5aa5bf36 100644 --- a/tests/test_proxies.py +++ b/tests/test_proxies.py @@ -1,7 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys, os, unittest +import os +import sys +import unittest # Path hack. sys.path.insert(0, os.path.abspath('..')) @@ -14,13 +16,13 @@ class HTTPSProxyTest(unittest.TestCase): smoke_url = "https://github.com" def test_empty_https_proxy(self): - proxy = {"https" : "" } - result = requests.get(self.smoke_url, verify=False, proxies = proxy) + proxy = {"https": ""} + result = requests.get(self.smoke_url, verify=False, proxies=proxy) self.assertEqual(result.status_code, 200) def test_empty_http_proxy(self): - proxy = {"http" : "" } - result = requests.get(self.smoke_url, proxies = proxy) + proxy = {"http": ""} + result = requests.get(self.smoke_url, proxies=proxy) self.assertEqual(result.status_code, 200) if __name__ == '__main__': diff --git a/tests/test_requests.py b/tests/test_requests.py index 3d6f49c2..9ed4ad03 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -51,6 +51,7 @@ class TestSetup(object): # time.sleep(1) _httpbin = True + class TestBaseMixin(object): def assertCookieHas(self, cookie, **kwargs): @@ -60,6 +61,7 @@ class TestBaseMixin(object): message = 'Failed comparison for %s: %s != %s' % (attr, cookie_attr, expected_value) self.assertEqual(cookie_attr, expected_value, message) + class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): """Requests test cases.""" @@ -903,7 +905,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): def test_connection_error_with_safe_mode(self): config = {'safe_mode': True} r = get('http://localhost:1/nope', allow_redirects=False, config=config) - assert r.content == None + assert r.content is None # def test_invalid_content(self): # # WARNING: if you're using a terrible DNS provider (comcast), @@ -1038,7 +1040,6 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): s.config['danger_mode'] = True s.get(httpbin('redirect', '4')) - def test_empty_response(self): r = requests.get(httpbin('status', '404')) r.text diff --git a/tests/test_requests_ext.py b/tests/test_requests_ext.py index 208803a7..e3cdd04e 100644 --- a/tests/test_requests_ext.py +++ b/tests/test_requests_ext.py @@ -2,7 +2,8 @@ # -*- coding: utf-8 -*- # Path hack. -import sys, os +import os +import sys sys.path.insert(0, os.path.abspath('..')) import unittest diff --git a/tests/test_requests_https.py b/tests/test_requests_https.py index 1691a8c0..2da09824 100755 --- a/tests/test_requests_https.py +++ b/tests/test_requests_https.py @@ -1,8 +1,8 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -import sys, os -import json +import os +import sys import unittest # Path hack.