aboutsummaryrefslogtreecommitdiff
path: root/requests/models.py
diff options
context:
space:
mode:
authorSVN-Git Migration <python-modules-team@lists.alioth.debian.org>2015-10-08 13:41:31 -0700
committerSVN-Git Migration <python-modules-team@lists.alioth.debian.org>2015-10-08 13:41:31 -0700
commitca5cb993a3ce4fbdf50eebd31cb6b71eec9bc391 (patch)
tree0cb1e57a7e04660775dc9426c1e4476082f88d1d /requests/models.py
parent224200a9815f792f93632d03a38e4f0763ae69ef (diff)
downloadpython-requests-ca5cb993a3ce4fbdf50eebd31cb6b71eec9bc391.tar
python-requests-ca5cb993a3ce4fbdf50eebd31cb6b71eec9bc391.tar.gz
Imported Upstream version 2.2.1
Diffstat (limited to 'requests/models.py')
-rw-r--r--requests/models.py101
1 files changed, 76 insertions, 25 deletions
diff --git a/requests/models.py b/requests/models.py
index 8fd9735..ae46a83 100644
--- a/requests/models.py
+++ b/requests/models.py
@@ -17,11 +17,13 @@ from .structures import CaseInsensitiveDict
from .auth import HTTPBasicAuth
from .cookies import cookiejar_from_dict, get_cookie_header
+from .packages.urllib3.fields import RequestField
from .packages.urllib3.filepost import encode_multipart_formdata
from .packages.urllib3.util import parse_url
+from .packages.urllib3.exceptions import DecodeError
from .exceptions import (
HTTPError, RequestException, MissingSchema, InvalidURL,
- ChunkedEncodingError)
+ ChunkedEncodingError, ContentDecodingError)
from .utils import (
guess_filename, get_auth_from_url, requote_uri,
stream_decode_response_unicode, to_key_val_list, parse_header_links,
@@ -90,7 +92,7 @@ class RequestEncodingMixin(object):
"""Build the body for a multipart/form-data request.
Will successfully encode files when passed as a dict or a list of
- 2-tuples. Order is retained if data is a list of 2-tuples but abritrary
+ 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
if parameters are supplied as a dict.
"""
@@ -119,11 +121,14 @@ class RequestEncodingMixin(object):
for (k, v) in files:
# support for explicit filename
ft = None
+ fh = None
if isinstance(v, (tuple, list)):
if len(v) == 2:
fn, fp = v
- else:
+ elif len(v) == 3:
fn, fp, ft = v
+ else:
+ fn, fp, ft, fh = v
else:
fn = guess_filename(v) or k
fp = v
@@ -132,11 +137,10 @@ class RequestEncodingMixin(object):
if isinstance(fp, bytes):
fp = BytesIO(fp)
- if ft:
- new_v = (fn, fp.read(), ft)
- else:
- new_v = (fn, fp.read())
- new_fields.append((k, new_v))
+ rf = RequestField(name=k, data=fp.read(),
+ filename=fn, headers=fh)
+ rf.make_multipart(content_type=ft)
+ new_fields.append(rf)
body, content_type = encode_multipart_formdata(new_fields)
@@ -267,6 +271,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
self.url = None
#: dictionary of HTTP headers.
self.headers = None
+ # The `CookieJar` used to create the Cookie header will be stored here
+ # after prepare_cookies is called
+ self._cookies = None
#: request body to send to the server.
self.body = None
#: dictionary of callback hooks, for internal usage.
@@ -274,7 +281,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
def prepare(self, method=None, url=None, headers=None, files=None,
data=None, params=None, auth=None, cookies=None, hooks=None):
- """Prepares the the entire request with the given parameters."""
+ """Prepares the entire request with the given parameters."""
self.prepare_method(method)
self.prepare_url(url, params)
@@ -295,7 +302,8 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
p = PreparedRequest()
p.method = self.method
p.url = self.url
- p.headers = self.headers
+ p.headers = self.headers.copy()
+ p._cookies = self._cookies.copy()
p.body = self.body
p.hooks = self.hooks
return p
@@ -317,11 +325,17 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
except UnicodeDecodeError:
pass
+ # Don't do any URL preparation for oddball schemes
+ if ':' in url and not url.lower().startswith('http'):
+ self.url = url
+ return
+
# Support for unicode domain names and paths.
scheme, auth, host, port, path, query, fragment = parse_url(url)
if not scheme:
- raise MissingSchema("Invalid URL %r: No schema supplied" % url)
+ raise MissingSchema("Invalid URL {0!r}: No schema supplied. "
+ "Perhaps you meant http://{0}?".format(url))
if not host:
raise InvalidURL("Invalid URL %r: No host supplied" % url)
@@ -404,7 +418,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
raise NotImplementedError('Streamed bodies and files are mutually exclusive.')
if length is not None:
- self.headers['Content-Length'] = str(length)
+ self.headers['Content-Length'] = builtin_str(length)
else:
self.headers['Transfer-Encoding'] = 'chunked'
else:
@@ -430,12 +444,12 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
def prepare_content_length(self, body):
if hasattr(body, 'seek') and hasattr(body, 'tell'):
body.seek(0, 2)
- self.headers['Content-Length'] = str(body.tell())
+ self.headers['Content-Length'] = builtin_str(body.tell())
body.seek(0, 0)
elif body is not None:
l = super_len(body)
if l:
- self.headers['Content-Length'] = str(l)
+ self.headers['Content-Length'] = builtin_str(l)
elif self.method not in ('GET', 'HEAD'):
self.headers['Content-Length'] = '0'
@@ -465,14 +479,13 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
"""Prepares the given HTTP cookie data."""
if isinstance(cookies, cookielib.CookieJar):
- cookies = cookies
+ self._cookies = cookies
else:
- cookies = cookiejar_from_dict(cookies)
+ self._cookies = cookiejar_from_dict(cookies)
- if 'cookie' not in self.headers:
- cookie_header = get_cookie_header(cookies, self)
- if cookie_header is not None:
- self.headers['Cookie'] = cookie_header
+ cookie_header = get_cookie_header(self._cookies, self)
+ if cookie_header is not None:
+ self.headers['Cookie'] = cookie_header
def prepare_hooks(self, hooks):
"""Prepares the given hooks."""
@@ -485,6 +498,19 @@ class Response(object):
server's response to an HTTP request.
"""
+ __attrs__ = [
+ '_content',
+ 'status_code',
+ 'headers',
+ 'url',
+ 'history',
+ 'encoding',
+ 'reason',
+ 'cookies',
+ 'elapsed',
+ 'request',
+ ]
+
def __init__(self):
super(Response, self).__init__()
@@ -500,7 +526,7 @@ class Response(object):
self.headers = CaseInsensitiveDict()
#: File-like object representation of response (for advanced usage).
- #: Requires that ``stream=True` on the request.
+ #: Use of ``raw`` requires that ``stream=True`` be set on the request.
# This requirement does not apply for use internally to Requests.
self.raw = None
@@ -524,6 +550,24 @@ class Response(object):
#: and the arrival of the response (as a timedelta)
self.elapsed = datetime.timedelta(0)
+ def __getstate__(self):
+ # Consume everything; accessing the content attribute makes
+ # sure the content has been fully read.
+ if not self._content_consumed:
+ self.content
+
+ return dict(
+ (attr, getattr(self, attr, None))
+ for attr in self.__attrs__
+ )
+
+ def __setstate__(self, state):
+ for name, value in state.items():
+ setattr(self, name, value)
+
+ # pickled objects do not have .raw
+ setattr(self, '_content_consumed', True)
+
def __repr__(self):
return '<Response [%s]>' % (self.status_code)
@@ -573,9 +617,11 @@ class Response(object):
yield chunk
except IncompleteRead as e:
raise ChunkedEncodingError(e)
+ except DecodeError as e:
+ raise ContentDecodingError(e)
except AttributeError:
# Standard file-like object.
- while 1:
+ while True:
chunk = self.raw.read(chunk_size)
if not chunk:
break
@@ -644,8 +690,13 @@ class Response(object):
def text(self):
"""Content of the response, in unicode.
- if Response.encoding is None and chardet module is available, encoding
- will be guessed.
+ If Response.encoding is None, encoding will be guessed using
+ ``chardet``.
+
+ The encoding of the response content is determined based soley on HTTP
+ headers, following RFC 2616 to the letter. If you can take advantage of
+ non-HTTP knowledge to make a better guess at the encoding, you should
+ set ``r.encoding`` appropriately before accessing this property.
"""
# Try charset from content-type
@@ -687,7 +738,7 @@ class Response(object):
encoding = guess_json_utf(self.content)
if encoding is not None:
return json.loads(self.content.decode(encoding), **kwargs)
- return json.loads(self.text or self.content, **kwargs)
+ return json.loads(self.text, **kwargs)
@property
def links(self):