mirror of
https://github.com/kennethreitz/requests.git
synced 2026-06-05 22:50:18 +00:00
Merge branch 'master' into proposed/3.0.0
This commit is contained in:
@@ -175,3 +175,5 @@ Patches and Suggestions
|
||||
- Brian Bamsch <bbamsch32@gmail.com> (`@bbamsch <https://github.com/bbamsch>`_)
|
||||
- Om Prakash Kumar <omprakash070@gmail.com> (`@iamprakashom <https://github.com/iamprakashom>`_)
|
||||
- Philipp Konrad <gardiac2002@gmail.com> (`@gardiac2002 <https://github.com/gardiac2002>`_)
|
||||
- Hussain Tamboli <hussaintamboli18@gmail.com> (`@hussaintamboli <https://github.com/hussaintamboli>`_)
|
||||
- Casey Davidson (`@davidsoncasey <https://github.com/davidsoncasey>`_)
|
||||
|
||||
+43
@@ -3,6 +3,49 @@
|
||||
Release History
|
||||
---------------
|
||||
|
||||
2.12.3 (2016-12-01)
|
||||
+++++++++++++++++++
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Fixed regression from v2.12.1 for URLs with schemes that begin with "http".
|
||||
These URLs have historically been processed as though they were HTTP-schemed
|
||||
URLs, and so have had parameters added. This was removed in v2.12.2 in an
|
||||
overzealous attempt to resolve problems with IDNA-encoding those URLs. This
|
||||
change was reverted: the other fixes for IDNA-encoding have been judged to
|
||||
be sufficient to return to the behaviour Requests had before v2.12.0.
|
||||
|
||||
2.12.2 (2016-11-30)
|
||||
+++++++++++++++++++
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Fixed several issues with IDNA-encoding URLs that are technically invalid but
|
||||
which are widely accepted. Requests will now attempt to IDNA-encode a URL if
|
||||
it can but, if it fails, and the host contains only ASCII characters, it will
|
||||
be passed through optimistically. This will allow users to opt-in to using
|
||||
IDNA2003 themselves if they want to, and will also allow technically invalid
|
||||
but still common hostnames.
|
||||
- Fixed an issue where URLs with leading whitespace would raise
|
||||
``InvalidSchema`` errors.
|
||||
- Fixed an issue where some URLs without the HTTP or HTTPS schemes would still
|
||||
have HTTP URL preparation applied to them.
|
||||
- Fixed an issue where Unicode strings could not be used in basic auth.
|
||||
- Fixed an issue encountered by some Requests plugins where constructing a
|
||||
Response object would cause ``Response.content`` to raise an
|
||||
``AttributeError``.
|
||||
|
||||
2.12.1 (2016-11-16)
|
||||
+++++++++++++++++++
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Updated setuptools 'security' extra for the new PyOpenSSL backend in urllib3.
|
||||
|
||||
**Miscellaneous**
|
||||
|
||||
- Updated bundled urllib3 to 1.19.1.
|
||||
|
||||
2.12.0 (2016-11-15)
|
||||
+++++++++++++++++++
|
||||
|
||||
|
||||
+5
-1
@@ -3,7 +3,7 @@ Requests: HTTP for Humans
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/requests.svg
|
||||
:target: https://pypi.python.org/pypi/requests
|
||||
|
||||
|
||||
Requests is the only *Non-GMO* HTTP library for Python, safe for human
|
||||
consumption.
|
||||
|
||||
@@ -29,6 +29,10 @@ Behold, the power of Requests:
|
||||
|
||||
See `the similar code, sans Requests <https://gist.github.com/973705>`_.
|
||||
|
||||
.. image:: http://docs.python-requests.org/en/master/_static/requests-sidebar.png
|
||||
:target: http://docs.python-requests.org/
|
||||
|
||||
|
||||
Requests allows you to send *organic, grass-fed* HTTP/1.1 requests, without the
|
||||
need for manual labor. There's no need to manually add query strings to your
|
||||
URLs, or to form-encode your POST data. Keep-alive and HTTP connection pooling
|
||||
|
||||
Vendored
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 299 KiB |
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
<p class="logo">
|
||||
<a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="Rezzy the Requests Sea Turtle"/>
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="https://kennethreitz.org/tattoos"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
allowtransparency="true" frameborder="0" scrolling="0" width="200" height="20"></iframe></p>
|
||||
|
||||
<p><a href="https://twitter.com/kennethreitz" class="twitter-follow-button" data-show-count="false">Follow @kennethreitz</a> <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script></p>
|
||||
|
||||
<p><a href="https://saythanks.io/to/kennethreitz">Say Thanks!</a></p>
|
||||
<p><a href="http://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
|
||||
|
||||
<h3>Other Projects</h3>
|
||||
|
||||
Vendored
+5
-1
@@ -1,6 +1,6 @@
|
||||
<p class="logo">
|
||||
<a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="Rezzy the Requests Sea Turtle"/>
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" title="https://kennethreitz.org/tattoos"/>
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
@@ -19,6 +19,10 @@
|
||||
|
||||
<p><a href="http://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
|
||||
|
||||
<hr/>
|
||||
|
||||
<p>If you enjoy using this project, <a href="https://saythanks.io/to/kennethreitz">Say Thanks!</a></p>
|
||||
|
||||
<p><iframe src="http://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false"
|
||||
allowtransparency="true" frameborder="0" scrolling="0" width="200" height="20"></iframe></p>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ A hotfix release will only include bug fixes that were missed when the project
|
||||
released the previous version. If the previous version of Requests released
|
||||
``v10.2.7`` the hotfix release would be versioned as ``v10.2.8``.
|
||||
|
||||
Hotfixes will **not** include upgrades to vendored dependences after
|
||||
Hotfixes will **not** include upgrades to vendored dependencies after
|
||||
``v2.6.2``
|
||||
|
||||
Reasoning
|
||||
|
||||
@@ -178,13 +178,14 @@ In general, however, you should use a pattern like this to save what is being
|
||||
streamed to a file::
|
||||
|
||||
with open(filename, 'wb') as fd:
|
||||
for chunk in r.iter_content(chunk_size):
|
||||
for chunk in r.iter_content(chunk_size=128):
|
||||
fd.write(chunk)
|
||||
|
||||
Using ``Response.iter_content`` will handle a lot of what you would otherwise
|
||||
have to handle when using ``Response.raw`` directly. When streaming a
|
||||
download, the above is the preferred and recommended way to retrieve the
|
||||
content.
|
||||
content. Note that ``chunk_size`` can be freely adjusted to a number that
|
||||
may better fit your use cases.
|
||||
|
||||
|
||||
Custom Headers
|
||||
@@ -423,8 +424,8 @@ suitable for use over multiple domains or paths. Cookie jars can
|
||||
also be passed in to requests::
|
||||
|
||||
>>> jar = requests.cookies.RequestsCookieJar()
|
||||
>>> jar.set('tasty_cookie', 'yum', site='httpbin.org', path='/cookies')
|
||||
>>> jar.set('gross_cookie', 'blech', site='httpbin.org', path='/elsewhere')
|
||||
>>> jar.set('tasty_cookie', 'yum', domain='httpbin.org', path='/cookies')
|
||||
>>> jar.set('gross_cookie', 'blech', domain='httpbin.org', path='/elsewhere')
|
||||
>>> url = 'http://httpbin.org/cookies'
|
||||
>>> r = requests.get(url, cookies=jar)
|
||||
>>> r.text
|
||||
|
||||
+8149
-1644
File diff suppressed because one or more lines are too long
+1
-487
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 863 KiB |
@@ -8,7 +8,7 @@ Provides utility functions that are consumed internally by Requests
|
||||
which depend on extremely few external helpers (such as compat)
|
||||
"""
|
||||
|
||||
from .compat import is_py2, builtin_str
|
||||
from .compat import is_py2, builtin_str, str
|
||||
|
||||
|
||||
def to_native_string(string, encoding='ascii'):
|
||||
@@ -25,3 +25,18 @@ def to_native_string(string, encoding='ascii'):
|
||||
out = string.decode(encoding)
|
||||
|
||||
return out
|
||||
|
||||
|
||||
def unicode_is_ascii(u_string):
|
||||
"""Determine if unicode string only contains ASCII characters.
|
||||
|
||||
:param str u_string: unicode string to check. Must be unicode
|
||||
and not Python 2 `str`.
|
||||
:rtype: bool
|
||||
"""
|
||||
assert isinstance(u_string, str)
|
||||
try:
|
||||
u_string.encode('ascii')
|
||||
return True
|
||||
except UnicodeEncodeError:
|
||||
return False
|
||||
|
||||
+1
-1
@@ -34,7 +34,7 @@ def request(method, url, session=None, **kwargs):
|
||||
before giving up, as a float, or a :ref:`(connect timeout, read
|
||||
timeout) <timeouts>` tuple.
|
||||
:type timeout: float or tuple
|
||||
:param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
|
||||
:param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection.
|
||||
:type allow_redirects: bool
|
||||
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
|
||||
:param verify: (optional) whether the SSL cert will be verified. A CA_BUNDLE path can also be provided. Defaults to ``True``.
|
||||
|
||||
+7
-1
@@ -27,9 +27,15 @@ CONTENT_TYPE_MULTI_PART = 'multipart/form-data'
|
||||
|
||||
def _basic_auth_str(username, password):
|
||||
"""Returns a Basic Auth string."""
|
||||
|
||||
if isinstance(username, str):
|
||||
username = username.encode('latin1')
|
||||
|
||||
if isinstance(password, str):
|
||||
password = password.encode('latin1')
|
||||
|
||||
authstr = 'Basic ' + to_native_string(
|
||||
b64encode(('%s:%s' % (username, password)).encode('latin1')).strip()
|
||||
b64encode(b':'.join((username, password))).strip()
|
||||
)
|
||||
|
||||
return authstr
|
||||
|
||||
+14
-8
@@ -33,7 +33,7 @@ from .packages.urllib3.exceptions import (
|
||||
from .exceptions import (
|
||||
HTTPError, MissingScheme, InvalidURL, ChunkedEncodingError,
|
||||
ContentDecodingError, ConnectionError, StreamConsumedError)
|
||||
from ._internal_utils import to_native_string
|
||||
from ._internal_utils import to_native_string, unicode_is_ascii
|
||||
from .utils import (
|
||||
guess_filename, get_auth_from_url, requote_uri,
|
||||
stream_decode_response_unicode, to_key_val_list, parse_header_links,
|
||||
@@ -372,11 +372,17 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
if not host:
|
||||
raise InvalidURL("Invalid URL %r: No host supplied" % url)
|
||||
|
||||
# Only want to apply IDNA to the hostname
|
||||
# In general, we want to try IDNA encoding every hostname, as that
|
||||
# allows users to automatically get the correct behaviour. However,
|
||||
# we’re quite strict about IDNA encoding, so certain valid hostnames
|
||||
# may fail to encode. On failure, we verify the hostname meets a
|
||||
# minimum standard of only containing ASCII characters, and not starting
|
||||
# with a wildcard (*), before allowing the unencoded hostname through.
|
||||
try:
|
||||
host = idna.encode(host, uts46=True).decode('utf-8')
|
||||
except (UnicodeError, idna.IDNAError):
|
||||
raise InvalidURL('URL has an invalid label.')
|
||||
if not unicode_is_ascii(host) or host.startswith(u'*'):
|
||||
raise InvalidURL('URL has an invalid label.')
|
||||
|
||||
# Carefully reconstruct the network location
|
||||
netloc = auth or ''
|
||||
@@ -600,7 +606,7 @@ class Response(object):
|
||||
#: Final URL location of Response.
|
||||
self.url = None
|
||||
|
||||
#: Encoding to decode with when accessing r.text or
|
||||
#: Encoding to decode with when accessing r.text or
|
||||
#: r.iter_content(decode_unicode=True)
|
||||
self.encoding = None
|
||||
|
||||
@@ -691,7 +697,7 @@ class Response(object):
|
||||
chunks are received. If stream=False, data is returned as
|
||||
a single chunk.
|
||||
|
||||
If using decode_unicode, the encoding must be set to a valid encoding
|
||||
If using decode_unicode, the encoding must be set to a valid encoding
|
||||
enumeration before invoking iter_content.
|
||||
"""
|
||||
|
||||
@@ -737,11 +743,11 @@ class Response(object):
|
||||
'encoding must be set before consuming streaming '
|
||||
'responses'
|
||||
)
|
||||
|
||||
|
||||
# check encoding value here, don't wait for the generator to be
|
||||
# consumed before raising an exception
|
||||
codecs.lookup(self.encoding)
|
||||
|
||||
|
||||
chunks = stream_decode_response_unicode(chunks, self)
|
||||
|
||||
return chunks
|
||||
@@ -787,7 +793,7 @@ class Response(object):
|
||||
raise RuntimeError(
|
||||
'The content for this response was already consumed')
|
||||
|
||||
if self.status_code == 0:
|
||||
if self.status_code == 0 or self.raw is None:
|
||||
self._content = None
|
||||
else:
|
||||
self._content = bytes().join(self.iter_content(CONTENT_CHUNK_SIZE)) or bytes()
|
||||
|
||||
@@ -32,7 +32,7 @@ except ImportError:
|
||||
|
||||
__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)'
|
||||
__license__ = 'MIT'
|
||||
__version__ = '1.19'
|
||||
__version__ = '1.19.1'
|
||||
|
||||
__all__ = (
|
||||
'HTTPConnectionPool',
|
||||
@@ -71,6 +71,7 @@ def add_stderr_logger(level=logging.DEBUG):
|
||||
logger.debug('Added a stderr logging handler to logger: %s', __name__)
|
||||
return handler
|
||||
|
||||
|
||||
# ... Clean up.
|
||||
del NullHandler
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ from __future__ import absolute_import
|
||||
import logging
|
||||
import os
|
||||
import warnings
|
||||
from urlparse import urljoin
|
||||
from ..packages.six.moves.urllib.parse import urljoin
|
||||
|
||||
from ..exceptions import (
|
||||
HTTPError,
|
||||
|
||||
@@ -141,4 +141,5 @@ def _has_ipv6(host):
|
||||
sock.close()
|
||||
return has_ipv6
|
||||
|
||||
|
||||
HAS_IPV6 = _has_ipv6('::1')
|
||||
|
||||
@@ -94,7 +94,8 @@ setup(
|
||||
cmdclass={'test': PyTest},
|
||||
tests_require=test_requirements,
|
||||
extras_require={
|
||||
'security': ['pyOpenSSL>=0.13', 'ndg-httpsclient', 'pyasn1'],
|
||||
'security': ['pyOpenSSL>=0.14', 'cryptography>=1.3.4', 'idna>=2.0.0'],
|
||||
'socks': ['PySocks>=1.5.6, !=1.5.7'],
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
+151
-3
@@ -156,6 +156,11 @@ class TestRequests:
|
||||
data=u"ööö".encode("utf-8")).prepare()
|
||||
assert isinstance(request.body, bytes)
|
||||
|
||||
def test_whitespaces_are_removed_from_url(self):
|
||||
# Test for issue #3696
|
||||
request = requests.Request('GET', ' http://example.com').prepare()
|
||||
assert request.url == 'http://example.com/'
|
||||
|
||||
@pytest.mark.parametrize('scheme', ('http://', 'HTTP://', 'hTTp://', 'HttP://'))
|
||||
def test_mixed_case_scheme_acceptable(self, httpbin, scheme):
|
||||
s = requests.Session()
|
||||
@@ -505,6 +510,20 @@ class TestRequests:
|
||||
r = s.get(url)
|
||||
assert r.status_code == 200
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'username, password', (
|
||||
('user', 'pass'),
|
||||
(u'имя'.encode('utf-8'), u'пароль'.encode('utf-8')),
|
||||
))
|
||||
def test_set_basicauth(self, httpbin, username, password):
|
||||
auth = (username, password)
|
||||
url = httpbin('get')
|
||||
|
||||
r = requests.Request('GET', url, auth=auth)
|
||||
p = r.prepare()
|
||||
|
||||
assert p.headers['Authorization'] == _basic_auth_str(username, password)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'url, exception', (
|
||||
# Connecting to an unknown domain should raise a ConnectionError
|
||||
@@ -1105,6 +1124,10 @@ class TestRequests:
|
||||
total_seconds = ((td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10**6)
|
||||
assert total_seconds > 0.0
|
||||
|
||||
def test_empty_response_has_content_none(self):
|
||||
r = requests.Response()
|
||||
assert r.content is None
|
||||
|
||||
def test_response_is_iterable(self):
|
||||
r = requests.Response()
|
||||
io = StringIO.StringIO('abc')
|
||||
@@ -1613,10 +1636,15 @@ class TestRequests:
|
||||
self._patch_adapter_gzipped_redirect(s, url)
|
||||
s.get(url)
|
||||
|
||||
def test_basic_auth_str_is_always_native(self):
|
||||
s = _basic_auth_str("test", "test")
|
||||
@pytest.mark.parametrize(
|
||||
'username, password, auth_str', (
|
||||
('test', 'test', 'Basic dGVzdDp0ZXN0'),
|
||||
(u'имя'.encode('utf-8'), u'пароль'.encode('utf-8'), 'Basic 0LjQvNGPOtC/0LDRgNC+0LvRjA=='),
|
||||
))
|
||||
def test_basic_auth_str_is_always_native(self, username, password, auth_str):
|
||||
s = _basic_auth_str(username, password)
|
||||
assert isinstance(s, builtin_str)
|
||||
assert s == "Basic dGVzdDp0ZXN0"
|
||||
assert s == auth_str
|
||||
|
||||
def test_requests_history_is_saved(self, httpbin):
|
||||
r = requests.get(httpbin('redirect/5'))
|
||||
@@ -1790,6 +1818,41 @@ class TestRequests:
|
||||
assert resp_with_cert.raw._pool.key_file == key
|
||||
assert resp.raw._pool is not resp_with_cert.raw._pool
|
||||
|
||||
def test_empty_stream_with_auth_does_not_set_content_length_header(self, httpbin):
|
||||
"""Ensure that a byte stream with size 0 will not set both a Content-Length
|
||||
and Transfer-Encoding header.
|
||||
"""
|
||||
auth = ('user', 'pass')
|
||||
url = httpbin('post')
|
||||
file_obj = io.BytesIO(b'')
|
||||
r = requests.Request('POST', url, auth=auth, data=file_obj)
|
||||
prepared_request = r.prepare()
|
||||
assert 'Transfer-Encoding' in prepared_request.headers
|
||||
assert 'Content-Length' not in prepared_request.headers
|
||||
|
||||
def test_stream_with_auth_does_not_set_transfer_encoding_header(self, httpbin):
|
||||
"""Ensure that a byte stream with size > 0 will not set both a Content-Length
|
||||
and Transfer-Encoding header.
|
||||
"""
|
||||
auth = ('user', 'pass')
|
||||
url = httpbin('post')
|
||||
file_obj = io.BytesIO(b'test data')
|
||||
r = requests.Request('POST', url, auth=auth, data=file_obj)
|
||||
prepared_request = r.prepare()
|
||||
assert 'Transfer-Encoding' not in prepared_request.headers
|
||||
assert 'Content-Length' in prepared_request.headers
|
||||
|
||||
def test_chunked_upload_does_not_set_content_length_header(self, httpbin):
|
||||
"""Ensure that requests with a generator body stream using
|
||||
Transfer-Encoding: chunked, not a Content-Length header.
|
||||
"""
|
||||
data = (i for i in [b'a', b'b', b'c'])
|
||||
url = httpbin('post')
|
||||
r = requests.Request('POST', url, data=data)
|
||||
prepared_request = r.prepare()
|
||||
assert 'Transfer-Encoding' in prepared_request.headers
|
||||
assert 'Content-Length' not in prepared_request.headers
|
||||
|
||||
|
||||
class TestCaseInsensitiveDict:
|
||||
|
||||
@@ -2242,6 +2305,7 @@ class TestPreparingURLs(object):
|
||||
(
|
||||
('http://google.com', 'http://google.com/'),
|
||||
(u'http://ジェーピーニック.jp', u'http://xn--hckqz9bzb1cyrb.jp/'),
|
||||
(u'http://xn--n3h.net/', u'http://xn--n3h.net/'),
|
||||
(
|
||||
u'http://ジェーピーニック.jp'.encode('utf-8'),
|
||||
u'http://xn--hckqz9bzb1cyrb.jp/'
|
||||
@@ -2262,6 +2326,18 @@ class TestPreparingURLs(object):
|
||||
u'http://Königsgäßchen.de/straße'.encode('utf-8'),
|
||||
u'http://xn--knigsgchen-b4a3dun.de/stra%C3%9Fe'
|
||||
),
|
||||
(
|
||||
b'http://xn--n3h.net/',
|
||||
u'http://xn--n3h.net/'
|
||||
),
|
||||
(
|
||||
b'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/',
|
||||
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/'
|
||||
),
|
||||
(
|
||||
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/',
|
||||
u'http://[1200:0000:ab00:1234:0000:2552:7777:1313]:12345/'
|
||||
)
|
||||
)
|
||||
)
|
||||
def test_preparing_url(self, url, expected):
|
||||
@@ -2276,9 +2352,81 @@ class TestPreparingURLs(object):
|
||||
b"http://*",
|
||||
u"http://*.google.com",
|
||||
u"http://*",
|
||||
u"http://☃.net/"
|
||||
)
|
||||
)
|
||||
def test_preparing_bad_url(self, url):
|
||||
r = requests.Request('GET', url=url)
|
||||
with pytest.raises(requests.exceptions.InvalidURL):
|
||||
r.prepare()
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'input, expected',
|
||||
(
|
||||
(
|
||||
b"http+unix://%2Fvar%2Frun%2Fsocket/path",
|
||||
u"http+unix://%2fvar%2frun%2fsocket/path",
|
||||
),
|
||||
(
|
||||
u"http+unix://%2Fvar%2Frun%2Fsocket/path",
|
||||
u"http+unix://%2fvar%2frun%2fsocket/path",
|
||||
),
|
||||
(
|
||||
b"mailto:user@example.org",
|
||||
u"mailto:user@example.org",
|
||||
),
|
||||
(
|
||||
u"mailto:user@example.org",
|
||||
u"mailto:user@example.org",
|
||||
),
|
||||
(
|
||||
b"data:SSDimaUgUHl0aG9uIQ==",
|
||||
u"data:SSDimaUgUHl0aG9uIQ==",
|
||||
)
|
||||
)
|
||||
)
|
||||
def test_url_mutation(self, input, expected):
|
||||
"""
|
||||
This test validates that we correctly exclude some URLs from
|
||||
preparation, and that we handle others. Specifically, it tests that
|
||||
any URL whose scheme doesn't begin with "http" is left alone, and
|
||||
those whose scheme *does* begin with "http" are mutated.
|
||||
"""
|
||||
r = requests.Request('GET', url=input)
|
||||
p = r.prepare()
|
||||
assert p.url == expected
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'input, params, expected',
|
||||
(
|
||||
(
|
||||
b"http+unix://%2Fvar%2Frun%2Fsocket/path",
|
||||
{"key": "value"},
|
||||
u"http+unix://%2fvar%2frun%2fsocket/path?key=value",
|
||||
),
|
||||
(
|
||||
u"http+unix://%2Fvar%2Frun%2Fsocket/path",
|
||||
{"key": "value"},
|
||||
u"http+unix://%2fvar%2frun%2fsocket/path?key=value",
|
||||
),
|
||||
(
|
||||
b"mailto:user@example.org",
|
||||
{"key": "value"},
|
||||
u"mailto:user@example.org",
|
||||
),
|
||||
(
|
||||
u"mailto:user@example.org",
|
||||
{"key": "value"},
|
||||
u"mailto:user@example.org",
|
||||
),
|
||||
)
|
||||
)
|
||||
def test_parameters_for_nonstandard_schemes(self, input, params, expected):
|
||||
"""
|
||||
Setting paramters for nonstandard schemes is allowed if those schemes
|
||||
begin with "http", and is forbidden otherwise.
|
||||
"""
|
||||
r = requests.Request('GET', url=input, params=params)
|
||||
p = r.prepare()
|
||||
assert p.url == expected
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ from requests.utils import (
|
||||
to_key_val_list, to_native_string,
|
||||
unquote_header_value, unquote_unreserved,
|
||||
urldefragauth, add_dict_to_cookiejar)
|
||||
from requests._internal_utils import unicode_is_ascii
|
||||
|
||||
from .compat import StringIO, cStringIO
|
||||
|
||||
@@ -515,6 +516,7 @@ def test_should_bypass_proxies(url, expected, monkeypatch):
|
||||
monkeypatch.setenv('NO_PROXY', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1')
|
||||
assert should_bypass_proxies(url) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'cookiejar', (
|
||||
compat.cookielib.CookieJar(),
|
||||
@@ -529,3 +531,14 @@ def test_add_dict_to_cookiejar(cookiejar):
|
||||
cj = add_dict_to_cookiejar(cookiejar, cookiedict)
|
||||
cookies = dict((cookie.name, cookie.value) for cookie in cj)
|
||||
assert cookiedict == cookies
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
'value, expected', (
|
||||
(u'test', True),
|
||||
(u'æíöû', False),
|
||||
(u'ジェーピーニック', False),
|
||||
)
|
||||
)
|
||||
def test_unicode_is_ascii(value, expected):
|
||||
assert unicode_is_ascii(value) is expected
|
||||
|
||||
Reference in New Issue
Block a user