Lazily encode data, params, files

Previously, data, params, and files were encoded and stored in
Request.__init__, and subsequently put into service during
Request.send. The problem with this approach is that hooks and auth
callables need to be aware of the eager encoding, and if they touch the
originals, make sure to update the encoded versions.

A better approach is to only encode late in the sending process. This
way, hooks and auth callables can safely make changes without fear of
the old, encoded variant overriding it.
This commit is contained in:
Idan Gazit
2012-05-03 00:04:13 +03:00
parent d240b1fe15
commit 324336e7f6
+15 -21
View File
@@ -114,9 +114,9 @@ class Request(object):
if 'HTTPS_PROXY' in os.environ:
self.proxies['https'] = os.environ['HTTPS_PROXY']
self.data, self._enc_data = self._encode_params(data)
self.params, self._enc_params = self._encode_params(params)
self.files, self._enc_files = self._encode_files(files)
self.data = data
self.params = params
self.files = files
#: :class:`Response <Response>` instance, containing
#: content and metadata of HTTP Response, once :attr:`sent <send>`.
@@ -314,19 +314,12 @@ class Request(object):
Will successfully encode parameters when passed as a dict or a list of
2-tuples. Order is retained if data is a list of 2-tuples but abritrary
if parameters are supplied as a dict.
If the data supplied contains parameters, encodes each parameter in it,
and returns a list of tuples containing the encoded parameters, and a
urlencoded version of that.
Otherwise, assumes the data is already encoded appropriately, and
returns it twice.
"""
if isinstance(data, bytes):
return data, data
return data
if isinstance(data, str):
return data, data
return data
elif hasattr(data, '__iter__'):
try:
dict(data)
@@ -340,14 +333,14 @@ class Request(object):
result.append(
(k.encode('utf-8') if isinstance(k, str) else k,
v.encode('utf-8') if isinstance(v, str) else v))
return result, urlencode(result, doseq=True)
return urlencode(result, doseq=True)
else:
return data, data
return data
def _encode_files(self, files):
if (not files) or isinstance(self.data, str):
return None, None
return None
try:
fields = self.data.copy()
@@ -365,7 +358,7 @@ class Request(object):
(body, content_type) = encode_multipart_formdata(fields)
return files, (body, content_type)
return (body, content_type)
@property
def full_url(self):
@@ -406,11 +399,12 @@ class Request(object):
url = (urlunparse([scheme, netloc, path, params, query, fragment]))
if self._enc_params:
enc_params = self._encode_params(self.params)
if enc_params:
if urlparse(url).query:
url = '%s&%s' % (url, self._enc_params)
url = '%s&%s' % (url, enc_params)
else:
url = '%s?%s' % (url, self._enc_params)
url = '%s?%s' % (url, enc_params)
if self.config.get('encode_uri', True):
url = requote_uri(url)
@@ -499,11 +493,11 @@ class Request(object):
# Multi-part file uploads.
if self.files:
(body, content_type) = self._enc_files
(body, content_type) = self._encode_files(self.files)
else:
if self.data:
body = self._enc_data
body = self._encode_params(self.data)
if isinstance(self.data, str):
content_type = None
else: