From 8c737069a53933566403ad115234e9e6c809b3d6 Mon Sep 17 00:00:00 2001 From: Rick Mak Date: Wed, 17 Aug 2011 12:49:19 +0800 Subject: [PATCH 01/62] Return the r.content as unicode. --- requests/models.py | 49 +++++++++++++++++++++++++++++++++- test_unicode.py | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 test_unicode.py diff --git a/requests/models.py b/requests/models.py index a2775550..2e35c7ec 100644 --- a/requests/models.py +++ b/requests/models.py @@ -10,6 +10,7 @@ import urllib import urllib2 import socket import zlib +import cgi from urllib2 import HTTPError from urlparse import urlparse, urlunparse, urljoin @@ -400,8 +401,54 @@ class Response(object): self._content = zlib.decompress(self._content, 16+zlib.MAX_WBITS) except zlib.error: pass - return self._content + return self.unicode_content(self._content) + + def get_content_type(self): + content_type = self.headers.get("content-type") + content_type, params = cgi.parse_header(content_type) + return content_type, params + + def get_encoding_from_content_type(self): + content_type, params = self.get_content_type() + if "charset" in params: + return params["charset"].strip("'\"") + + def get_encodings_from_content(self, content): + if self._charset_re is None: + self._charset_re = re.compile( + r']', flags=re.I + ) + return self._charset_re.findall(content) + + def unicode_content(self, content): + """ + Returns the requested content back in unicode. + Tried: + 1. charset from content-type + 2. every encodings from + 3. fall back and replace all unicode characters + """ + # Try charset from content-type + encoding = self.get_encoding_from_content_type() + if encoding: + try: + return unicode(content, encoding) + except UnicodeError: + self.tried_encodings.append(encoding) + + # Try every encodings from + encodings = self.get_encodings_from_content(content) + for encoding in encodings: + if encoding in self.tried_encodings: + continue + try: + return unicode(content, encoding) + except UnicodeError: + self.tried_encodings.append(encoding) + + # Fall back: + return unicode(content, encoding, errors="replace") def raise_for_status(self): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occured.""" diff --git a/test_unicode.py b/test_unicode.py new file mode 100644 index 00000000..38a1dfcd --- /dev/null +++ b/test_unicode.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from __future__ import with_statement + +import unittest +import cookielib + +try: + import omnijson as json +except ImportError: + import json + +import requests + + + +HTTPBIN_URL = 'http://httpbin.org/' +HTTPSBIN_URL = 'https://httpbin.ep.io/' + +# HTTPBIN_URL = 'http://staging.httpbin.org/' +# HTTPSBIN_URL = 'https://httpbin-staging.ep.io/' + + +def httpbin(*suffix): + """Returns url for HTTPBIN resource.""" + + return HTTPBIN_URL + '/'.join(suffix) + + +def httpsbin(*suffix): + """Returns url for HTTPSBIN resource.""" + + return HTTPSBIN_URL + '/'.join(suffix) + + +SERVICES = (httpbin, httpsbin) + + + +class RequestsTestSuite(unittest.TestCase): + """Requests test cases.""" + + + def setUp(self): + pass + + + def tearDown(self): + """Teardown.""" + pass + + + def test_HTTP_200_OK_GET_ON_ISO88591(self): + r = requests.get("http://www.qypedeals.de/Verzehrgutschein+für+Jellyfish") + self.assertEqual(r.status_code, 200) + self.assertIsInstance(r.content, unicode) + + def test_HTTP_200_OK_GET_ON_BIG5(self): + r = requests.get("http://google.com.hk/") + self.assertEqual(r.status_code, 200) + self.assertIsInstance(r.content, unicode) + + +if __name__ == '__main__': + unittest.main() From 820e2c73e62b94b43fc957a7d4d168050c7eabf5 Mon Sep 17 00:00:00 2001 From: Rick Mak Date: Thu, 18 Aug 2011 14:22:54 +0800 Subject: [PATCH 02/62] Import re --- requests/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/requests/models.py b/requests/models.py index 2e35c7ec..a2e4c2eb 100644 --- a/requests/models.py +++ b/requests/models.py @@ -11,6 +11,7 @@ import urllib2 import socket import zlib import cgi +import re from urllib2 import HTTPError from urlparse import urlparse, urlunparse, urljoin From d26f3333e4d2ac65fd82bd413bc5759a0808e259 Mon Sep 17 00:00:00 2001 From: Rick Mak Date: Thu, 18 Aug 2011 14:42:35 +0800 Subject: [PATCH 03/62] Fix tried_encodings scope --- requests/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/requests/models.py b/requests/models.py index a2e4c2eb..a8aa6cb5 100644 --- a/requests/models.py +++ b/requests/models.py @@ -430,23 +430,24 @@ class Response(object): 2. every encodings from 3. fall back and replace all unicode characters """ + tried_encodings = [] # Try charset from content-type encoding = self.get_encoding_from_content_type() if encoding: try: return unicode(content, encoding) except UnicodeError: - self.tried_encodings.append(encoding) + tried_encodings.append(encoding) # Try every encodings from encodings = self.get_encodings_from_content(content) for encoding in encodings: - if encoding in self.tried_encodings: + if encoding in tried_encodings: continue try: return unicode(content, encoding) except UnicodeError: - self.tried_encodings.append(encoding) + tried_encodings.append(encoding) # Fall back: return unicode(content, encoding, errors="replace") From 5f16a8a6b1684095f78b14533e1fe492265ce442 Mon Sep 17 00:00:00 2001 From: Alejandro Giacometti Date: Sat, 20 Aug 2011 23:05:39 +0200 Subject: [PATCH 04/62] Added readline method to response object. --- requests/models.py | 1 + 1 file changed, 1 insertion(+) diff --git a/requests/models.py b/requests/models.py index 2d7fc8fe..3358e120 100644 --- a/requests/models.py +++ b/requests/models.py @@ -176,6 +176,7 @@ class Request(object): try: response.headers = CaseInsensitiveDict(getattr(resp.info(), 'dict', None)) response.read = resp.read + response.readline = resp.readline response._resp = resp response._close = resp.close From 8bfa909ff2bcf8b51f19a5d612f82301f9afce3f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 18:34:33 -0400 Subject: [PATCH 05/62] merge remnant (oops) --- AUTHORS.orig | 40 ---------------------------------------- 1 file changed, 40 deletions(-) delete mode 100644 AUTHORS.orig diff --git a/AUTHORS.orig b/AUTHORS.orig deleted file mode 100644 index dd88224b..00000000 --- a/AUTHORS.orig +++ /dev/null @@ -1,40 +0,0 @@ -Requests is written and maintained by Kenneth Reitz and -various contributors: - -Development Lead -```````````````` - -- Kenneth Reitz - - -Patches and Suggestions -``````````````````````` - -- Various Pocoo Members -- Chris Adams -- Flavio Percoco Premoli -- Dj Gilcrease -- Justin Murphy -- Rob Madole -- Aram Dulyan -- Johannes Gorset -- 村山めがね (Megane Murayama) -- James Rowe -- Daniel Schauenberg -- Zbigniew Siciarz -- Daniele Tricoli 'Eriol' -- Richard Boulton -- Miguel Olivares -- Alberto Paro -- Jérémy Bethmont -- 潘旭 (Xu Pan) -- Tamás Gulácsi -- Rubén Abad -- Peter Manser -- Jeremy Selie -<<<<<<< HEAD -- Jens Diemer -- Alex <@alopatin> -======= -- Tom Hogans ->>>>>>> 0ed641a26ec2200de00e4bbf3d170c767375351e From 7fc8c7ccfd46b2ac37dfc4d8aa1225b139287de1 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:17:25 -0400 Subject: [PATCH 06/62] move encoding detection out of request object. --- requests/models.py | 77 +++++++++++++++------------------------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/requests/models.py b/requests/models.py index 3cbf1029..b12112ac 100644 --- a/requests/models.py +++ b/requests/models.py @@ -10,8 +10,7 @@ import urllib import urllib2 import socket import zlib -import cgi -import re + from urllib2 import HTTPError from urlparse import urlparse, urlunparse, urljoin @@ -22,9 +21,9 @@ from .monkeys import Request as _Request, HTTPBasicAuthHandler, HTTPForcedBasicA from .structures import CaseInsensitiveDict from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers, get_handlers -from .utils import dict_from_cookiejar -from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects +from .utils import dict_from_cookiejar, get_unicode_from_response from .status_codes import codes +from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) @@ -420,73 +419,43 @@ class Response(object): def __nonzero__(self): """Returns true if :attr:`status_code` is 'OK'.""" + return not self.error def __getattr__(self, name): - """Read and returns the full stream when accessing to :attr: `content`""" + """Read and returns the full stream when accessing to + :attr: `content` + """ + if name == 'content': if self._content is not None: return self._content + + # Read the contents. self._content = self.read() + + # Decode GZip'd content. if self.headers.get('content-encoding', '') == 'gzip': try: self._content = zlib.decompress(self._content, 16+zlib.MAX_WBITS) except zlib.error: pass - return self.unicode_content(self._content) - + # Decode unicode content. + try: + self._content = get_unicode_from_response(self) + # Don't trust this stuff. + except UserWarning, e: + print e + + + return self._content + else: raise AttributeError - - def get_content_type(self): - content_type = self.headers.get("content-type") - content_type, params = cgi.parse_header(content_type) - return content_type, params - def get_encoding_from_content_type(self): - content_type, params = self.get_content_type() - if "charset" in params: - return params["charset"].strip("'\"") - - def get_encodings_from_content(self, content): - if self._charset_re is None: - self._charset_re = re.compile( - r']', flags=re.I - ) - return self._charset_re.findall(content) - - def unicode_content(self, content): - """ - Returns the requested content back in unicode. - Tried: - 1. charset from content-type - 2. every encodings from - 3. fall back and replace all unicode characters - """ - tried_encodings = [] - # Try charset from content-type - encoding = self.get_encoding_from_content_type() - if encoding: - try: - return unicode(content, encoding) - except UnicodeError: - tried_encodings.append(encoding) - - # Try every encodings from - encodings = self.get_encodings_from_content(content) - for encoding in encodings: - if encoding in tried_encodings: - continue - try: - return unicode(content, encoding) - except UnicodeError: - tried_encodings.append(encoding) - - # Fall back: - return unicode(content, encoding, errors="replace") def raise_for_status(self): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occured.""" @@ -499,6 +468,8 @@ class Response(object): self._resp.fp._sock.recv = None self._close() + + class AuthManager(object): """Requests Authentication Manager.""" From 8fbb1e6d97cda90d588d4263a18906a52d147fba Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:17:41 -0400 Subject: [PATCH 07/62] move encoding methods into utils for external consumption --- requests/utils.py | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/requests/utils.py b/requests/utils.py index 8ac78b4e..72705734 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -9,7 +9,9 @@ that are also useful for external consumption. """ +import cgi import cookielib +import re def dict_from_cookiejar(cookiejar): @@ -70,3 +72,62 @@ def add_dict_to_cookiejar(cj, cookie_dict): cj.set_cookie(cookie) return cj + + +def get_encodings_from_content(content): + """Returns encodings from given content string.""" + + charset_re = re.compile(r']', flags=re.I) + + return charset_re.findall(content) + + + +def get_encoding_from_headers(headers): + """Returns encodings from given HTTP Header Dict.""" + + content_type = headers.get('content-type') + content_type, params = cgi.parse_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + +def get_unicode_from_response(r): + """Returns the requested content back in unicode. + + Tried: + 1. charset from content-type + 2. every encodings from + 3. fall back and replace all unicode characters + """ + + tried_encodings = [] + + # Try charset from content-type + encoding = get_encoding_from_headers(r.headers) + + if encoding: + try: + print '!' + return unicode(r.content, encoding) + except UnicodeError: + tried_encodings.append(encoding) + + # Try every encodings from + encodings = get_encodings_from_content(r.content) + + for encoding in encodings: + if encoding in tried_encodings: + continue + try: + + return unicode(r.content, encoding) + except (UnicodeError, TypeError): + tried_encodings.append(encoding) + + # Fall back: + try: + return unicode(r.content, encoding, errors='replace') + except TypeError: + return r.content From 4922daf4989d921dd873b93f5ec08e02ad2222b6 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:22:18 -0400 Subject: [PATCH 08/62] added Rick Mak to AUTHORS --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 61874982..1cf7d350 100644 --- a/AUTHORS +++ b/AUTHORS @@ -38,4 +38,5 @@ Patches and Suggestions - Armin Ronacher - Shrikant Sharat Kandula - Mikko Ohtamaa -- Den Shabalin \ No newline at end of file +- Den Shabalin +- Rick Mak \ No newline at end of file From 01411e37d65111d9bf09ac7ba82338664b595a0f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:22:48 -0400 Subject: [PATCH 09/62] AUTHORS += Alejandro Giacometti --- AUTHORS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 61874982..ed833ff5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -38,4 +38,5 @@ Patches and Suggestions - Armin Ronacher - Shrikant Sharat Kandula - Mikko Ohtamaa -- Den Shabalin \ No newline at end of file +- Den Shabalin +- Alejandro Giacometti \ No newline at end of file From 882ea76aa994918d3a62d9f31ad88533edd3ba03 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:26:56 -0400 Subject: [PATCH 10/62] cleanups, response.fo --- requests/models.py | 52 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/requests/models.py b/requests/models.py index 3358e120..26436892 100644 --- a/requests/models.py +++ b/requests/models.py @@ -11,6 +11,7 @@ import urllib2 import socket import zlib + from urllib2 import HTTPError from urlparse import urlparse, urlunparse, urljoin from datetime import datetime @@ -20,9 +21,9 @@ from .monkeys import Request as _Request, HTTPBasicAuthHandler, HTTPForcedBasicA from .structures import CaseInsensitiveDict from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers, get_handlers -from .utils import dict_from_cookiejar -from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects +from .utils import dict_from_cookiejar, get_unicode_from_response from .status_codes import codes +from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) @@ -132,9 +133,16 @@ class Request(object): _handlers.append(urllib2.HTTPCookieProcessor(self.cookiejar)) if self.auth: - if not isinstance(self.auth.handler, (urllib2.AbstractBasicAuthHandler, urllib2.AbstractDigestAuthHandler)): + if not isinstance(self.auth.handler, + (urllib2.AbstractBasicAuthHandler, + urllib2.AbstractDigestAuthHandler)): + # TODO: REMOVE THIS COMPLETELY - auth_manager.add_password(self.auth.realm, self.url, self.auth.username, self.auth.password) + auth_manager.add_password( + self.auth.realm, self.url, + self.auth.username, + self.auth.password) + self.auth.handler = self.auth.handler(auth_manager) auth_manager.add_auth(self.url, self.auth) @@ -166,7 +174,10 @@ class Request(object): def _build_response(self, resp, is_error=False): - """Build internal :class:`Response ` object from given response.""" + """Build internal :class:`Response ` object + from given response. + """ + def build(resp): @@ -176,8 +187,7 @@ class Request(object): try: response.headers = CaseInsensitiveDict(getattr(resp.info(), 'dict', None)) response.read = resp.read - response.readline = resp.readline - response._resp = resp + response.fo = resp response._close = resp.close if self.cookiejar: @@ -419,24 +429,44 @@ class Response(object): def __nonzero__(self): """Returns true if :attr:`status_code` is 'OK'.""" + return not self.error def __getattr__(self, name): - """Read and returns the full stream when accessing to :attr: `content`""" + """Read and returns the full stream when accessing to + :attr: `content` + """ + if name == 'content': if self._content is not None: return self._content + + # Read the contents. self._content = self.read() + + # Decode GZip'd content. if self.headers.get('content-encoding', '') == 'gzip': try: self._content = zlib.decompress(self._content, 16+zlib.MAX_WBITS) except zlib.error: pass + + # Decode unicode content. + try: + self._content = get_unicode_from_response(self) + # Don't trust this stuff. + except UserWarning, e: + print e + + return self._content + else: raise AttributeError + + def raise_for_status(self): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occured.""" if self.error: @@ -444,10 +474,12 @@ class Response(object): def close(self): - if self._resp.fp is not None and hasattr(self._resp.fp, '_sock'): - self._resp.fp._sock.recv = None + if self.fo.fp is not None and hasattr(self.fo.fp, '_sock'): + self.fo.fp._sock.recv = None self._close() + + class AuthManager(object): """Requests Authentication Manager.""" From 7bd47777a941237036ba8e15a2aaf2e93cc8e467 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:40:33 -0400 Subject: [PATCH 11/62] no separate test suite --- test_unicode.py | 66 ------------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 test_unicode.py diff --git a/test_unicode.py b/test_unicode.py deleted file mode 100644 index 38a1dfcd..00000000 --- a/test_unicode.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from __future__ import with_statement - -import unittest -import cookielib - -try: - import omnijson as json -except ImportError: - import json - -import requests - - - -HTTPBIN_URL = 'http://httpbin.org/' -HTTPSBIN_URL = 'https://httpbin.ep.io/' - -# HTTPBIN_URL = 'http://staging.httpbin.org/' -# HTTPSBIN_URL = 'https://httpbin-staging.ep.io/' - - -def httpbin(*suffix): - """Returns url for HTTPBIN resource.""" - - return HTTPBIN_URL + '/'.join(suffix) - - -def httpsbin(*suffix): - """Returns url for HTTPSBIN resource.""" - - return HTTPSBIN_URL + '/'.join(suffix) - - -SERVICES = (httpbin, httpsbin) - - - -class RequestsTestSuite(unittest.TestCase): - """Requests test cases.""" - - - def setUp(self): - pass - - - def tearDown(self): - """Teardown.""" - pass - - - def test_HTTP_200_OK_GET_ON_ISO88591(self): - r = requests.get("http://www.qypedeals.de/Verzehrgutschein+für+Jellyfish") - self.assertEqual(r.status_code, 200) - self.assertIsInstance(r.content, unicode) - - def test_HTTP_200_OK_GET_ON_BIG5(self): - r = requests.get("http://google.com.hk/") - self.assertEqual(r.status_code, 200) - self.assertIsInstance(r.content, unicode) - - -if __name__ == '__main__': - unittest.main() From a609f726e633018ebd0f11d59d7c63f54945b1be Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:43:36 -0400 Subject: [PATCH 12/62] settings.allow_unicode --- requests/config.py | 1 + requests/models.py | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/requests/config.py b/requests/config.py index 39be2ed4..5a7fcd3f 100644 --- a/requests/config.py +++ b/requests/config.py @@ -62,6 +62,7 @@ settings.proxies = None settings.verbose = None settings.timeout = None settings.max_redirects = 30 +settings.allow_unicode = True #: Use socket.setdefaulttimeout() as fallback? settings.timeout_fallback = True diff --git a/requests/models.py b/requests/models.py index 26436892..d3483149 100644 --- a/requests/models.py +++ b/requests/models.py @@ -453,12 +453,8 @@ class Response(object): pass # Decode unicode content. - try: + if settings.allow_unicode: self._content = get_unicode_from_response(self) - # Don't trust this stuff. - except UserWarning, e: - print e - return self._content From f038ec3b6e9e3dc9ba118eb34f60db295c6a5534 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:44:24 -0400 Subject: [PATCH 13/62] may have multiple encoding values --- requests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/models.py b/requests/models.py index d3483149..8692bbb9 100644 --- a/requests/models.py +++ b/requests/models.py @@ -446,7 +446,7 @@ class Response(object): self._content = self.read() # Decode GZip'd content. - if self.headers.get('content-encoding', '') == 'gzip': + if 'gzip' in self.headers.get('content-encoding', ''): try: self._content = zlib.decompress(self._content, 16+zlib.MAX_WBITS) except zlib.error: From 49066861863495f8e401ea22a25d01b07ccbab0e Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:46:50 -0400 Subject: [PATCH 14/62] utils.decode_gzip --- requests/models.py | 4 ++-- requests/utils.py | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/requests/models.py b/requests/models.py index 8692bbb9..51524608 100644 --- a/requests/models.py +++ b/requests/models.py @@ -21,7 +21,7 @@ from .monkeys import Request as _Request, HTTPBasicAuthHandler, HTTPForcedBasicA from .structures import CaseInsensitiveDict from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers, get_handlers -from .utils import dict_from_cookiejar, get_unicode_from_response +from .utils import dict_from_cookiejar, get_unicode_from_response, decode_gzip from .status_codes import codes from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects @@ -448,7 +448,7 @@ class Response(object): # Decode GZip'd content. if 'gzip' in self.headers.get('content-encoding', ''): try: - self._content = zlib.decompress(self._content, 16+zlib.MAX_WBITS) + self._content = decode_gzip(self._content) except zlib.error: pass diff --git a/requests/utils.py b/requests/utils.py index 72705734..beed3c1f 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -12,6 +12,7 @@ that are also useful for external consumption. import cgi import cookielib import re +import zlib def dict_from_cookiejar(cookiejar): @@ -131,3 +132,9 @@ def get_unicode_from_response(r): return unicode(r.content, encoding, errors='replace') except TypeError: return r.content + + +def decode_gzip(content): + """Return gzip-decoded string.""" + + return zlib.decompress(content, 16+zlib.MAX_WBITS) \ No newline at end of file From c19b2c517256ef2a8cd5915d9d5f44612731881d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:47:43 -0400 Subject: [PATCH 15/62] settings.decode_unicode --- requests/config.py | 2 +- requests/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requests/config.py b/requests/config.py index 5a7fcd3f..794109c5 100644 --- a/requests/config.py +++ b/requests/config.py @@ -62,7 +62,7 @@ settings.proxies = None settings.verbose = None settings.timeout = None settings.max_redirects = 30 -settings.allow_unicode = True +settings.decode_unicode = True #: Use socket.setdefaulttimeout() as fallback? settings.timeout_fallback = True diff --git a/requests/models.py b/requests/models.py index 51524608..db8a60e3 100644 --- a/requests/models.py +++ b/requests/models.py @@ -453,7 +453,7 @@ class Response(object): pass # Decode unicode content. - if settings.allow_unicode: + if settings.decode_unicode: self._content = get_unicode_from_response(self) return self._content From 86cc274cf01e38fd482c9e8be2e4c7f621340468 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:49:23 -0400 Subject: [PATCH 16/62] remote read/close methods from response --- requests/models.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/requests/models.py b/requests/models.py index db8a60e3..12551edc 100644 --- a/requests/models.py +++ b/requests/models.py @@ -186,9 +186,7 @@ class Request(object): try: response.headers = CaseInsensitiveDict(getattr(resp.info(), 'dict', None)) - response.read = resp.read response.fo = resp - response._close = resp.close if self.cookiejar: @@ -443,7 +441,7 @@ class Response(object): return self._content # Read the contents. - self._content = self.read() + self._content = self.fo.read() # Decode GZip'd content. if 'gzip' in self.headers.get('content-encoding', ''): @@ -462,19 +460,12 @@ class Response(object): raise AttributeError - def raise_for_status(self): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occured.""" if self.error: raise self.error - def close(self): - if self.fo.fp is not None and hasattr(self.fo.fp, '_sock'): - self.fo.fp._sock.recv = None - self._close() - - class AuthManager(object): """Requests Authentication Manager.""" From 7f35ec7665de834c012c218df279aa28c68443bd Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:52:18 -0400 Subject: [PATCH 17/62] r.fo bugfix --- requests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/models.py b/requests/models.py index 12551edc..a34a4a4b 100644 --- a/requests/models.py +++ b/requests/models.py @@ -217,7 +217,7 @@ class Request(object): (self.allow_redirects)) ): - r.close() + r.fo.close() if not len(history) < settings.max_redirects: raise TooManyRedirects() From 873d128c5a75bb862a6a857c9a72aa7c916659af Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:58:00 -0400 Subject: [PATCH 18/62] docstrings for utils module --- requests/utils.py | 37 +++++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index beed3c1f..0f6e8428 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -15,12 +15,15 @@ import re import zlib -def dict_from_cookiejar(cookiejar): - """Returns a key/value dictionary from a CookieJar.""" +def dict_from_cookiejar(cj): + """Returns a key/value dictionary from a CookieJar. + + :param cj: CookieJar object to extract cookies from. + """ cookie_dict = {} - for _, cookies in cookiejar._cookies.items(): + for _, cookies in cj._cookies.items(): for _, cookies in cookies.items(): for cookie in cookies.values(): # print cookie @@ -30,7 +33,10 @@ def dict_from_cookiejar(cookiejar): def cookiejar_from_dict(cookie_dict): - """Returns a CookieJar from a key/value dictionary.""" + """Returns a CookieJar from a key/value dictionary. + + :param cookie_dict: Dict of key/values to insert into CookieJar. + """ # return cookiejar if one was passed in if isinstance(cookie_dict, cookielib.CookieJar): @@ -45,7 +51,11 @@ def cookiejar_from_dict(cookie_dict): def add_dict_to_cookiejar(cj, cookie_dict): - """Returns a CookieJar from a key/value dictionary.""" + """Returns a CookieJar from a key/value dictionary. + + :param cj: CookieJar to insert cookies into. + :param cookie_dict: Dict of key/values to insert into CookieJar. + """ for k, v in cookie_dict.items(): @@ -76,7 +86,10 @@ def add_dict_to_cookiejar(cj, cookie_dict): def get_encodings_from_content(content): - """Returns encodings from given content string.""" + """Returns encodings from given content string. + + :param content: bytestring to extract encodings from. + """ charset_re = re.compile(r']', flags=re.I) @@ -85,7 +98,10 @@ def get_encodings_from_content(content): def get_encoding_from_headers(headers): - """Returns encodings from given HTTP Header Dict.""" + """Returns encodings from given HTTP Header Dict. + + :param headers: dictionary to extract encoding from. + """ content_type = headers.get('content-type') content_type, params = cgi.parse_header(content_type) @@ -97,6 +113,8 @@ def get_encoding_from_headers(headers): def get_unicode_from_response(r): """Returns the requested content back in unicode. + :param r: Reponse object to get unicode content from. + Tried: 1. charset from content-type 2. every encodings from @@ -135,6 +153,9 @@ def get_unicode_from_response(r): def decode_gzip(content): - """Return gzip-decoded string.""" + """Return gzip-decoded string. + + :param content: bytestring to gzip-decode. + """ return zlib.decompress(content, 16+zlib.MAX_WBITS) \ No newline at end of file From c5d787d6fd57b3cea6731c2afd5ba9de05cda720 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:59:21 -0400 Subject: [PATCH 19/62] cleanups --- requests/models.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/requests/models.py b/requests/models.py index a34a4a4b..6d27425d 100644 --- a/requests/models.py +++ b/requests/models.py @@ -266,8 +266,8 @@ class Request(object): Otherwise, assumes the data is already encoded appropriately, and returns it twice. - """ + if hasattr(data, 'items'): result = [] for k, vs in data.items(): @@ -375,7 +375,6 @@ class Request(object): self._build_response(why, is_error=True) - else: self._build_response(resp) self.response.ok = True @@ -386,7 +385,6 @@ class Request(object): return self.sent - class Response(object): """The core :class:`Response ` object. All :class:`Request ` objects contain a From d0fdf0eb38da6afaddc8bca88af3fa32fac367cf Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 19:59:41 -0400 Subject: [PATCH 20/62] no longer required --- requests/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requests/models.py b/requests/models.py index 6d27425d..caf809ce 100644 --- a/requests/models.py +++ b/requests/models.py @@ -53,7 +53,7 @@ class Request(object): #: Dictionary of files to multipart upload (``{filename: content}``). self.files = files - #: HTTP Method to use. Available: GET, HEAD, PUT, POST, DELETE. + #: HTTP Method to use. self.method = method #: Dictionary or byte of request body data to attach to the From 13db806861188ae15a5fb23bd39610fdb0aba4f2 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 20:04:11 -0400 Subject: [PATCH 21/62] docstringin' it up --- requests/models.py | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/requests/models.py b/requests/models.py index caf809ce..568ee5a1 100644 --- a/requests/models.py +++ b/requests/models.py @@ -393,31 +393,46 @@ class Response(object): """ def __init__(self): - #: Raw content of the response, in bytes. + #: Content of the response, in bytes or unicode (if available). #: If ``content-encoding`` of response was set to ``gzip``, the #: response data will be automatically deflated. - self._content = None + self.content = None + + # Hack for Sphinx. + del self.content + #: Integer Code of responded HTTP Status. self.status_code = None #: Case-insensitive Dictionary of Response Headers. #: For example, ``headers['content-encoding']`` will return the #: value of a ``'Content-Encoding'`` response header. self.headers = CaseInsensitiveDict() + + #: File-like object representation of response (for advanced usage). + self.fo = None + #: Final URL location of Response. self.url = None + #: True if no :attr:`error` occured. self.ok = False + #: Resulting :class:`HTTPError` of request, if one occured. self.error = None + #: A list of :class:`Response ` objects from #: the history of the Request. Any redirect responses will end #: up here. self.history = [] + #: The Request that created the Response. self.request = None + #: A dictionary of Cookies the server sent back. self.cookies = None + self._content = None + def __repr__(self): return '' % (self.status_code) From 1f3e53b32ec603c8859dacc2dbe17b875fcd2fe3 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 20:05:38 -0400 Subject: [PATCH 22/62] yay --- requests/models.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/requests/models.py b/requests/models.py index 568ee5a1..2ca2c75c 100644 --- a/requests/models.py +++ b/requests/models.py @@ -394,8 +394,6 @@ class Response(object): def __init__(self): #: Content of the response, in bytes or unicode (if available). - #: If ``content-encoding`` of response was set to ``gzip``, the - #: response data will be automatically deflated. self.content = None # Hack for Sphinx. @@ -403,6 +401,7 @@ class Response(object): #: Integer Code of responded HTTP Status. self.status_code = None + #: Case-insensitive Dictionary of Response Headers. #: For example, ``headers['content-encoding']`` will return the #: value of a ``'Content-Encoding'`` response header. From 596aceb185c3ca013e83db70eeeff3014d8e3a40 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 22:47:03 -0400 Subject: [PATCH 23/62] big docs update --- docs/api.rst | 56 +++++++++++++++++++++++++++++-------- requests/api.py | 70 +++++++++++----------------------------------- requests/core.py | 6 ++-- requests/models.py | 26 ++++++++--------- requests/utils.py | 6 +++- 5 files changed, 82 insertions(+), 82 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index cbd24fdb..e3338b66 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -13,34 +13,48 @@ important right here and provide links to the canonical documentation. Main Interface -------------- -All of Request's functionality can be accessed by these 6 methods. They -all return a :class:`Response ` object. +All of Request's functionality can be accessed by these 7 methods. +They all return an instance of the :class:`Response ` object. +.. autofunction:: request .. autofunction:: head .. autofunction:: get .. autofunction:: post .. autofunction:: put .. autofunction:: patch .. autofunction:: delete -.. autofunction:: request + ----------- -.. autoclass:: requests.models.Response +.. autoclass:: Response :inherited-members: -Exceptions ----------- -.. autoexception:: HTTPError +Utilities +--------- -.. autoexception:: RequestException +These functions are used internally, but may be useful outside of +Requests. -.. autoexception:: requests.models.AuthenticationError -.. autoexception:: requests.models.URLRequired -.. autoexception:: requests.models.InvalidMethod +.. module:: requests.utils + +Cookies +~~~~~~~ + +.. autofunction:: dict_from_cookiejar +.. autofunction:: cookiejar_from_dict +.. autofunction:: add_dict_to_cookiejar + +Encodings +~~~~~~~~~ + +.. autofunction:: get_encodings_from_content +.. autofunction:: get_encoding_from_headers +.. autofunction:: get_unicode_from_response +.. autofunction:: decode_gzip Internals @@ -50,8 +64,26 @@ These items are an internal component to Requests, and should never be seen by the end user (developer). This part of the API documentation exists for those who are extending the functionality of Requests. +Exceptions +~~~~~~~~~~ + +.. module:: requests + +.. autoexception:: HTTPError + +.. autoexception:: RequestException + +.. autoexception:: AuthenticationError +.. autoexception:: URLRequired +.. autoexception:: InvalidMethod +.. autoexception:: TooManyRedirects + + + Classes ~~~~~~~ -.. autoclass:: requests.models.Request +.. autoclass:: requests.Request :inherited-members: + + diff --git a/requests/api.py b/requests/api.py index 0cea63d4..5ded386c 100644 --- a/requests/api.py +++ b/requests/api.py @@ -25,8 +25,8 @@ def request(method, url, params=None, data=None, headers=None, cookies=None, files=None, auth=None, timeout=None, allow_redirects=False, proxies=None, hooks=None): - """Constructs and sends a :class:`Request `. - Returns :class:`Response ` object. + """Constructs and sends a :class:`Request `. + Returns :class:`Response ` object. :param method: method for the new :class:`Request` object. :param url: URL for the new :class:`Request` object. @@ -41,6 +41,8 @@ def request(method, url, :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. """ + method = method.upper() + if cookies is None: cookies = {} @@ -85,50 +87,31 @@ def get(url, **kwargs): """Sends a GET request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('GET', url, **kwargs) + return request('get', url, **kwargs) def head(url, **kwargs): - """Sends a HEAD request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('HEAD', url, **kwargs) + return request('head', url, **kwargs) def post(url, data='', **kwargs): - """Sends a POST request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to True if redirect following is allowed. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('POST', url, data=data, **kwargs) + return request('post', url, data=data, **kwargs) def put(url, data='', **kwargs): @@ -136,17 +119,10 @@ def put(url, data='', **kwargs): :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to True if redirect following is allowed. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('PUT', url, data=data, **kwargs) + return request('put', url, data=data, **kwargs) def patch(url, data='', **kwargs): @@ -154,31 +130,17 @@ def patch(url, data='', **kwargs): :param url: URL for the new :class:`Request` object. :param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param files: (optional) Dictionary of 'filename': file-like-objects for multipart encoding upload. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to True if redirect following is allowed. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('PATCH', url, **kwargs) + return request('patch', url, **kwargs) def delete(url, **kwargs): - """Sends a DELETE request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to True if redirect following is allowed. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param **kwargs: Optional arguments that ``request`` takes. """ - return request('DELETE', url, **kwargs) + return request('delete', url, **kwargs) diff --git a/requests/core.py b/requests/core.py index 8ba34a2f..c4366647 100644 --- a/requests/core.py +++ b/requests/core.py @@ -19,9 +19,11 @@ __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' -from models import HTTPError +from models import HTTPError, Request, Response from api import * from exceptions import * from sessions import session from status_codes import codes -from config import settings \ No newline at end of file +from config import settings + +import utils \ No newline at end of file diff --git a/requests/models.py b/requests/models.py index 2ca2c75c..92335181 100644 --- a/requests/models.py +++ b/requests/models.py @@ -31,7 +31,7 @@ REDIRECT_STATI = (codes.moved, codes.found, codes.other, codes.temporary_moved) class Request(object): - """The :class:`Request ` object. It carries out all functionality of + """The :class:`Request ` object. It carries out all functionality of Requests. Recommended interface is with the Requests functions. """ @@ -47,7 +47,7 @@ class Request(object): #: Request URL. self.url = url - #: Dictonary of HTTP Headers to attach to the :class:`Request `. + #: Dictonary of HTTP Headers to attach to the :class:`Request `. self.headers = headers #: Dictionary of files to multipart upload (``{filename: content}``). @@ -57,14 +57,14 @@ class Request(object): self.method = method #: Dictionary or byte of request body data to attach to the - #: :class:`Request `. + #: :class:`Request `. self.data = None #: Dictionary or byte of querystring data to attach to the - #: :class:`Request `. + #: :class:`Request `. self.params = None - #: True if :class:`Request ` is part of a redirect chain (disables history + #: True if :class:`Request ` is part of a redirect chain (disables history #: and HTTPError storage). self.redirect = redirect @@ -77,7 +77,7 @@ class Request(object): self.data, self._enc_data = self._encode_params(data) self.params, self._enc_params = self._encode_params(params) - #: :class:`Response ` instance, containing + #: :class:`Response ` instance, containing #: content and metadata of HTTP Response, once :attr:`sent `. self.response = Response() @@ -86,10 +86,10 @@ class Request(object): if not auth: auth = auth_manager.get_auth(self.url) - #: :class:`AuthObject` to attach to :class:`Request `. + #: :class:`AuthObject` to attach to :class:`Request `. self.auth = auth - #: CookieJar to attach to :class:`Request `. + #: CookieJar to attach to :class:`Request `. self.cookiejar = cookiejar #: True if Request has been sent. @@ -174,7 +174,7 @@ class Request(object): def _build_response(self, resp, is_error=False): - """Build internal :class:`Response ` object + """Build internal :class:`Response ` object from given response. """ @@ -386,9 +386,9 @@ class Request(object): class Response(object): - """The core :class:`Response ` object. All - :class:`Request ` objects contain a - :class:`response ` attribute, which is an instance + """The core :class:`Response ` object. All + :class:`Request ` objects contain a + :class:`response ` attribute, which is an instance of this class. """ @@ -419,7 +419,7 @@ class Response(object): #: Resulting :class:`HTTPError` of request, if one occured. self.error = None - #: A list of :class:`Response ` objects from + #: A list of :class:`Response ` objects from #: the history of the Request. Any redirect responses will end #: up here. self.history = [] diff --git a/requests/utils.py b/requests/utils.py index 0f6e8428..d96310b4 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -116,9 +116,13 @@ def get_unicode_from_response(r): :param r: Reponse object to get unicode content from. Tried: + 1. charset from content-type - 2. every encodings from + + 2. every encodings from ```` + 3. fall back and replace all unicode characters + """ tried_encodings = [] From 28ee9788a071ac1314ed920ab5cb4af74ceee307 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 22:51:24 -0400 Subject: [PATCH 24/62] Request --- requests/api.py | 2 +- requests/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requests/api.py b/requests/api.py index 5ded386c..0928d8c8 100644 --- a/requests/api.py +++ b/requests/api.py @@ -41,7 +41,7 @@ def request(method, url, :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. """ - method = method.upper() + method = str(method).upper() if cookies is None: cookies = {} diff --git a/requests/models.py b/requests/models.py index 92335181..41214816 100644 --- a/requests/models.py +++ b/requests/models.py @@ -424,7 +424,7 @@ class Response(object): #: up here. self.history = [] - #: The Request that created the Response. + #: The :class:`Request ` that created the Response. self.request = None #: A dictionary of Cookies the server sent back. From b45b329861ed77c264df4271e38771eec6238e64 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 22:55:30 -0400 Subject: [PATCH 25/62] history --- HISTORY.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HISTORY.rst b/HISTORY.rst index b09392b5..33d56b93 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,6 +1,11 @@ History ------- +* Automatic decoding of unicode, when available. +* New ``decode_unicode`` setting +* Removal of ``r.read/close`` methods +* New ``r.fo`` interface for advanced response usage. + 0.6.1 (2011-08-20) ++++++++++++++++++ From d4bdd84364b602624096b1407c5d10936c6c9068 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sat, 20 Aug 2011 23:00:17 -0400 Subject: [PATCH 26/62] new FAQs --- docs/community/faq.rst | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/community/faq.rst b/docs/community/faq.rst index b5717648..7b49725d 100644 --- a/docs/community/faq.rst +++ b/docs/community/faq.rst @@ -5,6 +5,21 @@ Frequently Asked Questions This part of the documentation covers common questions about Requests. +Encoded Data? +------------- + +Requests automatically decompresses GZip'ed responses, and decodes +response conten tinto unicode when encoding information is available. + + +Custom User-Agents? +------------------- + +Requests allows you to easily override User-Agent strings, along with +any other HTTP Header. + + + Why not Httplib2? ----------------- @@ -40,4 +55,11 @@ It's on the way. Here's a list of `supported interpreters `_. Keep-alive Support? ------------------- -It's on the way. \ No newline at end of file +It's on the way. + + +Proxy Support? +-------------- + +You bet! + From 6a96652396515631bb72ba7c363e96c27edd769a Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Sun, 21 Aug 2011 11:57:03 +0300 Subject: [PATCH 27/62] Refactor response.content into a property. This makes content attribute discoverable through dir(response) and also guards from errors like forgetting to raise AttributeError in __getattr__. Also you don't have to create fake self.content to fool Sphinx any more. --- requests/models.py | 56 +++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/requests/models.py b/requests/models.py index 41214816..03b853c8 100644 --- a/requests/models.py +++ b/requests/models.py @@ -396,9 +396,6 @@ class Response(object): #: Content of the response, in bytes or unicode (if available). self.content = None - # Hack for Sphinx. - del self.content - #: Integer Code of responded HTTP Status. self.status_code = None @@ -430,8 +427,6 @@ class Response(object): #: A dictionary of Cookies the server sent back. self.cookies = None - self._content = None - def __repr__(self): return '' % (self.status_code) @@ -443,33 +438,34 @@ class Response(object): return not self.error - def __getattr__(self, name): - """Read and returns the full stream when accessing to - :attr: `content` - """ - - if name == 'content': - if self._content is not None: - return self._content - - # Read the contents. - self._content = self.fo.read() - - # Decode GZip'd content. - if 'gzip' in self.headers.get('content-encoding', ''): - try: - self._content = decode_gzip(self._content) - except zlib.error: - pass - - # Decode unicode content. - if settings.decode_unicode: - self._content = get_unicode_from_response(self) - + @property + def content(self): + """Content of the response, in bytes or unicode + (if available).""" + + if self._content is not None: return self._content - else: - raise AttributeError + # Read the contents. + self._content = self.fo.read() + + # Decode GZip'd content. + if 'gzip' in self.headers.get('content-encoding', ''): + try: + self._content = decode_gzip(self._content) + except zlib.error: + pass + + # Decode unicode content. + if settings.decode_unicode: + self._content = get_unicode_from_response(self) + + return self._content + + + @content.setter + def content(self, value): + self._content = value def raise_for_status(self): From 8d5108b142dd8d9de27559ee8364967b13f2b62a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 21 Aug 2011 06:58:34 -0400 Subject: [PATCH 28/62] faq --- docs/community/faq.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/community/faq.rst b/docs/community/faq.rst index 7b49725d..b0921956 100644 --- a/docs/community/faq.rst +++ b/docs/community/faq.rst @@ -3,13 +3,16 @@ Frequently Asked Questions ========================== -This part of the documentation covers common questions about Requests. +This part of the documentation answers common questions about Requests. Encoded Data? ------------- -Requests automatically decompresses GZip'ed responses, and decodes -response conten tinto unicode when encoding information is available. +Requests automatically decompresses gzip-encoded responses, and does +it's best to decodes response content to unicode when possible. + +You can get direct access to the raw reasponse (and even the socket), +if needed as well. Custom User-Agents? From 1143d4237f5e433a6181e6f7e1abcb1e7031120a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 21 Aug 2011 06:59:13 -0400 Subject: [PATCH 29/62] AUTHORS += 'Den Shabalin' --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f79dd801..76c24373 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,3 +41,4 @@ Patches and Suggestions - Den Shabalin - Alejandro Giacometti - Rick Mak +- Den Shabalin \ No newline at end of file From c8110222a532821d27b0ade3ebdd7d0cb9545f80 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 21 Aug 2011 07:01:29 -0400 Subject: [PATCH 30/62] no need to set content avoids 2.5 workaround --- requests/models.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/requests/models.py b/requests/models.py index 03b853c8..262a564d 100644 --- a/requests/models.py +++ b/requests/models.py @@ -442,7 +442,7 @@ class Response(object): def content(self): """Content of the response, in bytes or unicode (if available).""" - + if self._content is not None: return self._content @@ -463,11 +463,6 @@ class Response(object): return self._content - @content.setter - def content(self, value): - self._content = value - - def raise_for_status(self): """Raises stored :class:`HTTPError` or :class:`URLError`, if one occured.""" if self.error: From a86af4477ec377223c10ddd6bf2fe90f508e1b60 Mon Sep 17 00:00:00 2001 From: Den Shabalin Date: Sun, 21 Aug 2011 14:09:03 +0300 Subject: [PATCH 31/62] AUTHORS -= Den Shabalin (I've already been mentioned in the list @ line 41.) --- AUTHORS | 1 - 1 file changed, 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 76c24373..f79dd801 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,4 +41,3 @@ Patches and Suggestions - Den Shabalin - Alejandro Giacometti - Rick Mak -- Den Shabalin \ No newline at end of file From 317c5b693a16e5e638d9253dd2913d93f5389e00 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 21 Aug 2011 07:12:54 -0400 Subject: [PATCH 32/62] _content --- requests/models.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/requests/models.py b/requests/models.py index 262a564d..5983c237 100644 --- a/requests/models.py +++ b/requests/models.py @@ -393,8 +393,8 @@ class Response(object): """ def __init__(self): - #: Content of the response, in bytes or unicode (if available). - self.content = None + + self._content = None #: Integer Code of responded HTTP Status. self.status_code = None @@ -441,7 +441,8 @@ class Response(object): @property def content(self): """Content of the response, in bytes or unicode - (if available).""" + (if available). + """ if self._content is not None: return self._content From e8dbecb4dbed3e835021977cf43f225a76bc5ec3 Mon Sep 17 00:00:00 2001 From: jbergstroem Date: Tue, 23 Aug 2011 11:29:36 +0200 Subject: [PATCH 33/62] Add test_requests.py to manifest --- MANIFEST.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 94c50f70..39fbb994 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1 @@ -include README.rst LICENSE HISTORY.rst \ No newline at end of file +include README.rst LICENSE HISTORY.rst test_requests.py From 75027f9557e61f2416af1794a269758604a7454c Mon Sep 17 00:00:00 2001 From: jbergstroem Date: Tue, 23 Aug 2011 11:37:51 +0200 Subject: [PATCH 34/62] Typos, nits and some 80w fixes --- docs/community/faq.rst | 3 +-- docs/community/updates.rst | 1 - docs/user/advanced.rst | 4 ++-- docs/user/install.rst | 9 ++++++--- docs/user/intro.rst | 12 +++++++++--- docs/user/quickstart.rst | 12 ++++++++---- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/docs/community/faq.rst b/docs/community/faq.rst index b0921956..b6efc786 100644 --- a/docs/community/faq.rst +++ b/docs/community/faq.rst @@ -11,7 +11,7 @@ Encoded Data? Requests automatically decompresses gzip-encoded responses, and does it's best to decodes response content to unicode when possible. -You can get direct access to the raw reasponse (and even the socket), +You can get direct access to the raw response (and even the socket), if needed as well. @@ -22,7 +22,6 @@ Requests allows you to easily override User-Agent strings, along with any other HTTP Header. - Why not Httplib2? ----------------- diff --git a/docs/community/updates.rst b/docs/community/updates.rst index 942ccac1..e6e1559f 100644 --- a/docs/community/updates.rst +++ b/docs/community/updates.rst @@ -20,7 +20,6 @@ I often tweet about new features and releases of Requests. Follow `@kennethreitz `_ for updates. - Mailing List ------------ diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst index d145da21..ae7827c9 100644 --- a/docs/user/advanced.rst +++ b/docs/user/advanced.rst @@ -66,7 +66,7 @@ Available hooks: You can assign a hook function on a per-request basis by passing a ``{hook_name: callback_function}`` dictionary to the ``hooks`` request -paramaeter:: +parameter:: hooks=dict(args=print_url) @@ -134,4 +134,4 @@ To do so, just configure Requests with a stream to write to:: >>> requests.settings.verbose = sys.stderr >>> requests.get('http://httpbin.org/headers') 2011-08-17T03:04:23.380175 GET http://httpbin.org/headers - \ No newline at end of file + diff --git a/docs/user/install.rst b/docs/user/install.rst index cdc6d86c..dc4aa627 100644 --- a/docs/user/install.rst +++ b/docs/user/install.rst @@ -3,7 +3,8 @@ Installation ============ -This part of the documentation covers the installation of Requests. The first step to using any software package is getting it properly installed. +This part of the documentation covers the installation of Requests. +The first step to using any software package is getting it properly installed. Distribute & Pip @@ -24,7 +25,8 @@ But, you really `shouldn't do that `_:: +If the Cheeseshop is down, you can also install Requests from Kenneth Reitz's +personal `Cheeseshop mirror `_:: $ pip install -i http://pip.kreitz.co/simple requests @@ -48,6 +50,7 @@ Or, download the `zipball ` section. +Eager to get started? This page gives a good introduction in how to get started +with Requests. This assumes you already have Requests installed. If you do not, +head over to the :ref:`Installation ` section. First, make sure that: @@ -25,7 +27,8 @@ Let's get GitHub's public timeline :: r = requests.get('https://github.com/timeline.json') -Now, we have a :class:`Response` object called ``r``. We can get all the information we need from this. +Now, we have a :class:`Response` object called ``r``. We can get all the +information we need from this. Response Content @@ -90,7 +93,8 @@ interface:: 'content-type': 'application/json; charset=utf-8' } -The dictionary is special, though: it's made just for HTTP headers. According to `RFC 2616 `_, HTTP +The dictionary is special, though: it's made just for HTTP headers. According to +`RFC 2616 `_, HTTP Headers are case-insensitive. So, we can access the headers using any capitalization we want:: @@ -118,7 +122,7 @@ If a response contains some Cookies, you can get quick access to them:: >>> print r.cookies {'requests-is': 'awesome'} -The underlying CookieJar is also available for more advanced handing:: +The underlying CookieJar is also available for more advanced handling:: >>> r.request.cookiejar From 281aa5ebc49520374707035343b74a5263ede5bf Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 23 Aug 2011 23:01:23 -0400 Subject: [PATCH 35/62] updated AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f79dd801..1eabf651 100644 --- a/AUTHORS +++ b/AUTHORS @@ -41,3 +41,4 @@ Patches and Suggestions - Den Shabalin - Alejandro Giacometti - Rick Mak +- Johan Bergström From ce3b85a62ee2bd12463aa2937a6b66a5a5e35a2d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 23 Aug 2011 23:01:35 -0400 Subject: [PATCH 36/62] unsuccessful --- requests/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/requests/models.py b/requests/models.py index 5983c237..5ff9eb48 100644 --- a/requests/models.py +++ b/requests/models.py @@ -311,7 +311,6 @@ class Request(object): """ self._checks() - success = False # Logging if settings.verbose: From a94541d38c8883457195a1a388c56172fc2df745 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 23 Aug 2011 23:03:18 -0400 Subject: [PATCH 37/62] Only decode unicode from http headers HTTP client, not HTML #115 --- requests/utils.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index d96310b4..8a419acb 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -132,23 +132,10 @@ def get_unicode_from_response(r): if encoding: try: - print '!' return unicode(r.content, encoding) except UnicodeError: tried_encodings.append(encoding) - # Try every encodings from - encodings = get_encodings_from_content(r.content) - - for encoding in encodings: - if encoding in tried_encodings: - continue - try: - - return unicode(r.content, encoding) - except (UnicodeError, TypeError): - tried_encodings.append(encoding) - # Fall back: try: return unicode(r.content, encoding, errors='replace') From 636e61d68b9176c614f8243295c81552dd0ee199 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 23 Aug 2011 23:09:09 -0400 Subject: [PATCH 38/62] utils.unicode_from_html --- requests/utils.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/requests/utils.py b/requests/utils.py index 8a419acb..35eb005b 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -110,6 +110,25 @@ def get_encoding_from_headers(headers): return params['charset'].strip("'\"") +def unicode_from_html(content): + """Attempts to decode an HTML string into unicode. + If unsuccessful, the original content is returned. + """ + + encodings = get_encodings_from_content(content) + + for encoding in encodings: + + try: + return unicode(content, encoding) + except (UnicodeError, TypeError): + pass + + return content + + + + def get_unicode_from_response(r): """Returns the requested content back in unicode. From 1d0a5b2665ce73dac5f27f9f698f451ca3812579 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 23 Aug 2011 23:09:51 -0400 Subject: [PATCH 39/62] whitespace --- requests/utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index 35eb005b..2b55a164 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -96,7 +96,6 @@ def get_encodings_from_content(content): return charset_re.findall(content) - def get_encoding_from_headers(headers): """Returns encodings from given HTTP Header Dict. @@ -124,9 +123,7 @@ def unicode_from_html(content): except (UnicodeError, TypeError): pass - return content - - + return content def get_unicode_from_response(r): From b97b4439c0ab264d36a2fbc1af07c0631bca2fbe Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 02:40:19 -0400 Subject: [PATCH 40/62] header expanding --- requests/utils.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/requests/utils.py b/requests/utils.py index 2b55a164..89387576 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -15,6 +15,36 @@ import re import zlib +def header_expand(header_dict): + """Returns an HTTP Header value string from a dictionary. + + Example expansion:: + + # Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c + {'text/x-dvi': {'q': '.8', 'mxb': '100000', 'mxt': '5.0'}, 'text/x-c': {}} + """ + + collector = [] + + for i, (value, params) in enumerate(header_dict.items()): + _params = [] + + for p_k, p_v in params.items(): + + _params.append('{k}={v}'.format(k=p_k, v=p_v)) + + if len(params): + collector.append(value) + collector.append('; ') + collector.append('; '.join(_params)) + + if not len(header_dict) == i+1: + collector.append(', ') + + return ''.join(collector) + + + def dict_from_cookiejar(cj): """Returns a key/value dictionary from a CookieJar. From e272ec13c36fa83f4e14d8bfc7a3b63ab7cd08b2 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:07:45 -0400 Subject: [PATCH 41/62] tuples too --- requests/utils.py | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index 89387576..10625693 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -15,32 +15,49 @@ import re import zlib -def header_expand(header_dict): +def header_expand(headers): """Returns an HTTP Header value string from a dictionary. Example expansion:: - # Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c {'text/x-dvi': {'q': '.8', 'mxb': '100000', 'mxt': '5.0'}, 'text/x-c': {}} + # Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c + + (('text/x-dvi', {'q': '.8', 'mxb': '100000', 'mxt': '5.0'}), ('text/x-c', {})) + # Accept: text/x-dvi; q=.8; mxb=100000; mxt=5.0, text/x-c """ collector = [] - for i, (value, params) in enumerate(header_dict.items()): + if isinstance(headers, dict): + + # Assume header-tuple + headers = headers.items() + + # print headers + + for i, (value, params) in enumerate(headers): + _params = [] - for p_k, p_v in params.items(): + for (p_k, p_v) in params.items(): - _params.append('{k}={v}'.format(k=p_k, v=p_v)) + _params.append('%s=%s' % (p_k, p_v)) + + collector.append(value) + collector.append('; ') if len(params): - collector.append(value) - collector.append('; ') + collector.append('; '.join(_params)) - if not len(header_dict) == i+1: + if not len(headers) == i+1: collector.append(', ') + + if collector[-1] in (', ', '; '): + del collector[-1] + return ''.join(collector) From 3b9fc987b86fc536f1ad6a91c6c12e31ba4dcf91 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:09:26 -0400 Subject: [PATCH 42/62] cleanup --- requests/utils.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/requests/utils.py b/requests/utils.py index 10625693..25168400 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -30,12 +30,8 @@ def header_expand(headers): collector = [] if isinstance(headers, dict): - - # Assume header-tuple headers = headers.items() - # print headers - for i, (value, params) in enumerate(headers): _params = [] @@ -55,6 +51,7 @@ def header_expand(headers): collector.append(', ') + # Remove trailing seperators. if collector[-1] in (', ', '; '): del collector[-1] From 2fa180e9ea63b4b2a8992b5d750fe7b5f650b006 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:22:03 -0400 Subject: [PATCH 43/62] automatic header expansion --- requests/api.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/requests/api.py b/requests/api.py index 0928d8c8..8f8d6ea0 100644 --- a/requests/api.py +++ b/requests/api.py @@ -15,7 +15,7 @@ import config from .models import Request, Response, AuthObject from .status_codes import codes from .hooks import dispatch_hook -from .utils import cookiejar_from_dict +from .utils import cookiejar_from_dict, header_expand from urlparse import urlparse @@ -48,6 +48,14 @@ def request(method, url, cookies = cookiejar_from_dict(cookies) + # Expand header values + if headers: + for k, v in headers.items() or {}: + headers[k] = header_expand(v) + + # headers = [(k, map(header_expand, v)) for k,v in headers.items()] + # print headers + args = dict( method = method, url = url, From dba7a5a7e20d0dd2a8781c7b2a79eb50c9a60e0a Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:22:20 -0400 Subject: [PATCH 44/62] shortcut strings --- requests/utils.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/requests/utils.py b/requests/utils.py index 25168400..8db2cb55 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -32,6 +32,9 @@ def header_expand(headers): if isinstance(headers, dict): headers = headers.items() + elif isinstance(headers, basestring): + return headers + for i, (value, params) in enumerate(headers): _params = [] From 35fc3b4dbb6c0b87f97c183dfae14289eb87d60d Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:22:46 -0400 Subject: [PATCH 45/62] cleanup --- requests/api.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/requests/api.py b/requests/api.py index 8f8d6ea0..cd522c29 100644 --- a/requests/api.py +++ b/requests/api.py @@ -53,9 +53,6 @@ def request(method, url, for k, v in headers.items() or {}: headers[k] = header_expand(v) - # headers = [(k, map(header_expand, v)) for k,v in headers.items()] - # print headers - args = dict( method = method, url = url, From fed17cb58a23853731a322d0178217dc77f83ce0 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Sun, 28 Aug 2011 03:23:54 -0400 Subject: [PATCH 46/62] history --- HISTORY.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 33d56b93..6fcd8f15 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,11 +1,11 @@ History ------- -* Automatic decoding of unicode, when available. +* Automatic decoding of unicode, based on HTTP Headers. * New ``decode_unicode`` setting * Removal of ``r.read/close`` methods -* New ``r.fo`` interface for advanced response usage. - +* New ``r.fo`` interface for advanced response usage.* +* Automatic expansion of parameterized headers 0.6.1 (2011-08-20) ++++++++++++++++++ From 1ecb593c7be7d6465cf61356f3bdada3849b84fd Mon Sep 17 00:00:00 2001 From: Josselin Jacquard Date: Tue, 30 Aug 2011 12:04:48 +0200 Subject: [PATCH 47/62] Fix a bug when content-type is empty --- requests/utils.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/requests/utils.py b/requests/utils.py index 8db2cb55..d21966cd 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -150,6 +150,8 @@ def get_encoding_from_headers(headers): """ content_type = headers.get('content-type') + if not content_type : + return content_type, params = cgi.parse_header(content_type) if 'charset' in params: From 6d25fff3f93eb89a87742bf3be24fa87724fe550 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Tue, 30 Aug 2011 23:58:31 -0400 Subject: [PATCH 48/62] Added Josselin Jacquard to AUTHORS --- AUTHORS | 1 + requests/utils.py | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index 1eabf651..8497a09c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -42,3 +42,4 @@ Patches and Suggestions - Alejandro Giacometti - Rick Mak - Johan Bergström +- Josselin Jacquard diff --git a/requests/utils.py b/requests/utils.py index d21966cd..27423ee6 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -150,8 +150,10 @@ def get_encoding_from_headers(headers): """ content_type = headers.get('content-type') - if not content_type : - return + + if not content_type: + return None + content_type, params = cgi.parse_header(content_type) if 'charset' in params: From 6f84ce72f28a58afa782db585a86aa10632447df Mon Sep 17 00:00:00 2001 From: verm666 Date: Mon, 29 Aug 2011 20:01:27 +0400 Subject: [PATCH 49/62] Fixed logic for auto redirect in GET and HEAD methods. --- requests/api.py | 6 ++++++ requests/models.py | 3 +-- test_requests.py | 7 +++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/requests/api.py b/requests/api.py index cd522c29..102bc756 100644 --- a/requests/api.py +++ b/requests/api.py @@ -95,6 +95,9 @@ def get(url, **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ + if "allow_redirects" not in kwargs: + kwargs["allow_redirects"] = True + return request('get', url, **kwargs) @@ -105,6 +108,9 @@ def head(url, **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ + if "allow_redirects" not in kwargs: + kwargs["allow_redirects"] = True + return request('head', url, **kwargs) diff --git a/requests/models.py b/requests/models.py index 5ff9eb48..a951ab9e 100644 --- a/requests/models.py +++ b/requests/models.py @@ -212,8 +212,7 @@ class Request(object): while ( ('location' in r.headers) and - ((self.method in ('GET', 'HEAD')) or - (r.status_code is codes.see_other) or + ((r.status_code is codes.see_other) or (self.allow_redirects)) ): diff --git a/test_requests.py b/test_requests.py index dd923471..e3db01d8 100755 --- a/test_requests.py +++ b/test_requests.py @@ -60,6 +60,13 @@ class RequestsTestSuite(unittest.TestCase): r = requests.get(httpbin('/')) self.assertEqual(r.status_code, 200) + def test_HTTP_302_ALLOW_REDIRECT_GET(self): + r = requests.get(httpbin('redirect', '1')) + self.assertEqual(r.status_code, 200) + + def test_HTTP_302_GET(self): + r = requests.get(httpbin('redirect', '1'), allow_redirects=False) + self.assertEqual(r.status_code, 302) def test_HTTPS_200_OK_GET(self): r = requests.get(httpsbin('/')) From 41876fd8c6b7146026acfe58b18ceeb21aed3069 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 3 Sep 2011 17:59:30 +0200 Subject: [PATCH 50/62] Implemented content streaming for responses. --- requests/models.py | 34 +++++++++++++++++++++++++++++++++- requests/utils.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/requests/models.py b/requests/models.py index a951ab9e..9a7c57d0 100644 --- a/requests/models.py +++ b/requests/models.py @@ -9,6 +9,7 @@ requests.models import urllib import urllib2 import socket +import codecs import zlib @@ -21,7 +22,7 @@ from .monkeys import Request as _Request, HTTPBasicAuthHandler, HTTPForcedBasicA from .structures import CaseInsensitiveDict from .packages.poster.encode import multipart_encode from .packages.poster.streaminghttp import register_openers, get_handlers -from .utils import dict_from_cookiejar, get_unicode_from_response, decode_gzip +from .utils import dict_from_cookiejar, get_unicode_from_response, stream_decode_response_unicode, decode_gzip, stream_decode_gzip from .status_codes import codes from .exceptions import RequestException, AuthenticationError, Timeout, URLRequired, InvalidMethod, TooManyRedirects @@ -393,6 +394,7 @@ class Response(object): def __init__(self): self._content = None + self._content_consumed = False #: Integer Code of responded HTTP Status. self.status_code = None @@ -435,6 +437,31 @@ class Response(object): return not self.error + def iter_content(self, chunk_size=10 * 1024, decode_unicode=None): + """Iterates over the response data. This avoids reading the content + at once into memory for large responses. The chunk size is the number + of bytes it should read into memory. This is not necessarily the + length of each item returned as decoding can take place. + """ + if self._content_consumed: + raise RuntimeError('The content for this response was ' + 'already consumed') + + def generate(): + while 1: + chunk = self.fo.read(chunk_size) + if not chunk: + break + yield chunk + self._content_consumed = True + gen = generate() + if 'gzip' in self.headers.get('content-encoding', ''): + gen = stream_decode_gzip(gen) + if decode_unicode is None: + decode_unicode = settings.decode_unicode + if decode_unicode: + gen = stream_decode_response_unicode(gen, self) + return gen @property def content(self): @@ -445,6 +472,10 @@ class Response(object): if self._content is not None: return self._content + if self._content_consumed: + raise RuntimeError('The content for this response was ' + 'already consumed') + # Read the contents. self._content = self.fo.read() @@ -459,6 +490,7 @@ class Response(object): if settings.decode_unicode: self._content = get_unicode_from_response(self) + self._content_consumed = True return self._content diff --git a/requests/utils.py b/requests/utils.py index 27423ee6..a9b4c75a 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -10,6 +10,7 @@ that are also useful for external consumption. """ import cgi +import codecs import cookielib import re import zlib @@ -177,6 +178,19 @@ def unicode_from_html(content): return content +def stream_decode_response_unicode(iterator, r): + """Stream decodes a iterator.""" + encoding = get_encoding_from_headers(r.headers) + decoder = codecs.getincrementaldecoder(encoding)(errors='replace') + for chunk in iterator: + rv = decoder.decode(chunk) + if rv: + yield rv + rv = decoder.decode('', final=True) + if rv: + yield rv + + def get_unicode_from_response(r): """Returns the requested content back in unicode. @@ -216,4 +230,20 @@ def decode_gzip(content): :param content: bytestring to gzip-decode. """ - return zlib.decompress(content, 16+zlib.MAX_WBITS) \ No newline at end of file + return zlib.decompress(content, 16 + zlib.MAX_WBITS) + + +def stream_decode_gzip(iterator): + """Stream decodes a gzip-encoded iterator""" + try: + dec = zlib.decompressobj(16 + zlib.MAX_WBITS) + for chunk in iterator: + rv = dec.decompress(chunk) + if rv: + yield rv + buf = dec.decompress('') + rv = buf + dec.flush() + if rv: + yield rv + except zlib.error: + pass From 0d6773c68ca04cc90c004cb3a98313dd035c5e22 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Sat, 3 Sep 2011 18:04:51 +0200 Subject: [PATCH 51/62] Fail silently if encoding header is missing --- requests/utils.py | 5 +++++ test_requests.py | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/requests/utils.py b/requests/utils.py index a9b4c75a..2e16163b 100644 --- a/requests/utils.py +++ b/requests/utils.py @@ -181,6 +181,11 @@ def unicode_from_html(content): def stream_decode_response_unicode(iterator, r): """Stream decodes a iterator.""" encoding = get_encoding_from_headers(r.headers) + if encoding is None: + for item in iterator: + yield item + return + decoder = codecs.getincrementaldecoder(encoding)(errors='replace') for chunk in iterator: rv = decoder.decode(chunk) diff --git a/test_requests.py b/test_requests.py index e3db01d8..2b2d50b7 100755 --- a/test_requests.py +++ b/test_requests.py @@ -477,6 +477,5 @@ class RequestsTestSuite(unittest.TestCase): self.assertEqual(r2.status_code, 200) - if __name__ == '__main__': unittest.main() From b14fa0764bc5e1340762e45af999334e9b74f642 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 21:50:04 -0400 Subject: [PATCH 52/62] gevent installation documentation --- docs/user/advanced.rst | 2 +- docs/user/install.rst | 22 ++++++++++++++++++++++ requests/models.py | 1 - 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/docs/user/advanced.rst b/docs/user/advanced.rst index e8c812a8..9f0a6838 100644 --- a/docs/user/advanced.rst +++ b/docs/user/advanced.rst @@ -50,7 +50,7 @@ Requests has first-class support for non-blocking i/o requests, powered by gevent. This allows you to send a bunch of HTTP requests at the same First, let's import the async module. Heads up — if you don't have -**gevent** installed, this will fail.:: +`gevent `_ this will fail:: from requests import async diff --git a/docs/user/install.rst b/docs/user/install.rst index dc4aa627..6179abdc 100644 --- a/docs/user/install.rst +++ b/docs/user/install.rst @@ -54,3 +54,25 @@ Once you have a copy of the source, you can embed it in your Python package, or install it into your site-packages easily:: $ python setup.py install + +.. _gevent: + +Installing Gevent +----------------- + +If you are using the ``requests.async`` module for making concurrent +requests, you need to install gevent. + +To install gevent, you'll need ``libevent``. + +OSX:: + + $ brew install libevent + +Ubuntu:: + + $ apt-get install libevent-dev + +Once you have ``libevent``, you can install ``gevent`` with ``pip``:: + + $ pip install gevent \ No newline at end of file diff --git a/requests/models.py b/requests/models.py index 8969c886..a63c904c 100644 --- a/requests/models.py +++ b/requests/models.py @@ -182,7 +182,6 @@ class Request(object): response._close = resp.close if self.cookiejar: - response.cookies = dict_from_cookiejar(self.cookiejar) From aa31b6b4dd199ba733b5e03226a8019a2b9c7c66 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:02:46 -0400 Subject: [PATCH 53/62] Merge fixes --- requests/api.py | 11 +---------- requests/models.py | 5 ----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/requests/api.py b/requests/api.py index 54aeff88..ab388ed7 100644 --- a/requests/api.py +++ b/requests/api.py @@ -112,13 +112,9 @@ def get(url, **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ - return request('GET', url, **kwargs) + kwargs.setdefault('allow_redirects', True) return request('GET', url, **kwargs) - if "allow_redirects" not in kwargs: - kwargs["allow_redirects"] = True - - return request('get', url, **kwargs) def head(url, **kwargs): @@ -141,13 +137,8 @@ def head(url, **kwargs): :param **kwargs: Optional arguments that ``request`` takes. """ - return request('HEAD', url, **kwargs) kwargs.setdefault('allow_redirects', True) return request('HEAD', url, **kwargs) - if "allow_redirects" not in kwargs: - kwargs["allow_redirects"] = True - - return request('head', url, **kwargs) def post(url, data='', **kwargs): diff --git a/requests/models.py b/requests/models.py index 4a304a50..bf564b8c 100644 --- a/requests/models.py +++ b/requests/models.py @@ -214,12 +214,7 @@ class Request(object): while ( ('location' in r.headers) and - ((self.method in ('GET', 'HEAD')) or - (r.status_code is codes.see_other) or - (self.allow_redirects)) ((r.status_code is codes.see_other) or (self.allow_redirects)) - ((r.status_code is codes.see_other) or - (self.allow_redirects)) ): r.fo.close() From 33dec52b8eb4eb6ddc2677981bb5d5cf70ada59b Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:05:57 -0400 Subject: [PATCH 54/62] merge cleanups --- docs/user/intro.rst | 4 ---- requests/api.py | 27 +-------------------------- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/docs/user/intro.rst b/docs/user/intro.rst index 0a168d1b..15a17790 100644 --- a/docs/user/intro.rst +++ b/docs/user/intro.rst @@ -47,7 +47,3 @@ Requests License THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - -Support for Python 3.x is planned. -Support for Python 3.x is planned. diff --git a/requests/api.py b/requests/api.py index ab388ed7..1b847b7b 100644 --- a/requests/api.py +++ b/requests/api.py @@ -38,6 +38,7 @@ def request(method, url, :param timeout: (optional) Float describing the timeout of the request. :param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed. :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param return_response: (optional) If False, an un-sent Request object will returned. """ method = str(method).upper() @@ -96,19 +97,6 @@ def get(url, **kwargs): """Sends a GET request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to False to disable redirect following. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. :param **kwargs: Optional arguments that ``request`` takes. """ @@ -121,19 +109,6 @@ def head(url, **kwargs): """Sends a HEAD request. Returns :class:`Response` object. :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. - :param params: (optional) Dictionary of parameters, or bytes, to be sent in the query string for the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to sent with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param auth: (optional) AuthObject to enable Basic HTTP Auth. - :param timeout: (optional) Float describing the timeout of the request. - :param allow_redirects: (optional) Boolean. Set to False to disable redirect following. - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. :param **kwargs: Optional arguments that ``request`` takes. """ From 030d877ed51fc3676e402f824b3108c69c440df8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:11:42 -0400 Subject: [PATCH 55/62] v0.6.4 --- HISTORY.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/HISTORY.rst b/HISTORY.rst index c5c711f9..053d37a7 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,10 +1,13 @@ History ------- +0.6.4 (2011-10-13) +++++++++++++++++++ + * Automatic decoding of unicode, based on HTTP Headers. * New ``decode_unicode`` setting * Removal of ``r.read/close`` methods -* New ``r.fo`` interface for advanced response usage.* +* New ``r.faw`` interface for advanced response usage.* * Automatic expansion of parameterized headers 0.6.3 (2011-10-13) From 573ab095e44690e13047273b4f67eafcfd6613c8 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:11:50 -0400 Subject: [PATCH 56/62] fo => raw --- requests/models.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/requests/models.py b/requests/models.py index bf564b8c..9a8f5f9d 100644 --- a/requests/models.py +++ b/requests/models.py @@ -189,7 +189,7 @@ class Request(object): try: response.headers = CaseInsensitiveDict(getattr(resp.info(), 'dict', None)) - response.fo = resp + response.raw = resp if self.cookiejar: response.cookies = dict_from_cookiejar(self.cookiejar) @@ -217,7 +217,7 @@ class Request(object): ((r.status_code is codes.see_other) or (self.allow_redirects)) ): - r.fo.close() + r.raw.close() if not len(history) < settings.max_redirects: raise TooManyRedirects() @@ -407,7 +407,7 @@ class Response(object): self.headers = CaseInsensitiveDict() #: File-like object representation of response (for advanced usage). - self.fo = None + self.raw = None #: Final URL location of Response. self.url = None @@ -451,7 +451,7 @@ class Response(object): def generate(): while 1: - chunk = self.fo.read(chunk_size) + chunk = self.raw.read(chunk_size) if not chunk: break yield chunk @@ -479,7 +479,7 @@ class Response(object): 'already consumed') # Read the contents. - self._content = self.fo.read() + self._content = self.raw.read() # Decode GZip'd content. if 'gzip' in self.headers.get('content-encoding', ''): From daf7aeb8c3756508f3d960a58b6d3839be1e731f Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:15:55 -0400 Subject: [PATCH 57/62] Async API --- docs/api.rst | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 328e9e8b..9b1b10f2 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -31,6 +31,21 @@ They all return an instance of the :class:`Response ` object. .. autoclass:: Response :inherited-members: +Async +----- + +.. module:: requests.async + + +.. autofunction:: map +.. autofunction:: request +.. autofunction:: head +.. autofunction:: get +.. autofunction:: post +.. autofunction:: put +.. autofunction:: patch +.. autofunction:: delete + Utilities @@ -48,9 +63,6 @@ Cookies .. autofunction:: cookiejar_from_dict .. autofunction:: add_dict_to_cookiejar -Curl -~~~~ -.. autofunction:: curl_from_request Encodings ~~~~~~~~~ From f1f56c30818adc6c1e8e6814c4ffbcb341e3cdaa Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:17:24 -0400 Subject: [PATCH 58/62] Remove debian sources. --- debian/changelog | 5 ----- debian/compat | 1 - debian/control | 13 ------------- debian/docs | 1 - debian/pyversions | 1 - debian/rules | 42 ------------------------------------------ 6 files changed, 63 deletions(-) delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/docs delete mode 100644 debian/pyversions delete mode 100755 debian/rules diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 519752c4..00000000 --- a/debian/changelog +++ /dev/null @@ -1,5 +0,0 @@ -python-requests (0.4.1-0) testing; urgency=low - - * Initial Debian package - - -- Bruno Clermont Thu, 26 May 2011 16:25:00 -0500 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7ed6ff82..00000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/debian/control b/debian/control deleted file mode 100644 index 5c6ce49a..00000000 --- a/debian/control +++ /dev/null @@ -1,13 +0,0 @@ -Source: python-requests -Section: python -Priority: optional -Maintainer: Bruno Clermont -Homepage: https://github.com/bclermont/requests -Bugs: https://github.com/bclermont/requests/issues -Build-Depends: debhelper, python-support - -Package: python-requests -Architecture: all -Depends: ${python:Depends}, python-support -Provides: ${python:Provides} -Description: Python HTTP Requests for Humans. diff --git a/debian/docs b/debian/docs deleted file mode 100644 index 9bb74d2d..00000000 --- a/debian/docs +++ /dev/null @@ -1 +0,0 @@ -docs/user/*.rst \ No newline at end of file diff --git a/debian/pyversions b/debian/pyversions deleted file mode 100644 index 8b253bc3..00000000 --- a/debian/pyversions +++ /dev/null @@ -1 +0,0 @@ -2.4- diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 28e92ec0..00000000 --- a/debian/rules +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/make -f - -# Verbose mode -#export DH_VERBOSE=1 - -clean: - dh_testdir - dh_testroot - - rm -rf build requests.egg-info -# find django-sentry/ -name *.pyc | xargs rm -f - - dh_clean - -build: - dh_testdir - - python setup.py build - -install: - dh_testdir - dh_installdirs - - python setup.py install --root $(CURDIR)/debian/python-requests - -binary-indep: install - -binary-arch: install - dh_install - dh_installdocs -# dh_installchangelogs - dh_compress - dh_fixperms - dh_pysupport - dh_gencontrol - dh_installdeb - dh_md5sums - dh_builddeb -- -Z lzma -z9 - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary - From 244172bdd4b66ec7fdebdc76850b9ee08412a16c Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:17:54 -0400 Subject: [PATCH 59/62] v0.6.4 --- requests/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/requests/core.py b/requests/core.py index e44cf83a..de05cf9f 100644 --- a/requests/core.py +++ b/requests/core.py @@ -12,8 +12,8 @@ This module implements the main Requests system. """ __title__ = 'requests' -__version__ = '0.6.3' -__build__ = 0x000603 +__version__ = '0.6.4' +__build__ = 0x000604 __author__ = 'Kenneth Reitz' __license__ = 'ISC' __copyright__ = 'Copyright 2011 Kenneth Reitz' From efc267ce59f6f18cffdfe6f736290857fdde1855 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:20:23 -0400 Subject: [PATCH 60/62] Remove deprecated tox configuration. --- tox.ini | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 tox.ini diff --git a/tox.ini b/tox.ini deleted file mode 100644 index b0fc2138..00000000 --- a/tox.ini +++ /dev/null @@ -1,8 +0,0 @@ -[tox] -envlist = py25,py26,py27 - -[testenv] -commands=py.test --junitxml=junit-{envname}.xml -deps = - pytest - omnijson \ No newline at end of file From 29548bfab65be51d7a7589cd702adc6eb0961588 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:20:43 -0400 Subject: [PATCH 61/62] Remove hacking file. --- HACKING | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 HACKING diff --git a/HACKING b/HACKING deleted file mode 100644 index f23d6fb0..00000000 --- a/HACKING +++ /dev/null @@ -1,15 +0,0 @@ -Where possible, please follow PEP8 with regard to coding style. Sometimes the -line length restriction is too hard to follow, so don't bend over backwards -there. - -Triple-quotes should always be """, single quotes are ' unless using " would -result in less escaping within the string. - -All modules, functions, and methods should be well documented reStructuredText -for Sphinx AutoDoc. - -All functionality should be available in pure Python. Optional C (via Cython) -implementations may be written for performance reasons, but should never -replace the Python implementation. - -Lastly, don't take yourself too seriously :) From 9011852db06ae94e1c79900172a0000e846a44dd Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Thu, 13 Oct 2011 22:22:38 -0400 Subject: [PATCH 62/62] Bunk submodule. --- requests/patches.py | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 requests/patches.py diff --git a/requests/patches.py b/requests/patches.py deleted file mode 100644 index 43a3b4c4..00000000 --- a/requests/patches.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.monkeys -"""