consolidate super_len code and cleanup docstrings

This commit is contained in:
Nate Prewitt
2017-02-12 23:02:47 -07:00
parent f239fe754d
commit a52fe6586c
4 changed files with 25 additions and 27 deletions
+3
View File
@@ -104,12 +104,15 @@ class StreamConsumedError(RequestException, TypeError):
class RetryError(RequestException):
"""Custom retries logic failed"""
class UnrewindableBodyError(RequestException):
"""Requests encountered an error when trying to rewind a body"""
class ConflictingHeaderError(RequestException):
"""Mutually exclusive request headers set"""
class InvalidBodyError(RequestException, ValueError):
"""An invalid request body was specified"""
+11 -17
View File
@@ -39,7 +39,7 @@ from .utils import (
guess_filename, get_auth_from_url, requote_uri,
stream_decode_response_unicode, to_key_val_list, parse_header_links,
iter_slices, guess_json_utf, super_len, check_header_validity,
determine_if_stream)
is_stream)
from .compat import (
cookielib, urlunparse, urlsplit, urlencode, str, bytes, StringIO,
is_py2, chardet, builtin_str, basestring)
@@ -468,9 +468,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
if not isinstance(body, bytes):
body = body.encode('utf-8')
is_stream = determine_if_stream(data)
if is_stream:
if is_stream(data):
body = data
if getattr(body, 'tell', None) is not None:
@@ -509,30 +507,26 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
def prepare_content_length(self, body):
"""Prepares Content-Length header.
If the length of the body of the request can be computed, Content-Length is set using
super_len. If user has manually set either a Transfer-Encoding or Content-Length header
when it should not be set (they should be mutually exclusive) an ConflictingHeaderError
If the length of the body of the request can be computed, Content-Length
is set using ``super_len``. If user has manually set either a
Transfer-Encoding or Content-Length header when it should not be set
(they should be mutually exclusive) a ConflictingHeaderError
error will be raised.
"""
if body is not None:
is_stream = determine_if_stream(body)
try:
length = super_len(body)
except (TypeError, AttributeError, UnsupportedOperation):
length = None
length = super_len(body)
if length:
self.headers['Content-Length'] = builtin_str(length)
elif is_stream and not length:
elif is_stream(body):
self.headers['Transfer-Encoding'] = 'chunked'
else:
raise InvalidBodyError("Non-null body must have length or be streamable")
elif (self.method not in ('GET', 'HEAD')) and (self.headers.get('Content-Length') is None):
raise InvalidBodyError('Non-null body must have length or be streamable.')
elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None:
self.headers['Content-Length'] = '0'
if 'Transfer-Encoding' in self.headers and 'Content-Length' in self.headers:
raise ConflictingHeaderError('Transfer-Encoding and Content-Length headers both set')
raise ConflictingHeaderError('Transfer-Encoding and Content-Length headers both set.')
def prepare_auth(self, auth, url=''):
"""Prepares the given HTTP auth data."""
+3 -4
View File
@@ -881,9 +881,8 @@ def rewind_body(prepared_request):
raise UnrewindableBodyError("Unable to rewind request body for redirect.")
def determine_if_stream(data):
"""Given data, determines if it should be sent as a stream.
"""
def is_stream(data):
"""Given data, determines if it should be sent as a stream."""
is_iterable = getattr(data, '__iter__', False)
is_io_type = not isinstance(data, (basestring, list, tuple, dict))
is_io_type = not isinstance(data, (basestring, list, tuple, collections.Mapping))
return is_iterable and is_io_type
+8 -6
View File
@@ -1925,16 +1925,18 @@ class TestRequests:
assert 'Content-Length' not in prepared_request.headers
def test_chunked_upload_with_manually_set_content_length_header_raises_error(self, httpbin):
"""Ensure that if a user manually sets a content length header when the data
is chunked that an ConflictingHeaderError is raised"""
data = (i for i in [b'a', b'b', b'c'])
"""Ensure that if a user manually sets a content length header, when
the data is chunked, that a ConflictingHeaderError is raised.
"""
data = (i for i in [b'a', b'b', b'c'])
url = httpbin('post')
with pytest.raises(ConflictingHeaderError):
r = requests.post(url, data=data, headers={'Content-Length': 'foo'})
def test_content_length_with_manually_set_transfer_encoding_raises_error(self, httpbin):
"""Ensure that if a user manually sets a Transfer-Encoding header when data is not chunked
that an ConflictingHeaderError is raised"""
"""Ensure that if a user manually sets a Transfer-Encoding header when
data is not chunked that an ConflictingHeaderError is raised.
"""
data = 'test data'
url = httpbin('post')
with pytest.raises(ConflictingHeaderError):
@@ -1945,7 +1947,7 @@ class TestRequests:
try:
requests.post(url, data=None)
except ConflictingHeaderError:
pytest.fail('ConflictingHeaderError raised')
pytest.fail('ConflictingHeaderError raised.')
def test_custom_redirect_mixin(self, httpbin):
"""Tests a custom mixin to overwrite ``get_redirect_target``.