From 857d8eda3a4055d92626f71ff5b34ce8cc6ec167 Mon Sep 17 00:00:00 2001
From: Shivaram Lingamneni
Date: Mon, 6 Aug 2012 13:57:04 -0700
Subject: [PATCH 01/20] red tests derived from @dhagrow's examples in #760
---
tests/test_requests.py | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index 83ca69fd..233daed1 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -979,6 +979,22 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
t = json.loads(r.text)
self.assertEqual(t.get('headers').get('Content-Type'), '')
+ def test_prefetch_redirect_bug(self):
+ """Test that prefetch persists across redirections."""
+ res = get(httpbin('redirect/2'), prefetch=False)
+ # prefetch should persist across the redirect; if it doesn't,
+ # this attempt to iterate will crash because the content has already
+ # been read.
+ first_line = next(res.iter_lines())
+ self.assertTrue(first_line.strip().startswith('{'))
+
+ def test_prefetch_return_response_interaction(self):
+ """Test that prefetch can be overridden as a kwarg to `send`."""
+ req = requests.get(httpbin('get'), return_response=False)
+ req.send(prefetch=False)
+ # content should not have been prefetched, and iter_lines should succeed
+ first_line = next(req.response.iter_lines())
+ self.assertTrue(first_line.strip().startswith('{'))
if __name__ == '__main__':
unittest.main()
From 030ead9c36b59d2e18f6381f3f8c96c6e4de0090 Mon Sep 17 00:00:00 2001
From: Shivaram Lingamneni
Date: Mon, 6 Aug 2012 15:37:28 -0700
Subject: [PATCH 02/20] properly handle send(prefetch=False)
fixes RequestsTestSuite.test_prefetch_return_response_interaction
---
requests/models.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/requests/models.py b/requests/models.py
index 5908928a..5556883e 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -458,7 +458,7 @@ class Request(object):
except ValueError:
return False
- def send(self, anyway=False, prefetch=True):
+ def send(self, anyway=False, prefetch=None):
"""Sends the request. Returns True if successful, False if not.
If there was an HTTPError during transmission,
self.response.status_code will contain the HTTPError code.
@@ -467,6 +467,9 @@ class Request(object):
:param anyway: If True, request will be sent, even if it has
already been sent.
+
+ :param prefetch: If not None, will override the request's own setting
+ for prefetch.
"""
# Build the URL
@@ -626,7 +629,9 @@ class Request(object):
self.__dict__.update(r.__dict__)
# If prefetch is True, mark content as consumed.
- if prefetch or self.prefetch:
+ if prefetch is None:
+ prefetch = self.prefetch
+ if prefetch:
# Save the response.
self.response.content
From 000c1053035812ee765a4f4a967eb69dba400a04 Mon Sep 17 00:00:00 2001
From: Shivaram Lingamneni
Date: Mon, 6 Aug 2012 15:46:47 -0700
Subject: [PATCH 03/20] propagate self.prefetch on redirect
fixes RequestsTestSuite.test_prefetch_redirect_bug
---
requests/models.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/requests/models.py b/requests/models.py
index 5556883e..d8c0f3e8 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -291,7 +291,8 @@ class Request(object):
proxies=self.proxies,
verify=self.verify,
session=self.session,
- cert=self.cert
+ cert=self.cert,
+ prefetch=self.prefetch,
)
request.send()
From 291859c199c481bf1e304e39613ca90b6f55f9f8 Mon Sep 17 00:00:00 2001
From: Shivaram Lingamneni
Date: Mon, 6 Aug 2012 16:11:45 -0700
Subject: [PATCH 04/20] fix the tests for python 3
---
tests/test_requests.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index 233daed1..dd08b2af 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -986,7 +986,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
# this attempt to iterate will crash because the content has already
# been read.
first_line = next(res.iter_lines())
- self.assertTrue(first_line.strip().startswith('{'))
+ self.assertTrue(first_line.strip().decode('utf-8').startswith('{'))
def test_prefetch_return_response_interaction(self):
"""Test that prefetch can be overridden as a kwarg to `send`."""
@@ -994,7 +994,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
req.send(prefetch=False)
# content should not have been prefetched, and iter_lines should succeed
first_line = next(req.response.iter_lines())
- self.assertTrue(first_line.strip().startswith('{'))
+ self.assertTrue(first_line.strip().decode('utf-8').startswith('{'))
if __name__ == '__main__':
unittest.main()
From e624ae8aeadc63b473e1d57f1bec71b4f713cf32 Mon Sep 17 00:00:00 2001
From: Cory Benfield
Date: Wed, 8 Aug 2012 11:59:00 +0100
Subject: [PATCH 05/20] Add test for Issue #423.
---
tests/test_requests.py | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index dd08b2af..f7803ba1 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -996,5 +996,23 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
first_line = next(req.response.iter_lines())
self.assertTrue(first_line.strip().decode('utf-8').startswith('{'))
+ def test_accept_objects_with_string_representations_as_urls(self):
+ """Test that URLs can be set to objects with string representations,
+ e.g. for use with furl."""
+ class URL():
+ def __unicode__(self):
+ # Can't have unicode literals in Python3, so avoid them.
+ # TODO: fixup when moving to Python 3.3
+ if (sys.version_info[0] == 2):
+ return 'http://httpbin.org/get'.decode('utf-8')
+ else:
+ return 'http://httpbin.org/get'
+
+ def __str__(self):
+ return 'http://httpbin.org/get'
+
+ r = get(URL())
+ self.assertEqual(r.status_code, 200)
+
if __name__ == '__main__':
unittest.main()
From 6166ba7e131ef77f9748488a02dc5e699928a17d Mon Sep 17 00:00:00 2001
From: Cory Benfield
Date: Wed, 8 Aug 2012 12:05:52 +0100
Subject: [PATCH 06/20] Accept objects with string representations as URLs.
---
requests/models.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/requests/models.py b/requests/models.py
index d8c0f3e8..20a28807 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -71,7 +71,14 @@ class Request(object):
self.timeout = timeout
#: Request URL.
- self.url = url
+ #: Accept objects that have string representations.
+ try:
+ self.url = unicode(url)
+ except NameError:
+ # We're on Python 3.
+ self.url = str(url)
+ except UnicodeDecodeError:
+ self.url = url
#: Dictionary of HTTP Headers to attach to the :class:`Request `.
self.headers = dict(headers or [])
From 875c9e18ab967464d13a2ea804119316c73277bb Mon Sep 17 00:00:00 2001
From: Stefan Praszalowicz
Date: Wed, 8 Aug 2012 11:12:32 -0700
Subject: [PATCH 07/20] Wrap socket.error in ConnectionError (+ unit tests)
---
requests/models.py | 4 ++++
tests/test_requests.py | 14 ++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/requests/models.py b/requests/models.py
index d8c0f3e8..44bf5818 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -8,6 +8,7 @@ This module contains the primary objects that power Requests.
"""
import os
+import socket
from datetime import datetime
from .hooks import dispatch_hook, HOOKS
@@ -608,6 +609,9 @@ class Request(object):
)
self.sent = True
+ except socket.error as sockerr:
+ raise ConnectionError(sockerr)
+
except MaxRetryError as e:
raise ConnectionError(e)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index dd08b2af..0a52c4c3 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -811,6 +811,20 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
assert ds1.prefetch
assert not ds2.prefetch
+ def test_connection_error(self):
+ try:
+ get('http://localhost:1/nope')
+ except requests.ConnectionError:
+ pass
+ else:
+ assert False
+
+ 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
+
+
# def test_invalid_content(self):
# # WARNING: if you're using a terrible DNS provider (comcast),
# # this will fail.
From 40ba6b4ec13e599ede207ec6987c37b0c1b54152 Mon Sep 17 00:00:00 2001
From: Kenneth Reitz
Date: Wed, 8 Aug 2012 23:31:30 -0500
Subject: [PATCH 08/20] new button domain
---
docs/_templates/sidebarintro.html | 2 +-
docs/_templates/sidebarlogo.html | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/_templates/sidebarintro.html b/docs/_templates/sidebarintro.html
index cb58776d..4d341223 100644
--- a/docs/_templates/sidebarintro.html
+++ b/docs/_templates/sidebarintro.html
@@ -5,7 +5,7 @@
-
diff --git a/docs/_templates/sidebarlogo.html b/docs/_templates/sidebarlogo.html
index df79ff24..6a75a67d 100644
--- a/docs/_templates/sidebarlogo.html
+++ b/docs/_templates/sidebarlogo.html
@@ -4,7 +4,7 @@
-
From 7a9419ce356d0be0383ec83b14e66658ea7f96be Mon Sep 17 00:00:00 2001
From: Cory Benfield
Date: Fri, 10 Aug 2012 14:47:13 +0100
Subject: [PATCH 09/20] Document encodings and RFC compliance.
---
docs/user/advanced.rst | 25 +++++++++++++++++++++++++
docs/user/quickstart.rst | 20 +++++++++++++++-----
2 files changed, 40 insertions(+), 5 deletions(-)
diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst
index adda9c73..0ac450d7 100644
--- a/docs/user/advanced.rst
+++ b/docs/user/advanced.rst
@@ -343,6 +343,31 @@ To use HTTP Basic Auth with your proxy, use the `http://user:password@host/` syn
"http": "http://user:pass@10.10.1.10:3128/",
}
+Compliance
+----------
+
+Requests is intended to be compliant with all relevant specifications and
+RFCs where that compliance will not cause difficulties for users. This
+attention to the specification can lead to some behaviour that may seem
+unusual to those not familiar with the relevant specification.
+
+Encodings
+^^^^^^^^^
+
+When you receive a response, Requests makes a guess at the encoding to use for
+decoding the response when you call the ``Response.text`` method. Requests
+will first check for an encoding in the HTTP header, and if none is present,
+will use `chardet `_ to attempt to guess
+the encoding.
+
+The only time Requests will not do this is if no explicit charset is present
+in the HTTP headers **and** the ``Content-Type`` header contains ``text``. In
+this situation,
+`RFC 2616 `_
+specifies that the default charset must be ``ISO-8859-1``. Requests follows
+the specification in this case. If you require a different encoding, you can
+manually set the ``Response.encoding`` property, or use the raw
+``Request.content``.
HTTP Verbs
----------
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index 9b0399d4..71ffea05 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -86,12 +86,22 @@ again::
Requests will automatically decode content from the server. Most unicode
charsets are seamlessly decoded.
-When you make a request, ``r.encoding`` is set, based on the HTTP headers.
-Requests will use that encoding when you access ``r.text``. If ``r.encoding``
-is ``None``, Requests will make an extremely educated guess of the encoding
-of the response body. You can manually set ``r.encoding`` to any encoding
-you'd like, and that charset will be used.
+When you make a request, Requests makes educated guesses about the encoding of
+the response based on the HTTP headers. The text encoding guessed by Requests
+is used when you access ``r.text``. You can find out what encoding Requests is
+using, and change it, using the ``r.encoding`` property::
+ >>> r.encoding
+ 'utf-8'
+ >>> r.encoding = 'ISO-8859-1'
+
+If you change the encoding, Requests will use the new value of ``r.encoding``
+whenever you call ``r.text``.
+
+Requests will also use custom encodings in the event that you need them. If
+you have created your own encoding and registered it with the ``codecs``
+module, you can simply use the codec name as the value of ``r.encoding`` and
+Requests will handle the decoding for you.
Binary Response Content
-----------------------
From 4da4792844017b7b7e5f78cf106e34a68a08af96 Mon Sep 17 00:00:00 2001
From: Radomir Stevanovic
Date: Fri, 10 Aug 2012 17:51:01 +0200
Subject: [PATCH 10/20] tests: python2.6 compat (`assertIn` added in 2.7)
---
tests/test_requests_ext.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/tests/test_requests_ext.py b/tests/test_requests_ext.py
index 883bdceb..7645d8c1 100644
--- a/tests/test_requests_ext.py
+++ b/tests/test_requests_ext.py
@@ -110,7 +110,7 @@ class RequestsTestSuite(unittest.TestCase):
s = requests.session()
s.get(url='http://tinyurl.com/preview.php?disable=1')
# we should have set a cookie for tinyurl: preview=0
- self.assertIn('preview', s.cookies)
+ self.assertTrue('preview' in s.cookies)
self.assertEqual(s.cookies['preview'], '0')
self.assertEqual(list(s.cookies)[0].name, 'preview')
self.assertEqual(list(s.cookies)[0].domain, 'tinyurl.com')
@@ -118,13 +118,13 @@ class RequestsTestSuite(unittest.TestCase):
# get cookies on another domain
r2 = s.get(url='http://httpbin.org/cookies')
# the cookie is not there
- self.assertNotIn('preview', json.loads(r2.text)['cookies'])
+ self.assertTrue('preview' not in json.loads(r2.text)['cookies'])
# this redirects to another domain, httpbin.org
# cookies of the first domain should NOT be sent to the next one
r3 = s.get(url='http://tinyurl.com/7zp3jnr')
assert r3.url == 'http://httpbin.org/cookies'
- self.assertNotIn('preview', json.loads(r2.text)['cookies'])
+ self.assertTrue('preview' not in json.loads(r2.text)['cookies'])
if __name__ == '__main__':
unittest.main()
From cfa627ae62cebff20edf0816ce327c61603ef6a8 Mon Sep 17 00:00:00 2001
From: Jakub Roztocil
Date: Fri, 27 Jul 2012 17:08:16 +0200
Subject: [PATCH 11/20] Fixed encoding of fields with the same name.
* Properly handle repeated data fields for multipart/form-data requests (#737)
* Allow a list of 2-tuples as the `files` agument.
* Consistently serialize lists a of parameters (#729).
---
AUTHORS.rst | 1 +
requests/models.py | 47 ++++++++++++++++++++++++++++--------------
tests/test_requests.py | 38 ++++++++++++++++++++++++++++++++--
3 files changed, 69 insertions(+), 17 deletions(-)
diff --git a/AUTHORS.rst b/AUTHORS.rst
index 1ff53148..f21d1736 100644
--- a/AUTHORS.rst
+++ b/AUTHORS.rst
@@ -110,3 +110,4 @@ Patches and Suggestions
- Victoria Mo
- Leila Muhtasib
- Matthias Rahlf
+- Jakub Roztocil
diff --git a/requests/models.py b/requests/models.py
index 8f31c3a7..1a74dc2b 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -344,16 +344,33 @@ class Request(object):
return data
def _encode_files(self, files):
+ """Build the body for a multipart/form-data request.
+ Will successfully encode files when passed as a dict or a list of
+ 2-tuples. Order is retained if data is a list of 2-tuples but abritrary
+ if parameters are supplied as a dict.
+
+ """
if (not files) or isinstance(self.data, str):
return None
- try:
- fields = self.data.copy()
- except AttributeError:
- fields = dict(self.data)
+ def tuples(obj):
+ """Ensure 2-tuples. A dict or a 2-tuples list can be supplied."""
+ if isinstance(obj, dict):
+ return list(obj.items())
+ elif hasattr(obj, '__iter__'):
+ try:
+ dict(obj)
+ except ValueError:
+ pass
+ else:
+ return obj
+ raise ValueError('A dict or a list of 2-tuples required.')
- for (k, v) in list(files.items()):
+ # 2-tuples containing both file and data fields.
+ fields = []
+
+ for k, v in tuples(files):
# support for explicit filename
if isinstance(v, (tuple, list)):
fn, fp = v
@@ -362,18 +379,18 @@ class Request(object):
fp = v
if isinstance(fp, (bytes, str)):
fp = StringIO(fp)
- fields.update({k: (fn, fp.read())})
+ fields.append((k, (fn, fp.read())))
- for field in fields:
- if isinstance(fields[field], numeric_types):
- fields[field] = str(fields[field])
- if isinstance(fields[field], list):
- newvalue = ', '.join(fields[field])
- fields[field] = newvalue
-
- (body, content_type) = encode_multipart_formdata(fields)
+ for k, vs in tuples(self.data):
+ if isinstance(vs, list):
+ for v in vs:
+ fields.append((k, str(v)))
+ else:
+ fields.append((k, str(vs)))
- return (body, content_type)
+ body, content_type = encode_multipart_formdata(fields)
+
+ return body, content_type
@property
def full_url(self):
diff --git a/tests/test_requests.py b/tests/test_requests.py
index e8bfc881..abc57e12 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -981,10 +981,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
list for a value in the data argument."""
data = {'field': ['a', 'b']}
- files = {'file': 'Garbled data'}
+ files = {'field': 'Garbled data'}
r = post(httpbin('post'), data=data, files=files)
t = json.loads(r.text)
- self.assertEqual(t.get('form'), {'field': 'a, b'})
+ self.assertEqual(t.get('form'), {'field': ['a', 'b']})
self.assertEqual(t.get('files'), files)
def test_str_data_content_type(self):
@@ -1028,5 +1028,39 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
r = get(URL())
self.assertEqual(r.status_code, 200)
+ def test_post_fields_with_multiple_values_and_files_as_tuples(self):
+ """Test that it is possible to POST multiple data and file fields
+ with the same name."""
+
+ data = [
+ ('__field__', '__value__'),
+ ('__field__', '__value__'),
+ ]
+ files = [
+ ('__field__', '__value__'),
+ ('__field__', '__value__'),
+ ]
+
+ r = post(httpbin('post'), data=data, files=files)
+ t = json.loads(r.text)
+
+ self.assertEqual(t.get('form'), {
+ '__field__': [
+ '__value__',
+ '__value__',
+ ]
+ })
+
+ # It's not currently possible to test for multiple file fields with
+ # the same name against httpbin so we need to inspect the encoded
+ # body manually.
+ request = r.request
+ body, content_type = request._encode_files(request.files)
+ file_field = ('Content-Disposition: form-data;'
+ ' name="__field__"; filename="__field__"')
+ self.assertEqual(body.count('__value__'), 4)
+ self.assertEqual(body.count(file_field), 2)
+
+
if __name__ == '__main__':
unittest.main()
From dee3693ea004e2f859e4fba4cfedb376e4d0bb2b Mon Sep 17 00:00:00 2001
From: Jakub Roztocil
Date: Mon, 30 Jul 2012 10:35:47 +0200
Subject: [PATCH 12/20] Use BytesIO for bytes.
This fixes a TypeError on Python 3 that ocurred when passing
bytes as the values for files.
---
requests/models.py | 5 ++++-
tests/test_requests.py | 9 +++++++--
2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/requests/models.py b/requests/models.py
index 1a74dc2b..136427fe 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -10,6 +10,7 @@ This module contains the primary objects that power Requests.
import os
import socket
from datetime import datetime
+from io import BytesIO
from .hooks import dispatch_hook, HOOKS
from .structures import CaseInsensitiveDict
@@ -377,8 +378,10 @@ class Request(object):
else:
fn = guess_filename(v) or k
fp = v
- if isinstance(fp, (bytes, str)):
+ if isinstance(fp, str):
fp = StringIO(fp)
+ if isinstance(fp, bytes):
+ fp = BytesIO(fp)
fields.append((k, (fn, fp.read())))
for k, vs in tuples(self.data):
diff --git a/tests/test_requests.py b/tests/test_requests.py
index abc57e12..e196af44 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -7,7 +7,6 @@
import sys
import os
sys.path.insert(0, os.path.abspath('..'))
-
import json
import os
import unittest
@@ -1030,7 +1029,9 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
def test_post_fields_with_multiple_values_and_files_as_tuples(self):
"""Test that it is possible to POST multiple data and file fields
- with the same name."""
+ with the same name.
+ https://github.com/kennethreitz/requests/pull/746
+ """
data = [
('__field__', '__value__'),
@@ -1061,6 +1062,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
self.assertEqual(body.count('__value__'), 4)
self.assertEqual(body.count(file_field), 2)
+ def test_bytes_files(self):
+ """Test that `bytes` can be used as the values of `files`."""
+ post(httpbin('post'), files={'test': b'test'})
+
if __name__ == '__main__':
unittest.main()
From 88c762e256647a03f10a7a8c8707043a1b33aa5b Mon Sep 17 00:00:00 2001
From: Jakub Roztocil
Date: Sat, 11 Aug 2012 08:19:35 +0200
Subject: [PATCH 13/20] Fixed tests for Python 3 (text vs. bytes).
---
tests/test_requests.py | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index e196af44..f43ccac8 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -1033,16 +1033,12 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
https://github.com/kennethreitz/requests/pull/746
"""
- data = [
- ('__field__', '__value__'),
- ('__field__', '__value__'),
- ]
- files = [
+ fields = [
('__field__', '__value__'),
('__field__', '__value__'),
]
- r = post(httpbin('post'), data=data, files=files)
+ r = post(httpbin('post'), data=fields, files=fields)
t = json.loads(r.text)
self.assertEqual(t.get('form'), {
@@ -1057,9 +1053,9 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
# body manually.
request = r.request
body, content_type = request._encode_files(request.files)
- file_field = ('Content-Disposition: form-data;'
- ' name="__field__"; filename="__field__"')
- self.assertEqual(body.count('__value__'), 4)
+ file_field = (b'Content-Disposition: form-data;'
+ b' name="__field__"; filename="__field__"')
+ self.assertEqual(body.count(b'__value__'), 4)
self.assertEqual(body.count(file_field), 2)
def test_bytes_files(self):
From e08b853a0c001bda8215819c9cbcb7381e8c2c24 Mon Sep 17 00:00:00 2001
From: Cory Benfield
Date: Fri, 10 Aug 2012 17:24:00 +0100
Subject: [PATCH 14/20] Test for throwing useful exception on bad label.
---
tests/test_requests.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/tests/test_requests.py b/tests/test_requests.py
index f43ccac8..3bbcfdf4 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -19,6 +19,7 @@ from requests.compat import str, StringIO
from requests import HTTPError
from requests import get, post, head, put
from requests.auth import HTTPBasicAuth, HTTPDigestAuth
+from requests.exceptions import InvalidURL
if 'HTTPBIN_URL' not in os.environ:
os.environ['HTTPBIN_URL'] = 'http://httpbin.org/'
@@ -1062,6 +1063,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
"""Test that `bytes` can be used as the values of `files`."""
post(httpbin('post'), files={'test': b'test'})
+ def test_invalid_urls_throw_requests_exception(self):
+ """Test that URLs with invalid labels throw
+ Requests.exceptions.InvalidURL instead of UnicodeError."""
+ self.assertRaises(InvalidURL, get, 'http://.google.com/')
if __name__ == '__main__':
unittest.main()
From 79d53d3b8acf021203853e12e8fe0eeb0b742b51 Mon Sep 17 00:00:00 2001
From: Cory Benfield
Date: Fri, 10 Aug 2012 17:29:12 +0100
Subject: [PATCH 15/20] Throw InvalidURL not UnicodeError on bad label.
---
requests/models.py | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/requests/models.py b/requests/models.py
index 136427fe..ae3c1be1 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -413,7 +413,10 @@ class Request(object):
if not scheme in SCHEMAS:
raise InvalidSchema("Invalid scheme %r" % scheme)
- netloc = netloc.encode('idna').decode('utf-8')
+ try:
+ netloc = netloc.encode('idna').decode('utf-8')
+ except UnicodeError:
+ raise InvalidURL('URL has an invalid label.')
if not path:
path = '/'
From ff55d737d509d8af1308c4b118dd2cc4ebbaaa72 Mon Sep 17 00:00:00 2001
From: Locker537
Date: Thu, 16 Aug 2012 16:27:31 -0400
Subject: [PATCH 16/20] Change variable '_r' to 'r' for consistency.
---
docs/user/quickstart.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index 71ffea05..c0ecf8d2 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -260,11 +260,11 @@ reference::
If we made a bad request (non-200 response), we can raise it with
:class:`Response.raise_for_status()`::
- >>> _r = requests.get('http://httpbin.org/status/404')
- >>> _r.status_code
+ >>> r = requests.get('http://httpbin.org/status/404')
+ >>> r.status_code
404
- >>> _r.raise_for_status()
+ >>> r.raise_for_status()
Traceback (most recent call last):
File "requests/models.py", line 832, in raise_for_status
raise http_error
From b9d3ce2e10339d41aeaeb24c4226c4ce17558b53 Mon Sep 17 00:00:00 2001
From: Locker537
Date: Thu, 16 Aug 2012 16:50:01 -0400
Subject: [PATCH 17/20] Change variable '_r' to 'bad_r' to avoid confusion
about Python's private variable convention.
---
docs/user/quickstart.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index c0ecf8d2..7d0fe5b2 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -260,11 +260,11 @@ reference::
If we made a bad request (non-200 response), we can raise it with
:class:`Response.raise_for_status()`::
- >>> r = requests.get('http://httpbin.org/status/404')
- >>> r.status_code
+ >>> bad_r = requests.get('http://httpbin.org/status/404')
+ >>> bad_r.status_code
404
- >>> r.raise_for_status()
+ >>> bad_r.raise_for_status()
Traceback (most recent call last):
File "requests/models.py", line 832, in raise_for_status
raise http_error
From b31a4399c7cdd0a7c5a7f2c4c7a320fbeb30ebff Mon Sep 17 00:00:00 2001
From: Locker537
Date: Thu, 16 Aug 2012 17:08:57 -0400
Subject: [PATCH 18/20] Remove trailing whitespace from docs directory.
---
docs/MANIFEST.in | 2 +-
docs/_themes/LICENSE | 4 +--
docs/_themes/README.rst | 2 +-
docs/_themes/kr/theme.conf | 2 +-
docs/_themes/kr_small/static/flasky.css_t | 44 +++++++++++------------
docs/user/quickstart.rst | 10 +++---
6 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/docs/MANIFEST.in b/docs/MANIFEST.in
index 403c87a6..fb1021bf 100644
--- a/docs/MANIFEST.in
+++ b/docs/MANIFEST.in
@@ -1 +1 @@
-include HISTORY.rst README.rst LICENSE
\ No newline at end of file
+include HISTORY.rst README.rst LICENSE
\ No newline at end of file
diff --git a/docs/_themes/LICENSE b/docs/_themes/LICENSE
index b160a8ee..3d1e04a2 100644
--- a/docs/_themes/LICENSE
+++ b/docs/_themes/LICENSE
@@ -1,9 +1,9 @@
-Modifications:
+Modifications:
Copyright (c) 2011 Kenneth Reitz.
-Original Project:
+Original Project:
Copyright (c) 2010 by Armin Ronacher.
diff --git a/docs/_themes/README.rst b/docs/_themes/README.rst
index 2e875d46..de8310a2 100644
--- a/docs/_themes/README.rst
+++ b/docs/_themes/README.rst
@@ -1,7 +1,7 @@
krTheme Sphinx Style
====================
-This repository contains sphinx styles Kenneth Reitz uses in most of
+This repository contains sphinx styles Kenneth Reitz uses in most of
his projects. It is a derivative of Mitsuhiko's themes for Flask and Flask related
projects. To use this style in your Sphinx documentation, follow
this guide:
diff --git a/docs/_themes/kr/theme.conf b/docs/_themes/kr/theme.conf
index 307a1f0d..07698f6f 100644
--- a/docs/_themes/kr/theme.conf
+++ b/docs/_themes/kr/theme.conf
@@ -4,4 +4,4 @@ stylesheet = flasky.css
pygments_style = flask_theme_support.FlaskyStyle
[options]
-touch_icon =
+touch_icon =
diff --git a/docs/_themes/kr_small/static/flasky.css_t b/docs/_themes/kr_small/static/flasky.css_t
index fe2141c5..71961a27 100644
--- a/docs/_themes/kr_small/static/flasky.css_t
+++ b/docs/_themes/kr_small/static/flasky.css_t
@@ -8,11 +8,11 @@
* :license: BSD, see LICENSE for details.
*
*/
-
+
@import url("basic.css");
-
+
/* -- page layout ----------------------------------------------------------- */
-
+
body {
font-family: 'Georgia', serif;
font-size: 17px;
@@ -35,7 +35,7 @@ div.bodywrapper {
hr {
border: 1px solid #B1B4B6;
}
-
+
div.body {
background-color: #ffffff;
color: #3E4349;
@@ -46,7 +46,7 @@ img.floatingflask {
padding: 0 0 10px 10px;
float: right;
}
-
+
div.footer {
text-align: right;
color: #888;
@@ -55,12 +55,12 @@ div.footer {
width: 650px;
margin: 0 auto 40px auto;
}
-
+
div.footer a {
color: #888;
text-decoration: underline;
}
-
+
div.related {
line-height: 32px;
color: #888;
@@ -69,18 +69,18 @@ div.related {
div.related ul {
padding: 0 0 0 10px;
}
-
+
div.related a {
color: #444;
}
-
+
/* -- body styles ----------------------------------------------------------- */
-
+
a {
color: #004B6B;
text-decoration: underline;
}
-
+
a:hover {
color: #6D4100;
text-decoration: underline;
@@ -89,7 +89,7 @@ a:hover {
div.body {
padding-bottom: 40px; /* saved for footer */
}
-
+
div.body h1,
div.body h2,
div.body h3,
@@ -109,24 +109,24 @@ div.indexwrapper h1 {
height: {{ theme_index_logo_height }};
}
{% endif %}
-
+
div.body h2 { font-size: 180%; }
div.body h3 { font-size: 150%; }
div.body h4 { font-size: 130%; }
div.body h5 { font-size: 100%; }
div.body h6 { font-size: 100%; }
-
+
a.headerlink {
color: white;
padding: 0 4px;
text-decoration: none;
}
-
+
a.headerlink:hover {
color: #444;
background: #eaeaea;
}
-
+
div.body p, div.body dd, div.body li {
line-height: 1.4em;
}
@@ -164,25 +164,25 @@ div.note {
background-color: #eee;
border: 1px solid #ccc;
}
-
+
div.seealso {
background-color: #ffc;
border: 1px solid #ff6;
}
-
+
div.topic {
background-color: #eee;
}
-
+
div.warning {
background-color: #ffe4e4;
border: 1px solid #f66;
}
-
+
p.admonition-title {
display: inline;
}
-
+
p.admonition-title:after {
content: ":";
}
@@ -254,7 +254,7 @@ dl {
dl dd {
margin-left: 30px;
}
-
+
pre {
padding: 0;
margin: 15px -30px;
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index 7d0fe5b2..66f6119b 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -24,7 +24,7 @@ Make a Request
Making a request with Requests is very simple.
Begin by importing the Requests module::
-
+
>>> import requests
Now, let's try to get a webpage. For this example, let's get GitHub's public
@@ -37,12 +37,12 @@ information we need from this object.
Requests' simple API means that all forms of HTTP request are as obvious. For
example, this is how you make an HTTP POST request::
-
+
>>> r = requests.post("http://httpbin.org/post")
Nice, right? What about the other HTTP request types: PUT, DELETE, HEAD and
OPTIONS? These are all just as simple::
-
+
>>> r = requests.put("http://httpbin.org/put")
>>> r = requests.delete("http://httpbin.org/delete")
>>> r = requests.head("http://httpbin.org/get")
@@ -70,7 +70,7 @@ You can see that the URL has been correctly encoded by printing the URL::
>>> print r.url
u'http://httpbin.org/get?key2=value2&key1=value1'
-
+
Response Content
----------------
@@ -229,7 +229,7 @@ You can set the filename explicitly::
If you want, you can send strings to be received as files::
>>> url = 'http://httpbin.org/post'
- >>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
+ >>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
>>> r = requests.post(url, files=files)
>>> r.text
From 42d0a2169eb894df0fc3c3788925bfd107765597 Mon Sep 17 00:00:00 2001
From: Locker537
Date: Thu, 16 Aug 2012 17:33:27 -0400
Subject: [PATCH 19/20] Whitespace fixes following PEP8.
---
requests/api.py | 2 ++
requests/auth.py | 3 +++
requests/compat.py | 1 -
requests/cookies.py | 30 +++++++++++++++--------
requests/exceptions.py | 10 ++++++++
requests/hooks.py | 1 +
requests/models.py | 3 ++-
requests/safe_mode.py | 9 ++++---
requests/sessions.py | 9 +------
requests/status_codes.py | 2 +-
requests/structures.py | 1 +
requests/utils.py | 3 +++
tests/informal/test_leaked_connections.py | 1 +
tests/test_cookies.py | 21 +++++++++-------
tests/test_requests.py | 9 +++----
tests/test_requests_ext.py | 8 ------
tests/test_requests_https.py | 1 +
17 files changed, 67 insertions(+), 47 deletions(-)
diff --git a/requests/api.py b/requests/api.py
index f192b8f5..ded79352 100644
--- a/requests/api.py
+++ b/requests/api.py
@@ -14,6 +14,7 @@ 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 `.
@@ -52,6 +53,7 @@ def request(method, url, **kwargs):
if adhoc_session:
session.close()
+
def get(url, **kwargs):
"""Sends a GET request. Returns :class:`Response` object.
diff --git a/requests/auth.py b/requests/auth.py
index 6aee69b2..38dd8741 100644
--- a/requests/auth.py
+++ b/requests/auth.py
@@ -34,6 +34,7 @@ log = logging.getLogger(__name__)
CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded'
+
def _basic_auth_str(username, password):
"""Returns a Basic Auth string."""
@@ -239,6 +240,7 @@ class HTTPDigestAuth(AuthBase):
r.register_hook('response', self.handle_401)
return r
+
def _negotiate_value(r):
"""Extracts the gssapi authentication token from the appropriate header"""
@@ -252,6 +254,7 @@ def _negotiate_value(r):
return None
+
class HTTPKerberosAuth(AuthBase):
"""Attaches HTTP GSSAPI/Kerberos Authentication to the given Request object."""
def __init__(self, require_mutual_auth=True):
diff --git a/requests/compat.py b/requests/compat.py
index 201da3a9..d7012033 100644
--- a/requests/compat.py
+++ b/requests/compat.py
@@ -112,4 +112,3 @@ elif is_py3:
bytes = bytes
basestring = (str,bytes)
numeric_types = (int, float)
-
diff --git a/requests/cookies.py b/requests/cookies.py
index 04158561..bd2d6654 100644
--- a/requests/cookies.py
+++ b/requests/cookies.py
@@ -14,6 +14,7 @@ try:
except ImportError:
import dummy_threading as threading
+
class MockRequest(object):
"""Wraps a `requests.Request` to mimic a `urllib2.Request`.
@@ -66,6 +67,7 @@ class MockRequest(object):
def get_new_headers(self):
return self._new_headers
+
class MockResponse(object):
"""Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
@@ -86,6 +88,7 @@ class MockResponse(object):
def getheaders(self, name):
self._headers.getheaders(name)
+
def extract_cookies_to_jar(jar, request, response):
"""Extract the cookies from the response into a CookieJar.
@@ -99,12 +102,14 @@ def extract_cookies_to_jar(jar, request, response):
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."""
r = MockRequest(request)
jar.add_cookie_header(r)
return r.get_new_headers().get('Cookie')
+
def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
"""Unsets a cookie by name, by default over all domains and paths.
@@ -120,10 +125,12 @@ def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
for domain, path, name in clearables:
cookiejar.clear(domain, path, name)
+
class CookieConflictError(RuntimeError):
- """There are two cookies that meet the criteria specified in the cookie jar.
+ """There are two cookies that meet the criteria specified in the cookie jar.
Use .get and .set and include domain and path args in order to be more specific."""
+
class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
"""Compatibility class; is a cookielib.CookieJar, but exposes a dict interface.
@@ -181,7 +188,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
for cookie in iter(self):
values.append(cookie.value)
return values
-
+
def items(self):
"""Dict-like items() that returns a list of name-value tuples from the jar.
See keys() and values(). Allows client-code to call "dict(RequestsCookieJar)
@@ -215,14 +222,14 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
if cookie.domain is not None and cookie.domain in domains:
return True
domains.append(cookie.domain)
- return False # there is only one domain in jar
+ return False # there is only one domain in jar
def get_dict(self, domain=None, path=None):
"""Takes as an argument an optional domain and path and returns a plain old
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 == None or cookie.domain == domain) and (path == None
or cookie.path == path):
dictionary[cookie.name] = cookie.value
return dictionary
@@ -244,7 +251,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
remove_cookie_by_name(self, name)
def _find(self, name, domain=None, path=None):
- """Requests uses this method internally to get cookie values. Takes as args name
+ """Requests uses this method internally to get cookie values. Takes as args name
and optional domain and path. Returns a cookie.value. If there are conflicting cookies,
_find arbitrarily chooses one. See _find_no_duplicates if you want an exception thrown
if there are conflicting cookies."""
@@ -257,18 +264,18 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path))
def _find_no_duplicates(self, name, domain=None, path=None):
- """__get_item__ and get call _find_no_duplicates -- never used in Requests internally.
- Takes as args name and optional domain and path. Returns a cookie.value.
- Throws KeyError if cookie is not found and CookieConflictError if there are
+ """__get_item__ and get call _find_no_duplicates -- never used in Requests internally.
+ Takes as args name and optional domain and path. Returns a cookie.value.
+ Throws KeyError if cookie is not found and CookieConflictError if there are
multiple cookies that match name and optionally domain and path."""
toReturn = None
for cookie in iter(self):
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 != 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
+ toReturn = cookie.value # we will eventually return this as long as no cookie conflict
if toReturn:
return toReturn
@@ -291,6 +298,7 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
"""This is not implemented. Calling this will throw an exception."""
raise NotImplementedError
+
def create_cookie(name, value, **kwargs):
"""Make a cookie from underspecified parameters.
@@ -326,6 +334,7 @@ def create_cookie(name, value, **kwargs):
return cookielib.Cookie(**result)
+
def morsel_to_cookie(morsel):
"""Convert a Morsel object into a Cookie containing the one k/v pair."""
c = create_cookie(
@@ -349,6 +358,7 @@ def morsel_to_cookie(morsel):
)
return c
+
def cookiejar_from_dict(cookie_dict, cookiejar=None):
"""Returns a CookieJar from a key/value dictionary.
diff --git a/requests/exceptions.py b/requests/exceptions.py
index 57f7b82d..6759af56 100644
--- a/requests/exceptions.py
+++ b/requests/exceptions.py
@@ -8,34 +8,44 @@ This module contains the set of Requests' exceptions.
"""
+
class RequestException(RuntimeError):
"""There was an ambiguous exception that occurred while handling your
request."""
+
class HTTPError(RequestException):
"""An HTTP error occurred."""
response = None
+
class ConnectionError(RequestException):
"""A Connection error occurred."""
+
class SSLError(ConnectionError):
"""An SSL error occurred."""
+
class Timeout(RequestException):
"""The request timed out."""
+
class URLRequired(RequestException):
"""A valid URL is required to make a request."""
+
class TooManyRedirects(RequestException):
"""Too many redirects."""
+
class MissingSchema(RequestException, ValueError):
"""The URL schema (e.g. http or https) is missing."""
+
class InvalidSchema(RequestException, ValueError):
"""See defaults.py for valid schemas."""
+
class InvalidURL(RequestException, ValueError):
""" The URL provided was somehow invalid. """
diff --git a/requests/hooks.py b/requests/hooks.py
index 272abb73..55bd9ac6 100644
--- a/requests/hooks.py
+++ b/requests/hooks.py
@@ -30,6 +30,7 @@ import traceback
HOOKS = ('args', 'pre_request', 'pre_send', 'post_request', 'response')
+
def dispatch_hook(key, hooks, hook_data):
"""Dispatches a hook dictionary on a given piece of data."""
diff --git a/requests/models.py b/requests/models.py
index ae3c1be1..87d795c7 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -39,6 +39,7 @@ from .compat import (
REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved)
CONTENT_CHUNK_SIZE = 10 * 1024
+
class Request(object):
"""The :class:`Request ` object. It carries out all functionality of
Requests. Recommended interface is with the Requests functions.
@@ -553,7 +554,7 @@ class Request(object):
self.__dict__.update(r.__dict__)
_p = urlparse(url)
- no_proxy = filter(lambda x:x.strip(), self.proxies.get('no', '').split(','))
+ no_proxy = filter(lambda x: x.strip(), self.proxies.get('no', '').split(','))
proxy = self.proxies.get(_p.scheme)
if proxy and not any(map(_p.netloc.endswith, no_proxy)):
diff --git a/requests/safe_mode.py b/requests/safe_mode.py
index cd171f7d..0fb8d705 100644
--- a/requests/safe_mode.py
+++ b/requests/safe_mode.py
@@ -16,15 +16,16 @@ from .packages.urllib3.response import HTTPResponse
from .exceptions import RequestException, ConnectionError, HTTPError
import socket
+
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')
+ 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)
@@ -32,8 +33,8 @@ def catch_exceptions_if_in_safe_mode(function):
socket.timeout, socket.gaierror) as e:
r = Response()
r.error = e
- r.raw = HTTPResponse() # otherwise, tests fail
- r.status_code = 0 # with this status_code, content returns None
+ 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
diff --git a/requests/sessions.py b/requests/sessions.py
index 73c7b17b..1201498e 100644
--- a/requests/sessions.py
+++ b/requests/sessions.py
@@ -18,6 +18,7 @@ from .hooks import dispatch_hook
from .utils import header_expand
from .packages.urllib3.poolmanager import PoolManager
+
def merge_kwargs(local_kwarg, default_kwarg):
"""Merges kwarg dictionaries.
@@ -56,7 +57,6 @@ class Session(object):
'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks',
'params', 'config', 'verify', 'cert', 'prefetch']
-
def __init__(self,
headers=None,
cookies=None,
@@ -240,7 +240,6 @@ class Session(object):
# Return the response.
return r.response
-
def get(self, url, **kwargs):
"""Sends a GET request. Returns :class:`Response` object.
@@ -251,7 +250,6 @@ class Session(object):
kwargs.setdefault('allow_redirects', True)
return self.request('get', url, **kwargs)
-
def options(self, url, **kwargs):
"""Sends a OPTIONS request. Returns :class:`Response` object.
@@ -262,7 +260,6 @@ class Session(object):
kwargs.setdefault('allow_redirects', True)
return self.request('options', url, **kwargs)
-
def head(self, url, **kwargs):
"""Sends a HEAD request. Returns :class:`Response` object.
@@ -273,7 +270,6 @@ class Session(object):
kwargs.setdefault('allow_redirects', False)
return self.request('head', url, **kwargs)
-
def post(self, url, data=None, **kwargs):
"""Sends a POST request. Returns :class:`Response` object.
@@ -284,7 +280,6 @@ class Session(object):
return self.request('post', url, data=data, **kwargs)
-
def put(self, url, data=None, **kwargs):
"""Sends a PUT request. Returns :class:`Response` object.
@@ -295,7 +290,6 @@ class Session(object):
return self.request('put', url, data=data, **kwargs)
-
def patch(self, url, data=None, **kwargs):
"""Sends a PATCH request. Returns :class:`Response` object.
@@ -306,7 +300,6 @@ class Session(object):
return self.request('patch', url, data=data, **kwargs)
-
def delete(self, url, **kwargs):
"""Sends a DELETE request. Returns :class:`Response` object.
diff --git a/requests/status_codes.py b/requests/status_codes.py
index da74286d..e25ecdb9 100644
--- a/requests/status_codes.py
+++ b/requests/status_codes.py
@@ -83,4 +83,4 @@ for (code, titles) in list(_codes.items()):
for title in titles:
setattr(codes, title, code)
if not title.startswith('\\'):
- setattr(codes, title.upper(), code)
\ No newline at end of file
+ setattr(codes, title.upper(), code)
diff --git a/requests/structures.py b/requests/structures.py
index fd1051a8..3fda9843 100644
--- a/requests/structures.py
+++ b/requests/structures.py
@@ -47,6 +47,7 @@ class CaseInsensitiveDict(dict):
else:
return default
+
class LookupDict(dict):
"""Dictionary lookup object."""
diff --git a/requests/utils.py b/requests/utils.py
index ce08ba78..864760cc 100644
--- a/requests/utils.py
+++ b/requests/utils.py
@@ -49,6 +49,7 @@ POSSIBLE_CA_BUNDLE_PATHS = [
'/etc/ssl/ca-bundle.pem',
]
+
def get_os_ca_bundle_path():
"""Try to pick an available CA certificate bundle provided by the OS."""
for path in POSSIBLE_CA_BUNDLE_PATHS:
@@ -60,6 +61,7 @@ def get_os_ca_bundle_path():
# otherwise, try and use the OS bundle
DEFAULT_CA_BUNDLE_PATH = CERTIFI_BUNDLE_PATH or get_os_ca_bundle_path()
+
def dict_to_sequence(d):
"""Returns an internal sequence dictionary update."""
@@ -445,6 +447,7 @@ def requote_uri(uri):
# or '%')
return quote(unquote_unreserved(uri), safe="!#$%&'()*+,/:;=?@[]~")
+
def get_environ_proxies():
"""Return a dict of environment proxies."""
diff --git a/tests/informal/test_leaked_connections.py b/tests/informal/test_leaked_connections.py
index 5357bf2f..438a6cee 100644
--- a/tests/informal/test_leaked_connections.py
+++ b/tests/informal/test_leaked_connections.py
@@ -6,6 +6,7 @@ the body of the request is not read.
import gc, os, subprocess, requests, sys
+
def main():
gc.disable()
diff --git a/tests/test_cookies.py b/tests/test_cookies.py
index c6f71b42..e1c4203a 100755
--- a/tests/test_cookies.py
+++ b/tests/test_cookies.py
@@ -16,6 +16,7 @@ from requests.compat import cookielib
sys.path.append('.')
from test_requests import httpbin, TestBaseMixin
+
class CookieTests(TestBaseMixin, unittest.TestCase):
def test_cookies_from_response(self):
@@ -106,22 +107,22 @@ class CookieTests(TestBaseMixin, unittest.TestCase):
def test_disabled_cookie_persistence(self):
"""Test that cookies are not persisted when configured accordingly."""
- config = {'store_cookies' : False}
+ config = {'store_cookies': False}
# Check the case when no cookie is passed as part of the request and the one in response is ignored
- cookies = requests.get(httpbin('cookies', 'set', 'key', 'value'), config = config).cookies
+ cookies = requests.get(httpbin('cookies', 'set', 'key', 'value'), config=config).cookies
self.assertTrue(cookies.get("key") is None)
# Test that the cookies passed while making the request still gets used and is available in response object.
# only the ones received from server is not saved
- cookies_2 = requests.get(httpbin('cookies', 'set', 'key', 'value'), config = config,\
- cookies = {"key_2" : "value_2"}).cookies
+ cookies_2 = requests.get(httpbin('cookies', 'set', 'key', 'value'), config=config,\
+ cookies={"key_2": "value_2"}).cookies
self.assertEqual(len(cookies_2), 1)
self.assertEqual(cookies_2.get("key_2"), "value_2")
# Use the session and make sure that the received cookie is not used in subsequent calls
s = requests.session()
- s.get(httpbin('cookies', 'set', 'key', 'value'), config = config)
+ s.get(httpbin('cookies', 'set', 'key', 'value'), config=config)
r = s.get(httpbin('cookies'))
self.assertEqual(json.loads(r.text)['cookies'], {})
@@ -134,7 +135,7 @@ class CookieTests(TestBaseMixin, unittest.TestCase):
self.assertEqual(len(c), len(r.cookies.keys()))
self.assertEqual(len(c), len(r.cookies.values()))
self.assertEqual(len(c), len(r.cookies.items()))
-
+
# domain and path utility functions
domain = r.cookies.list_domains()[0]
path = r.cookies.list_paths()[0]
@@ -151,13 +152,14 @@ class CookieTests(TestBaseMixin, unittest.TestCase):
# test keys, values, and items
self.assertEqual(r.cookies.keys(), ['myname'])
self.assertEqual(r.cookies.values(), ['myvalue'])
- self.assertEqual(r.cookies.items(), [('myname','myvalue')])
-
+ self.assertEqual(r.cookies.items(), [('myname', 'myvalue')])
+
# test if we can convert jar to dict
dictOfCookies = dict(r.cookies)
- self.assertEqual(dictOfCookies, {'myname':'myvalue'})
+ self.assertEqual(dictOfCookies, {'myname': 'myvalue'})
self.assertEqual(dictOfCookies, r.cookies.get_dict())
+
class LWPCookieJarTest(TestBaseMixin, unittest.TestCase):
"""Check store/load of cookies to FileCookieJar's, specifically LWPCookieJar's."""
@@ -254,6 +256,7 @@ class LWPCookieJarTest(TestBaseMixin, unittest.TestCase):
self.assertEqual(len(cookiejar_2), 1)
self.assertCookieHas(list(cookiejar_2)[0], name='Persistent', value='CookiesAreScary')
+
class MozCookieJarTest(LWPCookieJarTest):
"""Same test, but substitute MozillaCookieJar."""
diff --git a/tests/test_requests.py b/tests/test_requests.py
index 3bbcfdf4..25e6bbdc 100755
--- a/tests/test_requests.py
+++ b/tests/test_requests.py
@@ -52,6 +52,7 @@ class TestSetup(object):
# time.sleep(1)
_httpbin = True
+
class TestBaseMixin(object):
def assertCookieHas(self, cookie, **kwargs):
@@ -61,6 +62,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."""
@@ -349,10 +351,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
post1 = post(url, files={'fname.txt': 'fdata'})
self.assertEqual(post1.status_code, 200)
- post2 = post(url, files={'fname.txt': 'fdata', 'fname2.txt':'more fdata'})
+ post2 = post(url, files={'fname.txt': 'fdata', 'fname2.txt': 'more fdata'})
self.assertEqual(post2.status_code, 200)
- post3 = post(url, files={'fname.txt': 'fdata', 'fname2.txt':open(__file__,'rb')})
+ post3 = post(url, files={'fname.txt': 'fdata', 'fname2.txt': open(__file__, 'rb')})
self.assertEqual(post3.status_code, 200)
post4 = post(url, files={'fname.txt': 'fdata'})
@@ -377,7 +379,6 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
self.assertTrue(rbody['files'].get('fname.txt'), None)
self.assertEqual(rbody['files']['fname.txt'], 'fdata to verify')
-
def test_nonzero_evaluation(self):
for service in SERVICES:
@@ -824,7 +825,6 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase):
r = get('http://localhost:1/nope', allow_redirects=False, config=config)
assert r.content == None
-
# def test_invalid_content(self):
# # WARNING: if you're using a terrible DNS provider (comcast),
# # this will fail.
@@ -940,7 +940,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 7645d8c1..3e0d5b73 100644
--- a/tests/test_requests_ext.py
+++ b/tests/test_requests_ext.py
@@ -25,17 +25,14 @@ class RequestsTestSuite(unittest.TestCase):
def test_addition(self):
assert (1 + 1) == 2
-
def test_ssl_hostname_ok(self):
requests.get('https://github.com', verify=True)
-
def test_ssl_hostname_not_ok(self):
requests.get('https://kennethreitz.com', verify=False)
self.assertRaises(requests.exceptions.SSLError, requests.get, 'https://kennethreitz.com')
-
def test_ssl_hostname_session_not_ok(self):
s = requests.session()
@@ -44,7 +41,6 @@ class RequestsTestSuite(unittest.TestCase):
s.get('https://kennethreitz.com', verify=False)
-
def test_binary_post(self):
'''We need to be careful how we build the utf-8 string since
unicode literals are a syntax error in python3
@@ -59,13 +55,10 @@ class RequestsTestSuite(unittest.TestCase):
raise EnvironmentError('Flesh out this test for your environment.')
requests.post('http://www.google.com/', data=utf8_string)
-
-
def test_unicode_error(self):
url = 'http://blip.fm/~1abvfu'
requests.get(url)
-
def test_chunked_head_redirect(self):
url = "http://t.co/NFrx0zLG"
r = requests.head(url, allow_redirects=True)
@@ -128,4 +121,3 @@ class RequestsTestSuite(unittest.TestCase):
if __name__ == '__main__':
unittest.main()
-
diff --git a/tests/test_requests_https.py b/tests/test_requests_https.py
index c6ea8f35..1691a8c0 100755
--- a/tests/test_requests_https.py
+++ b/tests/test_requests_https.py
@@ -9,6 +9,7 @@ import unittest
sys.path.insert(0, os.path.abspath('..'))
import requests
+
class HTTPSTest(unittest.TestCase):
"""Smoke test for https functionality."""
From 76f90054f9ee5813921b3232519915dd88fc7b0c Mon Sep 17 00:00:00 2001
From: Kay Zhu
Date: Fri, 17 Aug 2012 06:12:15 -0400
Subject: [PATCH 20/20] "There many ..." to "There are many ..." in quickstart
---
docs/user/quickstart.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/user/quickstart.rst b/docs/user/quickstart.rst
index 71ffea05..39c77ea1 100644
--- a/docs/user/quickstart.rst
+++ b/docs/user/quickstart.rst
@@ -339,7 +339,7 @@ parameter::
Basic Authentication
--------------------
-Many web services require authentication. There many different types of
+Many web services require authentication. There are many different types of
authentication, but the most common is HTTP Basic Auth.
Making requests with Basic Auth is extremely simple::