Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b83131779c | ||
|
|
ce5b5fe227 | ||
|
|
eccbf4a412 | ||
|
|
86c3ecfd34 | ||
|
|
bd3cf95e34 | ||
|
|
386c589ba0 | ||
|
|
f723ab538f | ||
|
|
925e975295 | ||
|
|
4c61fef13f | ||
|
|
39090cfba6 | ||
|
|
d7c0249aa8 | ||
|
|
01b58ba04e | ||
|
|
a8205bb509 | ||
|
|
e8d02ea0bb | ||
|
|
e23bf10cf4 | ||
|
|
508f4b1ca5 | ||
|
|
1d9bf43def | ||
|
|
bf2e73522f | ||
|
|
4e90aa7bd0 | ||
|
|
cf82d4406b | ||
|
|
3246b1fe17 | ||
|
|
087a27aba9 |
@@ -158,3 +158,4 @@ Patches and Suggestions
|
||||
- Joe Alcorn (`@buttscicles <https://github.com/buttscicles>`_)
|
||||
- Syed Suhail Ahmed <ssuhail.ahmed93@gmail.com> (`@syedsuhail <https://github.com/syedsuhail>`_)
|
||||
- Scott Sadler (`@ssadler <https://github.com/ssadler>`_)
|
||||
- Arthur Darcet (`@arthurdarcet <https://github.com/arthurdarcet>`_)
|
||||
|
||||
13
HISTORY.rst
13
HISTORY.rst
@@ -3,6 +3,19 @@
|
||||
Release History
|
||||
---------------
|
||||
|
||||
2.5.1 (2014-12-23)
|
||||
++++++++++++++++++
|
||||
|
||||
**Behavioural Changes**
|
||||
|
||||
- Only catch HTTPErrors in raise_for_status (#2382)
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Handle LocationParseError from urllib3 (#2344)
|
||||
- Handle file-like object filenames that are not strings (#2379)
|
||||
- Unbreak HTTPDigestAuth handler. Allow new nonces to be negotiated (#2389)
|
||||
|
||||
2.5.0 (2014-12-01)
|
||||
++++++++++++++++++
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ perform the simplest of tasks.
|
||||
|
||||
Things shouldn't be this way. Not in Python.
|
||||
|
||||
.. code-block:: pycon
|
||||
.. code-block:: python
|
||||
|
||||
>>> r = requests.get('https://api.github.com', auth=('user', 'pass'))
|
||||
>>> r.status_code
|
||||
|
||||
@@ -384,7 +384,7 @@ Streaming Requests
|
||||
|
||||
With :class:`requests.Response.iter_lines()` you can easily
|
||||
iterate over streaming APIs such as the `Twitter Streaming
|
||||
API <https://dev.twitter.com/docs/streaming-api>`_. Simply
|
||||
API <https://dev.twitter.com/streaming/overview>`_. Simply
|
||||
set ``stream`` to ``True`` and iterate over the response with
|
||||
:class:`~requests.Response.iter_lines()`::
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
|
||||
"""
|
||||
|
||||
__title__ = 'requests'
|
||||
__version__ = '2.5.0'
|
||||
__build__ = 0x020500
|
||||
__version__ = '2.5.1'
|
||||
__build__ = 0x020501
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'Apache 2.0'
|
||||
__copyright__ = 'Copyright 2014 Kenneth Reitz'
|
||||
|
||||
@@ -67,6 +67,7 @@ class HTTPDigestAuth(AuthBase):
|
||||
self.nonce_count = 0
|
||||
self.chal = {}
|
||||
self.pos = None
|
||||
self.num_401_calls = 1
|
||||
|
||||
def build_digest_header(self, method, url):
|
||||
|
||||
@@ -154,7 +155,7 @@ class HTTPDigestAuth(AuthBase):
|
||||
def handle_redirect(self, r, **kwargs):
|
||||
"""Reset num_401_calls counter on redirects."""
|
||||
if r.is_redirect:
|
||||
setattr(self, 'num_401_calls', 1)
|
||||
self.num_401_calls = 1
|
||||
|
||||
def handle_401(self, r, **kwargs):
|
||||
"""Takes the given response and tries digest-auth, if needed."""
|
||||
@@ -168,7 +169,7 @@ class HTTPDigestAuth(AuthBase):
|
||||
|
||||
if 'digest' in s_auth.lower() and num_401_calls < 2:
|
||||
|
||||
setattr(self, 'num_401_calls', num_401_calls + 1)
|
||||
self.num_401_calls += 1
|
||||
pat = re.compile(r'digest ', flags=re.IGNORECASE)
|
||||
self.chal = parse_dict_header(pat.sub('', s_auth, count=1))
|
||||
|
||||
@@ -188,7 +189,7 @@ class HTTPDigestAuth(AuthBase):
|
||||
|
||||
return _r
|
||||
|
||||
setattr(self, 'num_401_calls', num_401_calls + 1)
|
||||
self.num_401_calls = 1
|
||||
return r
|
||||
|
||||
def __call__(self, r):
|
||||
|
||||
@@ -76,7 +76,7 @@ is_solaris = ('solar==' in str(sys.platform).lower()) # Complete guess.
|
||||
try:
|
||||
import simplejson as json
|
||||
except (ImportError, SyntaxError):
|
||||
# simplejson does not support Python 3.2, it thows a SyntaxError
|
||||
# simplejson does not support Python 3.2, it throws a SyntaxError
|
||||
# because of u'...' Unicode literals.
|
||||
import json
|
||||
|
||||
|
||||
@@ -20,11 +20,10 @@ 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, ReadTimeoutError, ProtocolError)
|
||||
DecodeError, ReadTimeoutError, ProtocolError, LocationParseError)
|
||||
from .exceptions import (
|
||||
HTTPError, RequestException, MissingSchema, InvalidURL,
|
||||
ChunkedEncodingError, ContentDecodingError, ConnectionError,
|
||||
StreamConsumedError)
|
||||
HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
|
||||
ContentDecodingError, ConnectionError, StreamConsumedError)
|
||||
from .utils import (
|
||||
guess_filename, get_auth_from_url, requote_uri,
|
||||
stream_decode_response_unicode, to_key_val_list, parse_header_links,
|
||||
@@ -351,7 +350,10 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
return
|
||||
|
||||
# Support for unicode domain names and paths.
|
||||
scheme, auth, host, port, path, query, fragment = parse_url(url)
|
||||
try:
|
||||
scheme, auth, host, port, path, query, fragment = parse_url(url)
|
||||
except LocationParseError as e:
|
||||
raise InvalidURL(*e.args)
|
||||
|
||||
if not scheme:
|
||||
raise MissingSchema("Invalid URL {0!r}: No schema supplied. "
|
||||
@@ -615,7 +617,7 @@ class Response(object):
|
||||
def ok(self):
|
||||
try:
|
||||
self.raise_for_status()
|
||||
except RequestException:
|
||||
except HTTPError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@@ -115,7 +115,7 @@ def get_netrc_auth(url):
|
||||
def guess_filename(obj):
|
||||
"""Tries to guess the filename of the given object."""
|
||||
name = getattr(obj, 'name', None)
|
||||
if name and name[0] != '<' and name[-1] != '>':
|
||||
if name and isinstance(name, builtin_str) and name[0] != '<' and name[-1] != '>':
|
||||
return os.path.basename(name)
|
||||
|
||||
|
||||
|
||||
@@ -258,7 +258,7 @@ class RequestsTestCase(unittest.TestCase):
|
||||
"""Do not send headers in Session.headers with None values."""
|
||||
ses = requests.Session()
|
||||
ses.headers['Accept-Encoding'] = None
|
||||
req = requests.Request('GET', 'http://httpbin.org/get')
|
||||
req = requests.Request('GET', httpbin('get'))
|
||||
prep = ses.prepare_request(req)
|
||||
assert 'Accept-Encoding' not in prep.headers
|
||||
|
||||
@@ -309,6 +309,11 @@ class RequestsTestCase(unittest.TestCase):
|
||||
with pytest.raises(ConnectionError):
|
||||
requests.get("http://httpbin.org:1")
|
||||
|
||||
def test_LocationParseError(self):
|
||||
"""Inputing a URL that cannot be parsed should raise an InvalidURL error"""
|
||||
with pytest.raises(InvalidURL):
|
||||
requests.get("http://fe80::5054:ff:fe5a:fc0")
|
||||
|
||||
def test_basicauth_with_netrc(self):
|
||||
auth = ('user', 'pass')
|
||||
wrong_auth = ('wronguser', 'wrongpass')
|
||||
@@ -928,6 +933,14 @@ class RequestsTestCase(unittest.TestCase):
|
||||
|
||||
assert 'multipart/form-data' in p.headers['Content-Type']
|
||||
|
||||
def test_can_send_file_object_with_non_string_filename(self):
|
||||
f = io.BytesIO()
|
||||
f.name = 2
|
||||
r = requests.Request('POST', httpbin('post'), files={'f': f})
|
||||
p = r.prepare()
|
||||
|
||||
assert 'multipart/form-data' in p.headers['Content-Type']
|
||||
|
||||
def test_autoset_header_values_are_native(self):
|
||||
data = 'this is a string'
|
||||
length = '16'
|
||||
@@ -1008,12 +1021,12 @@ class RequestsTestCase(unittest.TestCase):
|
||||
assert s == "Basic dGVzdDp0ZXN0"
|
||||
|
||||
def test_requests_history_is_saved(self):
|
||||
r = requests.get('https://httpbin.org/redirect/5')
|
||||
r = requests.get(httpbin('redirect/5'))
|
||||
total = r.history[-1].history
|
||||
i = 0
|
||||
for item in r.history:
|
||||
assert item.history == total[0:i]
|
||||
i=i+1
|
||||
i = i + 1
|
||||
|
||||
def test_json_param_post_content_type_works(self):
|
||||
r = requests.post(
|
||||
@@ -1350,7 +1363,7 @@ class TestMorselToCookieMaxAge(unittest.TestCase):
|
||||
class TestTimeout:
|
||||
def test_stream_timeout(self):
|
||||
try:
|
||||
requests.get('https://httpbin.org/delay/10', timeout=2.0)
|
||||
requests.get(httpbin('delay/10'), timeout=2.0)
|
||||
except requests.exceptions.Timeout as e:
|
||||
assert 'Read timed out' in e.args[0].args[0]
|
||||
|
||||
@@ -1450,7 +1463,7 @@ class TestRedirects:
|
||||
|
||||
def test_requests_are_updated_each_time(self):
|
||||
session = RedirectSession([303, 307])
|
||||
prep = requests.Request('POST', 'http://httpbin.org/post').prepare()
|
||||
prep = requests.Request('POST', httpbin('post')).prepare()
|
||||
r0 = session.send(prep)
|
||||
assert r0.request.method == 'POST'
|
||||
assert session.calls[-1] == SendCall((r0.request,), {})
|
||||
@@ -1534,12 +1547,12 @@ def test_prepare_unicode_url():
|
||||
def test_urllib3_retries():
|
||||
from requests.packages.urllib3.util import Retry
|
||||
s = requests.Session()
|
||||
s.mount('https://', HTTPAdapter(max_retries=Retry(
|
||||
s.mount('http://', HTTPAdapter(max_retries=Retry(
|
||||
total=2, status_forcelist=[500]
|
||||
)))
|
||||
|
||||
with pytest.raises(RetryError):
|
||||
s.get('https://httpbin.org/status/500')
|
||||
s.get(httpbin('status/500'))
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
Reference in New Issue
Block a user