From 42ddc4c9e8faff8103adf1e083f0260945357646 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 31 Jul 2012 15:56:22 -0400 Subject: [PATCH 01/12] Need to write tests but this looks good so far. --- requests/models.py | 41 ++++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/requests/models.py b/requests/models.py index 2d83c367..c62b2d37 100644 --- a/requests/models.py +++ b/requests/models.py @@ -37,9 +37,10 @@ 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. + """The :class:`Request ` object. It carries out all functionality + of Requests. Recommended interface is with the Requests functions. """ def __init__(self, @@ -311,9 +312,7 @@ class Request(object): if parameters are supplied as a dict. """ - if isinstance(data, bytes): - return data - if isinstance(data, str): + if isinstance(data, (str, bytes)): return data elif hasattr(data, 'read'): return data @@ -321,7 +320,8 @@ class Request(object): try: dict(data) except ValueError: - raise ValueError('Unable to encode lists with elements that are not 2-tuples.') + raise ValueError('Unable to encode lists with elements that ' + 'are not 2-tuples.') params = list(data.items() if isinstance(data, dict) else data) result = [] @@ -340,11 +340,14 @@ class Request(object): return None try: - fields = self.data.copy() + fields = self.data.items() except AttributeError: - fields = dict(self.data) + fields = dict(self.data).items() - for (k, v) in list(files.items()): + if isinstance(files, dict): + files = files.items() + + for (k, v) in files: # support for explicit filename if isinstance(v, (tuple, list)): fn, fp = v @@ -353,15 +356,19 @@ 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()))) + + new_fields = [] + for field, val in fields: + if isinstance(val, float): + new_fields.append((field, str(val))) + elif isinstance(val, list): + newvalue = ', '.join(val) + new_fields.append((field, newvalue)) + else: + new_fields.append((field, val)) + fields = new_fields - for field in fields: - if isinstance(fields[field], float): - fields[field] = str(fields[field]) - if isinstance(fields[field], list): - newvalue = ', '.join(fields[field]) - fields[field] = newvalue - (body, content_type) = encode_multipart_formdata(fields) return (body, content_type) From 2b33bc289f78adde0df16589122d8cdc8eb09567 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 31 Jul 2012 21:50:44 -0400 Subject: [PATCH 02/12] Tests written for _encode_files new capability. Work on issue #179 --- tests/test_requests.py | 43 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/tests/test_requests.py b/tests/test_requests.py index 60a84077..11d58e78 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -309,11 +309,13 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): with open(__file__) as f: post2 = post(url, files={'some': f}) + post3 = post(url, files=[('some', f)]) self.assertEqual(post2.status_code, 200) - - post3 = post(url, data='[{"some": "json"}]') self.assertEqual(post3.status_code, 200) + post4 = post(url, data='[{"some": "json"}]') + self.assertEqual(post4.status_code, 200) + def test_POSTBIN_GET_POST_FILES_WITH_PARAMS(self): for service in SERVICES: @@ -323,8 +325,13 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): post1 = post(url, files={'some': f}, data={'some': 'data'}) + post2 = post(url, data={'some': 'data'}, files=[('some', f)]) + post3 = post(url, data=[('some', 'data')], + files=[('some', f)]) self.assertEqual(post1.status_code, 200) + self.assertEqual(post2.status_code, 200) + self.assertEqual(post3.status_code, 200) def test_POSTBIN_GET_POST_FILES_WITH_HEADERS(self): @@ -349,10 +356,12 @@ 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'}) @@ -374,9 +383,29 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): post7 = post(url, files={'fname.txt': 'fdata to verify'}) rbody = json.loads(post7.text) self.assertTrue(rbody.get('files', None)) - self.assertTrue(rbody['files'].get('fname.txt'), None) + self.assertTrue(rbody['files'].get('fname.txt', None)) self.assertEqual(rbody['files']['fname.txt'], 'fdata to verify') + post8 = post(url, files=[('fname.txt', 'fdata')]) + self.assertEqual(post8.status_code, 200) + resp_body = post8.json + self.assertTrue(resp_body.get('files', None)) + self.assertTrue(resp_body['files'].get('fname.txt', None)) + self.assertEqual(resp_body['files']['fname.txt'], 'fdata') + + post9 = post(url, files=[('fname.txt', fdata)]) + self.assertEqual(post9.status_code, 200) + + post10 = post(url, files=[('file', + ('file.txt', 'more file data'))]) + self.assertEqual(post10.status_code, 200) + + post11 = post(url, files=[('fname.txt', 'fdata'), + ('fname2.txt', 'more fdata')]) + post12 = post(url, files=[('fname.txt', 'fdata'), + ('fname2.txt', open(__file__, 'rb'))]) + self.assertEqual(post11.status_code, 200) + self.assertEqual(post12.status_code, 200) def test_nonzero_evaluation(self): @@ -972,6 +1001,10 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): t = json.loads(r.text) self.assertEqual(t.get('form'), {'field': 'a, b'}) self.assertEqual(t.get('files'), files) + r = post(httpbin('post'), data=data, files=files.items()) + t = r.json + self.assertEqual(t.get('form'), {'field': 'a, b'}) + self.assertEqual(t.get('files'), files) if __name__ == '__main__': unittest.main() From c71f48b5f1d989644e26b9004c2af7a6f27d4708 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 31 Jul 2012 22:17:47 -0400 Subject: [PATCH 03/12] Some pyflakes fixes. They were just bothering me far too much with vim+syntastic. --- Makefile | 2 +- tests/test_requests.py | 35 ++++++++++++++++++++++++----------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/Makefile b/Makefile index 1473d125..8b2ae83f 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ cipyflakes: ${PYFLAKES_IF_AVAILABLE} ${PYFLAKES_WHITELIST} citests: - nosetests ${CI_TESTS} --with-xunit --xunit-file=junit-report.xml + nosetests ${CI_TESTS} -v --with-xunit --xunit-file=junit-report.xml ci: citests cipyflakes diff --git a/tests/test_requests.py b/tests/test_requests.py index 11d58e78..55215572 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -52,15 +52,18 @@ class TestSetup(object): # time.sleep(1) _httpbin = True + class TestBaseMixin(object): def assertCookieHas(self, cookie, **kwargs): """Assert that a cookie has various specified properties.""" for attr, expected_value in kwargs.items(): cookie_attr = getattr(cookie, attr) - message = 'Failed comparison for %s: %s != %s' % (attr, cookie_attr, expected_value) + 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.""" @@ -121,7 +124,8 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): def test_HTTP_200_OK_GET_WITH_MIXED_PARAMS(self): heads = {'User-agent': 'Mozilla/5.0'} - r = get(httpbin('get') + '?test=true', params={'q': 'test'}, headers=heads) + r = get(httpbin('get') + '?test=true', params={'q': 'test'}, + headers=heads) self.assertEqual(r.status_code, 200) # def test_unicode_headers(self): @@ -761,7 +765,8 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): self.assertEqual(c, _c) # Have the server set a cookie. - r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s) + r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, + session=s) c = json.loads(r.text).get('cookies') assert 'k' in c @@ -826,7 +831,8 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): def test_unpickled_session_requests(self): s = requests.session() - r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s) + r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, + session=s) c = json.loads(r.text).get('cookies') assert 'k' in c @@ -955,24 +961,31 @@ 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 def test_max_redirects(self): - """Test the max_redirects config variable, normally and under safe_mode.""" + """Test the max_redirects config variable, normally and under + safe_mode. + """ def unsafe_callable(): - requests.get(httpbin('redirect', '3'), config=dict(max_redirects=2)) - self.assertRaises(requests.exceptions.TooManyRedirects, unsafe_callable) + requests.get(httpbin('redirect', '3'), + config=dict(max_redirects=2)) + self.assertRaises(requests.exceptions.TooManyRedirects, + unsafe_callable) # add safe mode - response = requests.get(httpbin('redirect', '3'), config=dict(safe_mode=True, max_redirects=2)) + response = requests.get(httpbin('redirect', '3'), + config=dict(safe_mode=True, max_redirects=2)) self.assertTrue(response.content is None) - self.assertTrue(isinstance(response.error, requests.exceptions.TooManyRedirects)) + self.assertTrue(isinstance(response.error, + requests.exceptions.TooManyRedirects)) def test_connection_keepalive_and_close(self): - """Test that we send 'Connection: close' when keep_alive is disabled.""" + """Test that we send 'Connection: close' when keep_alive is + disabled. + """ # keep-alive should be on by default r1 = requests.get(httpbin('get')) # XXX due to proxying issues, test the header sent back by httpbin, rather than From 46b6207f05f0f91c88a69156f88afa7e92c560cf Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Tue, 31 Jul 2012 22:23:47 -0400 Subject: [PATCH 04/12] Fix python3 errors. --- Makefile | 2 +- requests/models.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 8b2ae83f..1473d125 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ cipyflakes: ${PYFLAKES_IF_AVAILABLE} ${PYFLAKES_WHITELIST} citests: - nosetests ${CI_TESTS} -v --with-xunit --xunit-file=junit-report.xml + nosetests ${CI_TESTS} --with-xunit --xunit-file=junit-report.xml ci: citests cipyflakes diff --git a/requests/models.py b/requests/models.py index c62b2d37..8e2e3353 100644 --- a/requests/models.py +++ b/requests/models.py @@ -340,9 +340,9 @@ class Request(object): return None try: - fields = self.data.items() + fields = list(self.data.items()) except AttributeError: - fields = dict(self.data).items() + fields = list(dict(self.data).items()) if isinstance(files, dict): files = files.items() From 1efd06a87da37c074f7590ff5968090d849cea3f Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 1 Aug 2012 09:03:57 -0400 Subject: [PATCH 05/12] This simplification should work. Probably should write a test case where it should fail though. --- requests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/models.py b/requests/models.py index 8e2e3353..379c26d0 100644 --- a/requests/models.py +++ b/requests/models.py @@ -342,7 +342,7 @@ class Request(object): try: fields = list(self.data.items()) except AttributeError: - fields = list(dict(self.data).items()) + fields = list(self.data) if isinstance(files, dict): files = files.items() From 5ff165a1e2b30d5568c058b11139038963b4f979 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Wed, 1 Aug 2012 10:36:45 -0400 Subject: [PATCH 06/12] Better handling of invalid files. I stole the idea from _encode_params in all candor. --- requests/models.py | 7 +++++++ tests/test_requests.py | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/requests/models.py b/requests/models.py index 379c26d0..9bda7497 100644 --- a/requests/models.py +++ b/requests/models.py @@ -342,8 +342,15 @@ class Request(object): try: fields = list(self.data.items()) except AttributeError: + dict(self.data) fields = list(self.data) + try: + dict(files) + except ValueError: + raise ValueError('Unable to encode lists with elements that ' + 'are not 2-tuples.') + if isinstance(files, dict): files = files.items() diff --git a/tests/test_requests.py b/tests/test_requests.py index 55215572..4e0d0347 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -320,6 +320,11 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): post4 = post(url, data='[{"some": "json"}]') self.assertEqual(post4.status_code, 200) + try: + post(url, files=['bad file data']) + except ValueError: + pass + def test_POSTBIN_GET_POST_FILES_WITH_PARAMS(self): for service in SERVICES: From 2d5e38f30ad9f3bd0e3a87518ae79ccbdf779369 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 3 Aug 2012 22:04:43 -0400 Subject: [PATCH 07/12] params now accepts a k/v list. Also added test for params accepting k/v lists. --- requests/sessions.py | 13 +++++++++++-- tests/test_requests.py | 5 +++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/requests/sessions.py b/requests/sessions.py index 3113c787..ee47a012 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. @@ -37,12 +38,21 @@ def merge_kwargs(local_kwarg, default_kwarg): if not hasattr(default_kwarg, 'items'): return local_kwarg + try: + dict(local_kwarg) + except ValueError: + raise ValueError('Unable to encode lists with elements that are not ' + '2-tuples.') + + if hasattr(local_kwarg, 'items'): + local_kwarg = list(local_kwarg.items()) + # Update new values. kwargs = default_kwarg.copy() kwargs.update(local_kwarg) # Remove keys that are set to None. - for (k, v) in list(local_kwarg.items()): + for (k, v) in local_kwarg: if v is None: del kwargs[k] @@ -56,7 +66,6 @@ class Session(object): 'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks', 'params', 'config', 'verify', 'cert', 'prefetch'] - def __init__(self, headers=None, cookies=None, diff --git a/tests/test_requests.py b/tests/test_requests.py index 4e0d0347..076ca6ce 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -96,6 +96,11 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): self.assertEqual(request.full_url, "http://example.com/path?key=value&a=b#fragment") + def test_params_accepts_kv_list(self): + request = requests.Request('http://example.com/path', + params=[('a', 'b')]) + self.assertEqual(request.full_url, 'http://example.com/path?a=b') + def test_HTTP_200_OK_GET(self): r = get(httpbin('get')) self.assertEqual(r.status_code, 200) From 1722f289711e3d03b0e00fb548f3e8ea92544775 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sun, 5 Aug 2012 23:28:19 -0400 Subject: [PATCH 08/12] Add to_key_val_lists to avoid repetition. It uses the same logic whenever we're trying to use a list of key values and avoid what I had started doing -- using the same pattern everywhere. proxies, and headers should both be covered by this commit. --- requests/models.py | 27 ++++----------------------- requests/sessions.py | 33 ++++++++++++++------------------- requests/utils.py | 27 +++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/requests/models.py b/requests/models.py index 514bcb40..cdcdee8c 100644 --- a/requests/models.py +++ b/requests/models.py @@ -29,7 +29,7 @@ from .exceptions import ( from .utils import ( get_encoding_from_headers, stream_untransfer, guess_filename, requote_uri, stream_decode_response_unicode, get_netrc_auth, get_environ_proxies, - DEFAULT_CA_BUNDLE_PATH) + to_key_val_list, DEFAULT_CA_BUNDLE_PATH) from .compat import ( cookielib, urlparse, urlunparse, urljoin, urlsplit, urlencode, str, bytes, StringIO, is_py2, chardet, json, builtin_str) @@ -317,15 +317,8 @@ class Request(object): elif hasattr(data, 'read'): return data elif hasattr(data, '__iter__'): - try: - dict(data) - except ValueError: - raise ValueError('Unable to encode lists with elements that ' - 'are not 2-tuples.') - - params = list(data.items() if isinstance(data, dict) else data) result = [] - for k, vs in params: + for k, vs in to_key_val_list(data): for v in isinstance(vs, list) and vs or [vs]: result.append( (k.encode('utf-8') if isinstance(k, str) else k, @@ -339,20 +332,8 @@ class Request(object): if (not files) or isinstance(self.data, str): return None - try: - fields = list(self.data.items()) - except AttributeError: - dict(self.data) - fields = list(self.data) - - try: - dict(files) - except ValueError: - raise ValueError('Unable to encode lists with elements that ' - 'are not 2-tuples.') - - if isinstance(files, dict): - files = files.items() + fields = to_key_val_list(self.data) + files = to_key_val_list(files) for (k, v) in files: # support for explicit filename diff --git a/requests/sessions.py b/requests/sessions.py index ee47a012..32d39fc5 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -15,7 +15,7 @@ from .cookies import cookiejar_from_dict, remove_cookie_by_name from .defaults import defaults from .models import Request from .hooks import dispatch_hook -from .utils import header_expand +from .utils import header_expand, to_key_val_list from .packages.urllib3.poolmanager import PoolManager @@ -38,14 +38,7 @@ def merge_kwargs(local_kwarg, default_kwarg): if not hasattr(default_kwarg, 'items'): return local_kwarg - try: - dict(local_kwarg) - except ValueError: - raise ValueError('Unable to encode lists with elements that are not ' - '2-tuples.') - - if hasattr(local_kwarg, 'items'): - local_kwarg = list(local_kwarg.items()) + local_kwarg = to_key_val_list(local_kwarg) # Update new values. kwargs = default_kwarg.copy() @@ -79,12 +72,12 @@ class Session(object): verify=True, cert=None): - self.headers = headers or {} + self.headers = to_key_val_list(headers or []) self.auth = auth self.timeout = timeout - self.proxies = proxies or {} + self.proxies = to_key_val_list(proxies or []) self.hooks = hooks or {} - self.params = params or {} + self.params = to_key_val_list(params or []) self.config = config or {} self.prefetch = prefetch self.verify = verify @@ -157,10 +150,10 @@ class Session(object): method = str(method).upper() # Default empty dicts for dict params. - data = {} if data is None else data - files = {} if files is None else files - headers = {} if headers is None else headers - params = {} if params is None else params + data = [] if data is None else data + files = [] if files is None else files + headers = [] if headers is None else headers + params = [] if params is None else params hooks = {} if hooks is None else hooks prefetch = self.prefetch or prefetch @@ -170,8 +163,10 @@ class Session(object): # Expand header values. if headers: - for k, v in list(headers.items()) or {}: - headers[k] = header_expand(v) + expanded = [] + for k, v in to_key_val_list(headers): + expanded.append((k, header_expand(v))) + headers = expanded args = dict( method=method, @@ -185,7 +180,7 @@ class Session(object): hooks=hooks, timeout=timeout, allow_redirects=allow_redirects, - proxies=proxies, + proxies=to_key_val_list(proxies), config=config, prefetch=prefetch, verify=verify, diff --git a/requests/utils.py b/requests/utils.py index ce08ba78..53bb80f5 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -112,6 +112,33 @@ def guess_filename(obj): return name +def to_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return a list of + tuples, e.g.,: + + >>> to_key_val_list([('key', 'val')]) + [('key', 'val')] + >>> to_key_val_list('string') + ValueError: ... + >>> to_key_val_list({'key': 'val'}) + [('key', 'val')] + """ + if value is None: + return None + + try: + dict(value) + except ValueError: + raise ValueError('Unable to encode lists with elements that are not ' + '2-tuples.') + + if isinstance(value, dict) or hasattr(value, 'items'): + value = value.items() + + return list(value) + + # From mitsuhiko/werkzeug (used with permission). def parse_list_header(value): """Parse lists as described by RFC 2068 Section 2. From f01694e2743c9883ca316d3abd8d2385d5c5f37e Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Aug 2012 13:47:14 -0400 Subject: [PATCH 09/12] All tests pass, time for a PR. --- requests/models.py | 4 ++-- tests/test_requests.py | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/requests/models.py b/requests/models.py index f35ef7e1..9270f0ea 100644 --- a/requests/models.py +++ b/requests/models.py @@ -348,6 +348,7 @@ class Request(object): if (not files) or isinstance(self.data, str): return None + new_fields = [] fields = to_key_val_list(self.data) files = to_key_val_list(files) @@ -362,9 +363,8 @@ class Request(object): fp = StringIO(fp) if isinstance(fp, bytes): fp = BytesIO(fp) - fields.append((k, (fn, fp.read()))) + new_fields.append((k, (fn, fp.read()))) - new_fields = [] for field, val in fields: if isinstance(val, list): for v in val: diff --git a/tests/test_requests.py b/tests/test_requests.py index 10b43deb..b7dba369 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -1038,8 +1038,6 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): self.assertEqual(t.get('form'), {'field': ['a', 'b']}) self.assertEqual(t.get('files'), files) r = post(httpbin('post'), data=data, files=files.items()) - t = r.json - self.assertEqual(t.get('form'), {'field': 'a, b'}) self.assertEqual(t.get('files'), files) def test_str_data_content_type(self): From ab56e4a9f170c2c951d443853466f27b31dcc256 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Aug 2012 14:41:13 -0400 Subject: [PATCH 10/12] Fix python3 tests. I wasn't thorough enough with how I dealt with headers. Most of the header logic in the Request object utilizes dictionary properties which will not work with a key/value list. I'll dig more into this, but I know the rest of the features are more important so I'll take my time on this and send a separate pull request. --- requests/sessions.py | 13 +++++++------ tests/test_requests.py | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/requests/sessions.py b/requests/sessions.py index cd6daa66..cd05490d 100644 --- a/requests/sessions.py +++ b/requests/sessions.py @@ -72,7 +72,8 @@ class Session(object): verify=True, cert=None): - self.headers = to_key_val_list(headers or []) + #self.headers = to_key_val_list(headers or []) + self.headers = headers or {} self.auth = auth self.timeout = timeout self.proxies = to_key_val_list(proxies or []) @@ -160,7 +161,7 @@ class Session(object): # Default empty dicts for dict params. data = [] if data is None else data files = [] if files is None else files - headers = [] if headers is None else headers + headers = {} if headers is None else headers params = [] if params is None else params hooks = {} if hooks is None else hooks prefetch = prefetch if prefetch is not None else self.prefetch @@ -171,10 +172,10 @@ class Session(object): # Expand header values. if headers: - expanded = [] - for k, v in to_key_val_list(headers): - expanded.append((k, header_expand(v))) - headers = expanded + #e = [(k, header_expand(v)) for k, v in to_key_val_list(headers)] + #headers = e + for k, v in list(headers.items()) or {}: + headers[k] = header_expand(v) args = dict( method=method, diff --git a/tests/test_requests.py b/tests/test_requests.py index b7dba369..29ea9804 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -977,7 +977,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): # Don't choke on headers with none in the value. requests.get(httpbin('headers'), headers={'Foo': None}) except TypeError: - self.fail() + self.fail('Not able to have none in header values') def test_danger_mode_redirects(self): s = requests.session() From 329af44f351eaea251601cabcafcd70a62521af5 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Aug 2012 16:39:52 -0400 Subject: [PATCH 11/12] Forgot to add myself to the AUTHORS.rst [ci skip] --- AUTHORS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index f21d1736..47ffd102 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -111,3 +111,4 @@ Patches and Suggestions - Leila Muhtasib - Matthias Rahlf - Jakub Roztocil +- Ian Cordasco @sigmavirus24 From a5d462e176c61c9967ef6cbcc0ef50a4764dc0b6 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Sat, 18 Aug 2012 18:31:58 -0400 Subject: [PATCH 12/12] Revert "Some pyflakes fixes." This reverts commit c71f48b5f1d989644e26b9004c2af7a6f27d4708. To please his BDFLness @kennethreitz ;) --- tests/test_requests.py | 35 +++++++++++------------------------ 1 file changed, 11 insertions(+), 24 deletions(-) diff --git a/tests/test_requests.py b/tests/test_requests.py index 29ea9804..ff768cbe 100755 --- a/tests/test_requests.py +++ b/tests/test_requests.py @@ -52,18 +52,15 @@ class TestSetup(object): # time.sleep(1) _httpbin = True - class TestBaseMixin(object): def assertCookieHas(self, cookie, **kwargs): """Assert that a cookie has various specified properties.""" for attr, expected_value in kwargs.items(): cookie_attr = getattr(cookie, attr) - message = 'Failed comparison for %s: %s != %s' % (attr, - cookie_attr, expected_value) + 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.""" @@ -129,8 +126,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): def test_HTTP_200_OK_GET_WITH_MIXED_PARAMS(self): heads = {'User-agent': 'Mozilla/5.0'} - r = get(httpbin('get') + '?test=true', params={'q': 'test'}, - headers=heads) + r = get(httpbin('get') + '?test=true', params={'q': 'test'}, headers=heads) self.assertEqual(r.status_code, 200) # def test_unicode_headers(self): @@ -775,8 +771,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): self.assertEqual(c, _c) # Have the server set a cookie. - r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, - session=s) + r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s) c = json.loads(r.text).get('cookies') assert 'k' in c @@ -841,8 +836,7 @@ class RequestsTestSuite(TestSetup, TestBaseMixin, unittest.TestCase): def test_unpickled_session_requests(self): s = requests.session() - r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, - session=s) + r = get(httpbin('cookies', 'set', 'k', 'v'), allow_redirects=True, session=s) c = json.loads(r.text).get('cookies') assert 'k' in c @@ -984,31 +978,24 @@ 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 def test_max_redirects(self): - """Test the max_redirects config variable, normally and under - safe_mode. - """ + """Test the max_redirects config variable, normally and under safe_mode.""" def unsafe_callable(): - requests.get(httpbin('redirect', '3'), - config=dict(max_redirects=2)) - self.assertRaises(requests.exceptions.TooManyRedirects, - unsafe_callable) + requests.get(httpbin('redirect', '3'), config=dict(max_redirects=2)) + self.assertRaises(requests.exceptions.TooManyRedirects, unsafe_callable) # add safe mode - response = requests.get(httpbin('redirect', '3'), - config=dict(safe_mode=True, max_redirects=2)) + response = requests.get(httpbin('redirect', '3'), config=dict(safe_mode=True, max_redirects=2)) self.assertTrue(response.content is None) - self.assertTrue(isinstance(response.error, - requests.exceptions.TooManyRedirects)) + self.assertTrue(isinstance(response.error, requests.exceptions.TooManyRedirects)) def test_connection_keepalive_and_close(self): - """Test that we send 'Connection: close' when keep_alive is - disabled. - """ + """Test that we send 'Connection: close' when keep_alive is disabled.""" # keep-alive should be on by default r1 = requests.get(httpbin('get')) # XXX due to proxying issues, test the header sent back by httpbin, rather than