Compare commits

...

71 Commits

Author SHA1 Message Date
Kenneth Reitz
46d646064c v2.4.3 2014-10-06 05:44:25 -04:00
Kenneth Reitz
78d12bbbe9 v2.4.3 2014-10-06 05:42:55 -04:00
Kenneth Reitz
6da438dabd Merge pull request #2268 from sigmavirus24/fix-params
Re-order params for backwards compat
2014-10-06 05:40:03 -04:00
Kenneth Reitz
4ec26da2f7 Merge pull request #2267 from minrk/unicode-url-py2
allow unicode URLs on Python 2
2014-10-06 05:39:54 -04:00
Ian Cordasco
0e4efab270 Re-order params for backwards compat 2014-10-05 18:55:59 -05:00
MinRK
ca2ebc5b68 allow unicode URLs on Python 2
on Python 2 u'é'.decode('utf8') fails with UnicodeEncodeError,
but only AttributeError is caught.

This only calls decode on known bytes objects.
2014-10-05 16:30:11 -07:00
Kenneth Reitz
5850b1f53b Merge pull request #2249 from t-8ch/fix_2247
fix #2247
2014-10-05 13:19:14 -04:00
Kenneth Reitz
779c001e44 requests v2.4.2 2014-10-05 13:15:33 -04:00
Kenneth Reitz
79f56e2e7e fix documentation for utils.get_unicode_from_response() :) 2014-10-05 13:14:38 -04:00
Kenneth Reitz
90dc467fc0 v2.4.2 changelog 2014-10-05 13:13:42 -04:00
Kenneth Reitz
65cdccb70f Merge pull request #2241 from tijko/master
raise RuntimeError when a single streamed request calls *iter methods th...
2014-10-05 12:48:40 -04:00
Kenneth Reitz
1e79cf6a47 Merge pull request #2258 from willingc/add-json
Add json parameter
2014-10-05 12:46:09 -04:00
Cory Benfield
20ca9feeb3 Merge pull request #2265 from sigmavirus24/session-attrs
Remove timeout from __attrs__
2014-10-05 09:05:29 +01:00
Ian Cordasco
b1f3a2dd66 Remove timeout from __attrs__
We do not allow the user to set the timeout value on the Session any longer so
this is extraneous
2014-10-04 23:04:36 -05:00
Kenneth Reitz
e74791d054 Merge pull request #2238 from buttscicles/byte-urls
Support bytestring URLs on Python 3.x
2014-10-02 12:20:05 -04:00
Ian Cordasco
8ed941fa69 Fix a couple of issues I noticed
- Don't _ prefix json in prepare_body
- Don't initialize json to []
- Don't initialize json to {}
- Reorder parameters to PreparedRequest.prepare
- Remove extra parentheses
- Update docstring
2014-09-30 16:03:31 -05:00
Joe Alcorn
a68d1b4517 Support bytestring URLs on Python 3.x 2014-09-30 19:29:10 +01:00
Thomas Weißschuh
cd5eb62961 remove unused import 2014-09-26 22:28:29 +00:00
Thomas Weißschuh
6e1db21733 fix #2247
We have to pass urllib3 the url without the authentication information,
else it will be parsed by httplib as a netloc and included in the request line
and Host header
2014-09-25 19:49:28 +00:00
Cory Benfield
a718a81d27 Merge pull request #2248 from jktjkt/docs-CAs
docs: Clarify how to pass a custom set of CAs
2014-09-25 19:28:05 +01:00
Jan Kundrát
3635b1501d docs: Clarify how to pass a custom set of CAs
This new wording makes it hopefully easier to find how to override the
system-provided list of trusted CAs. I failed to find this through some googling
and had to resort to asking on IRC previously.
2014-09-25 20:06:04 +02:00
Kenneth Reitz
de76fbeefb Merge pull request #2244 from sigmavirus24/bug/2231
Avoid getting stuck in a loop
2014-09-24 22:57:38 -04:00
Cory Benfield
e0d88c2814 Merge pull request #2245 from sigmavirus24/doc-fix
Correct redirection introduction
2014-09-23 07:25:26 +01:00
Ian Cordasco
671ba85d41 Correct redirection introduction
The history attribute contains responses, not requests.

Thanks to Yang Yang for reporting this to me via email
2014-09-22 21:08:29 -05:00
Ian Cordasco
ac44b48297 Avoid getting stuck in a loop
This prevents a case where we make a request to URL A, which 301s to B which
would then 301 back to A. Alternatively, for less simple schemes, this will
also prevent us from getting stuck in a loop, e.g., it will prevent the
following from causing an endless loop:

    A -> B -> C -> D -> E -> F --
    ^                             \
    |                             /
    ---<------------<----------<-
2014-09-22 21:01:36 -05:00
Tim Konick
64ba451049 make StreamConsumedError doubly inherit 2014-09-22 15:58:54 -04:00
Tim Konick
6e5f7bb9d3 using the StreamConsumedError 2014-09-22 15:51:59 -04:00
Tim Konick
58e0a6f4a0 add-in StreamConsumedError 2014-09-22 15:51:10 -04:00
Tim Konick
d6470870d0 rm else after if then raise block 2014-09-22 12:46:07 -04:00
Tim Konick
fdf932c61c raise RuntimeError when a single streamed request calls *iter methods than once 2014-09-22 12:04:29 -04:00
Cory Benfield
d28d45af91 Merge pull request #2237 from buttscicles/contributing-update
Remove invoke from requirements.txt, docs
2014-09-20 23:12:38 +01:00
Joe Alcorn
d243668d16 Remove invoke from requirements.txt, docs 2014-09-20 20:56:00 +01:00
Cory Benfield
466a70f7c1 Fixup the remaining references to timeline.json. 2014-09-20 15:00:36 +01:00
Kenneth Reitz
082c8d0db8 Merge pull request #2227 from mjul/master
Added example of how to send multiple files in one request.
2014-09-18 10:06:54 +09:00
Martin Jul
0924069b68 Moved multiple files upload example to advanced section. 2014-09-16 11:54:31 +02:00
Martin Jul
4707d11004 Added example of how to send multiple files in one request. 2014-09-16 11:38:40 +02:00
Ian Cordasco
9b41308b9f Merge pull request #2223 from blueyed/doc-followup-2222
Document skipping in PreparedRequest; followup to #2222
2014-09-12 11:54:40 -05:00
Daniel Hahler
bff8b91638 Document skipping in PreparedRequest; followup to #2222 2014-09-12 18:07:28 +02:00
Cory Benfield
1a44a99f17 Merge pull request #2222 from blueyed/fix-MissingScheme-for-hostport
Add tests to test_invalid_url for `InvalidSchema`
2014-09-12 15:16:11 +01:00
Daniel Hahler
d3566ee1b0 Add more tests to test_invalid_url
This adds tests for the behavior introduced in b149be5d, where
`PreparedRequest` was made to skip `parse_url` for e.g.
`localhost:3128/`.
2014-09-12 16:11:30 +02:00
Kenneth Reitz
9e8702d3d5 lawl 2014-09-09 12:42:00 -04:00
Kenneth Reitz
27b6bfc213 mils 2014-09-09 12:39:36 -04:00
Kenneth Reitz
dff383ce8f requests v2.4.1 2014-09-09 12:34:34 -04:00
Cory Benfield
5e94c81e98 Merge pull request #2210 from sigmavirus24/bug/2207
Fix #2207
2014-09-09 15:24:24 +01:00
Cory Benfield
2416e2343a Merge pull request #2213 from kennethreitz/req-rsp
Request->Response.
2014-09-09 08:45:30 +01:00
Cory Benfield
bf8f791a93 Request->Response. 2014-09-09 08:44:40 +01:00
Ian Cordasco
27c83f7177 Fix #2207
@Lukasa wrote the fix in #2207
2014-09-07 12:02:23 -05:00
Kenneth Reitz
359659cf4b Merge pull request #2203 from Lukasa/remove_certifi
Remove hard certifi dependency and document.
2014-09-05 08:11:57 -07:00
Cory Benfield
9c6ae1dc0b Link to Mozilla trust store. 2014-09-04 19:44:37 +01:00
Kenneth Reitz
0df32de02d Merge pull request #2199 from mtorromeo/patch-1
Open README and HISTORY as utf-8 encoded files (fixes #2196)
2014-09-04 11:41:46 -07:00
Cory Benfield
a77054f90f Remove hard certifi dependency and document. 2014-09-04 19:40:15 +01:00
Kenneth Reitz
1324ca1a0f Merge pull request #2193 from sigmavirus24/bug/2192
Capture and re-raise urllib3 ProtocolError
2014-09-04 11:39:41 -07:00
Kenneth Reitz
209a871b63 Merge pull request #2191 from kevinburke/comma
add trailing comma
2014-09-04 11:39:23 -07:00
Kenneth Reitz
07bbe214aa Merge pull request #2187 from kevinburke/more-docs
Document Timeout behaviour
2014-09-04 11:39:12 -07:00
Kenneth Reitz
958845ae35 requests[security] 2014-09-04 11:37:45 -07:00
Kenneth Reitz
bc2560480e Merge pull request #2195 from sigmavirus24/betterssl
Add betterssl extra
2014-09-04 11:36:56 -07:00
Ian Cordasco
9354855648 Consolidate error handling 2014-09-03 16:01:25 -05:00
Massimiliano Torromeo
226b5c7b0a Open README and HISTORY as utf-8 encoded files (fixes #2196) 2014-09-03 09:40:27 +02:00
Ian Cordasco
ce7957c085 Add test for invalid port 2014-08-29 16:50:45 -05:00
Ian Cordasco
c6a1167e8b Merge remote-tracking branch 'kevinburke/domain-failure-connection-error' into bug/2192 2014-08-29 16:43:51 -05:00
Ian Cordasco
c809867035 Add betterssl extra 2014-08-29 16:39:22 -05:00
Kevin Burke
2c76122a48 Add test that invalid domain raises a ConnectionError 2014-08-29 14:07:28 -07:00
Ian Cordasco
da122231e4 Capture and re-raise urllib3 ProtocolError 2014-08-29 15:16:30 -05:00
Kevin Burke
34ea836d77 tildes 2014-08-29 12:08:03 -07:00
Kevin Burke
59f5a1089a add trailing comma 2014-08-29 12:06:58 -07:00
Kevin Burke
81d6b3e435 s/behavior/behaviour 2014-08-29 11:51:09 -07:00
Kevin Burke
dfa41afd43 Document Timeout behaviour 2014-08-29 11:50:11 -07:00
Carol Willing
0713e09526 Fixes typo in test 2014-08-28 19:42:21 -07:00
Carol Willing
402f3b4993 Changes check on base and json. Fails on tests. 2014-08-28 19:27:45 -07:00
Carol Willing
b34a496649 Adds review changes 2014-08-28 16:45:24 -07:00
Carol Willing
8f17741849 Adds json parameter for POST requests 2014-08-28 12:53:19 -07:00
18 changed files with 263 additions and 94 deletions

View File

@@ -154,3 +154,5 @@ Patches and Suggestions
- Константин Подшумок (`@podshumok <https://github.com/podshumok>`_)
- Ben Bass (`@codedstructure <https://github.com/codedstructure>`_)
- Jonathan Wong <evolutionace@gmail.com> (`@ContinuousFunction <https://github.com/ContinuousFunction>`_)
- Martin Jul (`@mjul <https://github.com/mjul>`_)
- Joe Alcorn (`@buttscicles <https://github.com/buttscicles>`_)

View File

@@ -3,6 +3,46 @@
Release History
---------------
2.4.3 (2014-10-06)
++++++++++++++++++
**Bugfixes**
- Unicode URL improvements for Python 2.
- Re-order JSON param for backwards compat.
- Automatically defrag authentication schemes from host/pass URIs. (`#2249 <https://github.com/kennethreitz/requests/issues/2249>`_)
2.4.2 (2014-10-05)
++++++++++++++++++
**Improvements**
- FINALLY! Add json parameter for uploads! (`#2258 <https://github.com/kennethreitz/requests/pull/2258>`_)
- Support for bytestring URLs on Python 3.x (`#2238 <https://github.com/kennethreitz/requests/pull/2238>`_)
**Bugfixes**
- Avoid getting stuck in a loop (`#2244 <https://github.com/kennethreitz/requests/pull/2244>`_)
- Multiple calls to iter* fail with unhelpful error. (`#2240 <https://github.com/kennethreitz/requests/issues/2240>`_, `#2241 <https://github.com/kennethreitz/requests/issues/2241>`_)
**Documentation**
- Correct redirection introduction (`#2245 <https://github.com/kennethreitz/requests/pull/2245/>`_)
- Added example of how to send multiple files in one request. (`#2227 <https://github.com/kennethreitz/requests/pull/2227/>`_)
- Clarify how to pass a custom set of CAs (`#2248 <https://github.com/kennethreitz/requests/pull/2248/>`_)
2.4.1 (2014-09-09)
++++++++++++++++++
- Now has a "security" package extras set, ``$ pip install requests[security]``
- Requests will now use Certifi if it is available.
- Capture and re-raise urllib3 ProtocolError
- Bugfix for responses that attempt to redirect to themselves forever (wtf?).
2.4.0 (2014-08-29)
++++++++++++++++++

View File

@@ -60,6 +60,8 @@ Exceptions
.. autoexception:: requests.exceptions.HTTPError
.. autoexception:: requests.exceptions.URLRequired
.. autoexception:: requests.exceptions.TooManyRedirects
.. autoexception:: requests.exceptions.ConnectTimeout
.. autoexception:: requests.exceptions.ReadTimeout
.. autoexception:: requests.exceptions.Timeout
@@ -247,29 +249,11 @@ API Changes
requests.get("http://example.org", proxies=proxies)
Behavioral Changes
~~~~~~~~~~~~~~~~~~
Behavioural Changes
~~~~~~~~~~~~~~~~~~~~~~~
* Keys in the ``headers`` dictionary are now native strings on all Python
versions, i.e. bytestrings on Python 2 and unicode on Python 3. If the
keys are not native strings (unicode on Python2 or bytestrings on Python 3)
they will be converted to the native string type assuming UTF-8 encoding.
* Timeouts behave slightly differently. On streaming requests, the timeout
only applies to the connection attempt. On regular requests, the timeout
is applied to the connection process and on to all attempts to read data from
the underlying socket. It does *not* apply to the total download time for the
request.
::
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
# One second timeout for the connection attempt
# Unlimited time to download the tarball
r = requests.get(tarball_url, stream=True, timeout=1)
# One second timeout for the connection attempt
# Another full second timeout to download the tarball
r = requests.get(tarball_url, timeout=1)

View File

@@ -15,7 +15,7 @@ If your question is less than 140 characters, feel free to send a tweet to
File an Issue
-------------
If you notice some unexpected behavior in Requests, or want to see support
If you notice some unexpected behaviour in Requests, or want to see support
for a new feature,
`file an issue on GitHub <https://github.com/kennethreitz/requests/issues>`_.

View File

@@ -24,8 +24,7 @@ Development Dependencies
You'll need to install py.test in order to run the Requests' test suite::
$ pip install -r requirements.txt
$ invoke test
py.test
$ py.test
platform darwin -- Python 2.7.3 -- pytest-2.3.4
collected 25 items

View File

@@ -47,8 +47,8 @@ Testimonials
Her Majesty's Government, Amazon, Google, Twilio, Runscope, Mozilla, Heroku,
PayPal, NPR, Obama for America, Transifex, Native Instruments, The Washington
Post, Twitter, SoundCloud, Kippt, Readability, Sony, and Federal US Institutions
use Requests internally. It has been downloaded over 21,000,000 times from PyPI.
Post, Twitter, SoundCloud, Kippt, Readability, Sony, and Federal US Institutions that prefer to be unnamed
use Requests internally. It has been downloaded over 23,000,000 times from PyPI.
**Armin Ronacher**
Requests is the perfect example how beautiful an API can be with the

View File

@@ -166,7 +166,7 @@ I don't have SSL setup on this domain, so it fails. Excellent. GitHub does thoug
>>> requests.get('https://github.com', verify=True)
<Response [200]>
You can also pass ``verify`` the path to a CA_BUNDLE file for private certs. You can also set the ``REQUESTS_CA_BUNDLE`` environment variable.
You can pass ``verify`` the path to a CA_BUNDLE file with certificates of trusted CAs. This list of trusted CAs can also be specified through the ``REQUESTS_CA_BUNDLE`` environment variable.
Requests can also ignore verifying the SSL certificate if you set ``verify`` to False.
@@ -194,7 +194,7 @@ Body Content Workflow
---------------------
By default, when you make a request, the body of the response is downloaded
immediately. You can override this behavior and defer downloading the response
immediately. You can override this behaviour and defer downloading the response
body until you access the :class:`Response.content <requests.Response.content>`
attribute with the ``stream`` parameter::
@@ -267,6 +267,30 @@ a length) for your body::
requests.post('http://some.url/chunked', data=gen())
POST Multiple Multipart-Encoded Files
-------------------------------------
You can send multiple files in one request. For example, suppose you want to
upload image files to an HTML form with a multiple file field 'images':
<input type="file" name="images" multiple="true" required="true"/>
To do that, just set files to a list of tuples of (form_field_name, file_info):
>>> url = 'http://httpbin.org/post'
>>> multiple_files = [('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
>>> r = requests.post(url, files=multiple_files)
>>> r.text
{
...
'files': {'images': 'data:image/png;base64,iVBORw ....'}
'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a',
...
}
Event Hooks
-----------
@@ -741,3 +765,21 @@ coffee.
r = requests.get('https://github.com', timeout=None)
.. _`connect()`: http://linux.die.net/man/2/connect
CA Certificates
---------------
By default Requests bundles a set of root CAs that it trusts, sourced from the
`Mozilla trust store`_. However, these are only updated once for each Requests
version. This means that if you pin a Requests version your certificates can
become extremely out of date.
From Requests version 2.4.0 onwards, Requests will attempt to use certificates
from `certifi`_ if it is present on the system. This allows for users to update
their trusted certificates without having to change the code that runs on their
system.
For the sake of security we recommend upgrading certifi frequently!
.. _certifi: http://certifi.io/
.. _Mozilla trust store: https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt

View File

@@ -31,7 +31,7 @@ timeline ::
>>> r = requests.get('https://api.github.com/events')
Now, we have a :class:`Request <requests.Request>` object called ``r``. We can
Now, we have a :class:`Response <requests.Response>` object called ``r``. We can
get all the information we need from this object.
Requests' simple API means that all forms of HTTP request are as obvious. For
@@ -81,7 +81,7 @@ We can read the content of the server's response. Consider the GitHub timeline
again::
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r = requests.get('https://api.github.com/events')
>>> r.text
u'[{"repository":{"open_issues":0,"url":"https://github.com/...
@@ -134,7 +134,7 @@ JSON Response Content
There's also a builtin JSON decoder, in case you're dealing with JSON data::
>>> import requests
>>> r = requests.get('https://github.com/timeline.json')
>>> r = requests.get('https://api.github.com/events')
>>> r.json()
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
@@ -150,7 +150,7 @@ In the rare case that you'd like to get the raw socket response from the
server, you can access ``r.raw``. If you want to do this, make sure you set
``stream=True`` in your initial request. Once you do, you can do this::
>>> r = requests.get('https://github.com/timeline.json', stream=True)
>>> r = requests.get('https://api.github.com/events', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
@@ -270,6 +270,9 @@ support this, but there is a separate package which does -
``requests-toolbelt``. You should read `the toolbelt's documentation
<https://toolbelt.rtfd.org>`_ for more details about how to use it.
For sending multiple files in one request refer to the :ref:`advanced <advanced>`
section.
Response Status Codes
---------------------
@@ -369,9 +372,9 @@ HEAD.
We can use the ``history`` property of the Response object to track redirection.
The :meth:`Response.history <requests.Response.history>` list contains the
:class:`Request <requests.Request>` objects that were created in order to
:class:`Response <requests.Response>` objects that were created in order to
complete the request. The list is sorted from the oldest to the most recent
request.
response.
For example, GitHub redirects all HTTP requests to HTTPS::

View File

@@ -13,7 +13,7 @@ Requests is an HTTP library, written in Python, for human beings. Basic GET
usage:
>>> import requests
>>> r = requests.get('http://python.org')
>>> r = requests.get('https://www.python.org')
>>> r.status_code
200
>>> 'Python is a programming language' in r.content
@@ -22,7 +22,7 @@ usage:
... or POST:
>>> payload = dict(key1='value1', key2='value2')
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> r = requests.post('http://httpbin.org/post', data=payload)
>>> print(r.text)
{
...
@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
"""
__title__ = 'requests'
__version__ = '2.4.0'
__build__ = 0x020400
__version__ = '2.4.3'
__build__ = 0x020403
__author__ = 'Kenneth Reitz'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2014 Kenneth Reitz'

View File

@@ -15,14 +15,15 @@ from .packages.urllib3 import Retry
from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
from .packages.urllib3.response import HTTPResponse
from .packages.urllib3.util import Timeout as TimeoutSauce
from .compat import urlparse, basestring, urldefrag
from .compat import urlparse, basestring
from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
prepend_scheme_if_needed, get_auth_from_url)
prepend_scheme_if_needed, get_auth_from_url, urldefragauth)
from .structures import CaseInsensitiveDict
from .packages.urllib3.exceptions import ConnectTimeoutError
from .packages.urllib3.exceptions import HTTPError as _HTTPError
from .packages.urllib3.exceptions import MaxRetryError
from .packages.urllib3.exceptions import ProxyError as _ProxyError
from .packages.urllib3.exceptions import ProtocolError
from .packages.urllib3.exceptions import ReadTimeoutError
from .packages.urllib3.exceptions import SSLError as _SSLError
from .cookies import extract_cookies_to_jar
@@ -269,7 +270,7 @@ class HTTPAdapter(BaseAdapter):
proxy = proxies.get(scheme)
if proxy and scheme != 'https':
url, _ = urldefrag(request.url)
url = urldefragauth(request.url)
else:
url = request.path_url
@@ -316,8 +317,10 @@ class HTTPAdapter(BaseAdapter):
:param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
:param stream: (optional) Whether to stream the request content.
:param timeout: (optional) The timeout on the request.
:type timeout: float or tuple (connect timeout, read timeout), eg (3.1, 20)
:param timeout: (optional) How long to wait for the server to send
data before giving up, as a float, or a (`connect timeout, read
timeout <user/advanced.html#timeouts>`_) tuple.
:type timeout: float or tuple
:param verify: (optional) Whether to verify SSL certificates.
:param cert: (optional) Any user-provided SSL certificate to be trusted.
:param proxies: (optional) The proxies dictionary to apply to the request.
@@ -400,8 +403,8 @@ class HTTPAdapter(BaseAdapter):
# All is well, return the connection to the pool.
conn._put_conn(low_conn)
except socket.error as sockerr:
raise ConnectionError(sockerr, request=request)
except (ProtocolError, socket.error) as err:
raise ConnectionError(err, request=request)
except MaxRetryError as e:
if isinstance(e.reason, ConnectTimeoutError):

View File

@@ -22,12 +22,17 @@ def request(method, url, **kwargs):
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary or bytes to be sent in the query string for the :class:`Request`.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
:param files: (optional) Dictionary of 'name': file-like-objects (or {'name': ('filename', fileobj)}) for multipart encoding upload.
:param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': ('filename', fileobj)}``) for multipart encoding upload.
:param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) Float describing the timeout of the request in seconds.
:param timeout: (optional) How long to wait for the server to send data
before giving up, as a float, or a (`connect timeout, read timeout
<user/advanced.html#timeouts>`_) tuple.
:type timeout: float or tuple
:param allow_redirects: (optional) Boolean. Set to True if POST/PUT/DELETE redirect following is allowed.
:type allow_redirects: bool
:param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
:param verify: (optional) if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
:param stream: (optional) if ``False``, the response content will be immediately downloaded.
@@ -77,15 +82,16 @@ def head(url, **kwargs):
return request('head', url, **kwargs)
def post(url, data=None, **kwargs):
def post(url, data=None, json=None, **kwargs):
"""Sends a POST request. Returns :class:`Response` object.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
"""
return request('post', url, data=data, **kwargs)
return request('post', url, data=data, json=json, **kwargs)
def put(url, data=None, **kwargs):

View File

@@ -46,15 +46,16 @@ class SSLError(ConnectionError):
class Timeout(RequestException):
"""The request timed out.
Catching this error will catch both :exc:`ConnectTimeout` and
:exc:`ReadTimeout` errors.
Catching this error will catch both
:exc:`~requests.exceptions.ConnectTimeout` and
:exc:`~requests.exceptions.ReadTimeout` errors.
"""
class ConnectTimeout(ConnectionError, Timeout):
"""The request timed out while trying to connect to the server.
"""The request timed out while trying to connect to the remote server.
Requests that produce this error are safe to retry
Requests that produced this error are safe to retry.
"""
@@ -88,3 +89,6 @@ class ChunkedEncodingError(RequestException):
class ContentDecodingError(RequestException, BaseHTTPError):
"""Failed to decode response content"""
class StreamConsumedError(RequestException, TypeError):
"""The content for this response was already consumed"""

View File

@@ -22,8 +22,9 @@ from .packages.urllib3.util import parse_url
from .packages.urllib3.exceptions import (
DecodeError, ReadTimeoutError, ProtocolError)
from .exceptions import (
HTTPError, RequestException, MissingSchema, InvalidURL,
ChunkedEncodingError, ContentDecodingError, ConnectionError)
HTTPError, RequestException, 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,
@@ -46,6 +47,8 @@ DEFAULT_REDIRECT_LIMIT = 30
CONTENT_CHUNK_SIZE = 10 * 1024
ITER_CHUNK_SIZE = 512
json_dumps = json.dumps
class RequestEncodingMixin(object):
@property
@@ -189,7 +192,8 @@ class Request(RequestHooksMixin):
:param url: URL to send.
:param headers: dictionary of headers to send.
:param files: dictionary of {filename: fileobject} files to multipart upload.
:param data: the body to attach the request. If a dictionary is provided, form-encoding will take place.
:param data: the body to attach to the request. If a dictionary is provided, form-encoding will take place.
:param json: json for the body to attach to the request (if data is not specified).
:param params: dictionary of URL parameters to append to the URL.
:param auth: Auth handler or (user, pass) tuple.
:param cookies: dictionary or CookieJar of cookies to attach to this request.
@@ -212,7 +216,8 @@ class Request(RequestHooksMixin):
params=None,
auth=None,
cookies=None,
hooks=None):
hooks=None,
json=None):
# Default empty dicts for dict params.
data = [] if data is None else data
@@ -230,6 +235,7 @@ class Request(RequestHooksMixin):
self.headers = headers
self.files = files
self.data = data
self.json = json
self.params = params
self.auth = auth
self.cookies = cookies
@@ -246,6 +252,7 @@ class Request(RequestHooksMixin):
headers=self.headers,
files=self.files,
data=self.data,
json=self.json,
params=self.params,
auth=self.auth,
cookies=self.cookies,
@@ -289,14 +296,15 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
self.hooks = default_hooks()
def prepare(self, method=None, url=None, headers=None, files=None,
data=None, params=None, auth=None, cookies=None, hooks=None):
data=None, params=None, auth=None, cookies=None, hooks=None,
json=None):
"""Prepares the entire request with the given parameters."""
self.prepare_method(method)
self.prepare_url(url, params)
self.prepare_headers(headers)
self.prepare_cookies(cookies)
self.prepare_body(data, files)
self.prepare_body(data, files, json)
self.prepare_auth(auth, url)
# Note that prepare_auth must be last to enable authentication schemes
# such as OAuth to work on a fully prepared request.
@@ -326,15 +334,18 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
def prepare_url(self, url, params):
"""Prepares the given HTTP URL."""
#: Accept objects that have string representations.
try:
url = unicode(url)
except NameError:
# We're on Python 3.
url = str(url)
except UnicodeDecodeError:
pass
#: We're unable to blindy call unicode/str functions
#: as this will include the bytestring indicator (b'')
#: on python 3.x.
#: https://github.com/kennethreitz/requests/pull/2238
if isinstance(url, bytes):
url = url.decode('utf8')
else:
url = unicode(url) if is_py2 else str(url)
# Don't do any URL preparation for oddball schemes
# Don't do any URL preparation for non-HTTP schemes like `mailto`,
# `data` etc to work around exceptions from `url_parse`, which
# handles RFC 3986 only.
if ':' in url and not url.lower().startswith('http'):
self.url = url
return
@@ -397,7 +408,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
else:
self.headers = CaseInsensitiveDict()
def prepare_body(self, data, files):
def prepare_body(self, data, files, json=None):
"""Prepares the given HTTP body data."""
# Check if file, fo, generator, iterator.
@@ -408,6 +419,10 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
content_type = None
length = None
if json is not None:
content_type = 'application/json'
body = json_dumps(json)
is_stream = all([
hasattr(data, '__iter__'),
not isinstance(data, (basestring, list, tuple, dict))
@@ -433,7 +448,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
if files:
(body, content_type) = self._encode_files(files, data)
else:
if data:
if data and json is None:
body = self._encode_params(data)
if isinstance(data, basestring) or hasattr(data, 'read'):
content_type = None
@@ -443,7 +458,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
self.prepare_content_length(body)
# Add content-type if it wasn't explicitly provided.
if (content_type) and (not 'content-type' in self.headers):
if content_type and ('content-type' not in self.headers):
self.headers['Content-Type'] = content_type
self.body = body
@@ -653,6 +668,8 @@ class Response(object):
self._content_consumed = True
if self._content_consumed and isinstance(self._content, bool):
raise StreamConsumedError()
# simulate reading small chunks of the content
reused_chunks = iter_slices(self._content, chunk_size)

View File

@@ -134,8 +134,8 @@ class SessionRedirectMixin(object):
url = requote_uri(url)
prepared_request.url = to_native_string(url)
# cache the url
if resp.is_permanent_redirect:
# Cache the url, unless it redirects to itself.
if resp.is_permanent_redirect and req.url != prepared_request.url:
self.redirect_cache[req.url] = prepared_request.url
# http://tools.ietf.org/html/rfc7231#section-6.4.4
@@ -271,9 +271,10 @@ class Session(SessionRedirectMixin):
"""
__attrs__ = [
'headers', 'cookies', 'auth', 'timeout', 'proxies', 'hooks',
'params', 'verify', 'cert', 'prefetch', 'adapters', 'stream',
'trust_env', 'max_redirects', 'redirect_cache']
'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify',
'cert', 'prefetch', 'adapters', 'stream', 'trust_env',
'max_redirects', 'redirect_cache'
]
def __init__(self):
@@ -365,6 +366,7 @@ class Session(SessionRedirectMixin):
url=request.url,
files=request.files,
data=request.data,
json=request.json,
headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict),
params=merge_setting(request.params, self.params),
auth=merge_setting(auth, self.auth),
@@ -386,7 +388,8 @@ class Session(SessionRedirectMixin):
hooks=None,
stream=None,
verify=None,
cert=None):
cert=None,
json=None):
"""Constructs a :class:`Request <Request>`, prepares it and sends it.
Returns :class:`Response <Response>` object.
@@ -396,17 +399,22 @@ class Session(SessionRedirectMixin):
string for the :class:`Request`.
:param data: (optional) Dictionary or bytes to send in the body of the
:class:`Request`.
:param json: (optional) json to send in the body of the
:class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the
:class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the
:class:`Request`.
:param files: (optional) Dictionary of 'filename': file-like-objects
:param files: (optional) Dictionary of ``'filename': file-like-objects``
for multipart encoding upload.
:param auth: (optional) Auth tuple or callable to enable
Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) Float describing the timeout of the
request in seconds.
:param allow_redirects: (optional) Boolean. Set to True by default.
:param timeout: (optional) How long to wait for the server to send
data before giving up, as a float, or a (`connect timeout, read
timeout <user/advanced.html#timeouts>`_) tuple.
:type timeout: float or tuple
:param allow_redirects: (optional) Set to True by default.
:type allow_redirects: bool
:param proxies: (optional) Dictionary mapping protocol to the URL of
the proxy.
:param stream: (optional) whether to immediately download the response
@@ -426,6 +434,7 @@ class Session(SessionRedirectMixin):
headers = headers,
files = files,
data = data or {},
json = json,
params = params or {},
auth = auth,
cookies = cookies,
@@ -479,15 +488,16 @@ class Session(SessionRedirectMixin):
kwargs.setdefault('allow_redirects', False)
return self.request('HEAD', url, **kwargs)
def post(self, url, data=None, **kwargs):
def post(self, url, data=None, json=None, **kwargs):
"""Sends a POST request. Returns :class:`Response` object.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
"""
return self.request('POST', url, data=data, **kwargs)
return self.request('POST', url, data=data, json=json, **kwargs)
def put(self, url, data=None, **kwargs):
"""Sends a PUT request. Returns :class:`Response` object.
@@ -532,8 +542,13 @@ class Session(SessionRedirectMixin):
if not isinstance(request, PreparedRequest):
raise ValueError('You can only send PreparedRequests.')
checked_urls = set()
while request.url in self.redirect_cache:
request.url = self.redirect_cache.get(request.url)
checked_urls.add(request.url)
new_url = self.redirect_cache.get(request.url)
if new_url in checked_urls:
break
request.url = new_url
# Set up variables needed for resolve_redirects and dispatching of hooks
allow_redirects = kwargs.pop('allow_redirects', True)

View File

@@ -351,10 +351,7 @@ def get_unicode_from_response(r):
Tried:
1. charset from content-type
2. every encodings from ``<meta ... charset=XXX>``
3. fall back and replace all unicode characters
2. fall back and replace all unicode characters
"""
@@ -555,7 +552,7 @@ def default_headers():
'User-Agent': default_user_agent(),
'Accept-Encoding': ', '.join(('gzip', 'deflate')),
'Accept': '*/*',
'Connection': 'keep-alive'
'Connection': 'keep-alive',
})
@@ -672,3 +669,18 @@ def to_native_string(string, encoding='ascii'):
out = string.decode(encoding)
return out
def urldefragauth(url):
"""
Given a url remove the fragment and the authentication part
"""
scheme, netloc, path, params, query, fragment = urlparse(url)
# see func:`prepend_scheme_if_needed`
if not netloc:
netloc, path = path, netloc
netloc = netloc.rsplit('@', 1)[-1]
return urlunparse((scheme, netloc, path, params, query, ''))

View File

@@ -1,5 +1,4 @@
py==1.4.12
pytest==2.3.4
pytest-cov==1.6
invoke==0.2.0
wheel

View File

@@ -5,6 +5,8 @@ import sys
import requests
from codecs import open
try:
from setuptools import setup
except ImportError:
@@ -25,11 +27,11 @@ packages = [
'requests.packages.urllib3.packages.ssl_match_hostname',
]
requires = ['certifi']
requires = []
with open('README.rst') as f:
with open('README.rst', 'r', 'utf-8') as f:
readme = f.read()
with open('HISTORY.rst') as f:
with open('HISTORY.rst', 'r', 'utf-8') as f:
history = f.read()
setup(
@@ -60,4 +62,7 @@ setup(
'Programming Language :: Python :: 3.4'
),
extras_require={
'security': ['pyOpenSSL', 'ndg-httpsclient', 'pyasn1'],
},
)

View File

@@ -18,8 +18,9 @@ from requests.auth import HTTPDigestAuth, _basic_auth_str
from requests.compat import (
Morsel, cookielib, getproxies, str, urljoin, urlparse, is_py3, builtin_str)
from requests.cookies import cookiejar_from_dict, morsel_to_cookie
from requests.exceptions import (InvalidURL, MissingSchema, ConnectTimeout,
ReadTimeout, ConnectionError, Timeout)
from requests.exceptions import (ConnectionError, ConnectTimeout,
InvalidSchema, InvalidURL, MissingSchema,
ReadTimeout, Timeout)
from requests.models import PreparedRequest
from requests.structures import CaseInsensitiveDict
from requests.sessions import SessionRedirectMixin
@@ -78,6 +79,12 @@ class RequestsTestCase(unittest.TestCase):
def test_invalid_url(self):
with pytest.raises(MissingSchema):
requests.get('hiwpefhipowhefopw')
with pytest.raises(InvalidSchema):
requests.get('localhost:3128')
with pytest.raises(InvalidSchema):
requests.get('localhost.localdomain:3128/')
with pytest.raises(InvalidSchema):
requests.get('10.122.1.1:3128/')
with pytest.raises(InvalidURL):
requests.get('http://')
@@ -286,6 +293,14 @@ class RequestsTestCase(unittest.TestCase):
r = s.get(url)
assert r.status_code == 200
def test_connection_error(self):
"""Connecting to an unknown domain should raise a ConnectionError"""
with pytest.raises(ConnectionError):
requests.get("http://fooobarbangbazbing.httpbin.org")
with pytest.raises(ConnectionError):
requests.get("http://httpbin.org:1")
def test_basicauth_with_netrc(self):
auth = ('user', 'pass')
wrong_auth = ('wronguser', 'wrongpass')
@@ -576,6 +591,12 @@ class RequestsTestCase(unittest.TestCase):
assert resp.json()['headers'][
'Dummy-Auth-Test'] == 'dummy-auth-test-ok'
def test_prepare_request_with_bytestring_url(self):
req = requests.Request('GET', b'https://httpbin.org/')
s = requests.Session()
prep = s.prepare_request(req)
assert prep.url == "https://httpbin.org/"
def test_links(self):
r = requests.Response()
r.headers = {
@@ -907,7 +928,7 @@ class RequestsTestCase(unittest.TestCase):
assert p.headers['Content-Length'] == length
def test_oddball_schemes_dont_check_URLs(self):
def test_nonhttp_schemes_dont_check_URLs(self):
test_urls = (
'data:image/gif;base64,R0lGODlhAQABAHAAACH5BAUAAAAALAAAAAABAAEAAAICRAEAOw==',
'file:///etc/passwd',
@@ -986,6 +1007,15 @@ class RequestsTestCase(unittest.TestCase):
assert item.history == total[0:i]
i=i+1
def test_json_param_post_content_type_works(self):
r = requests.post(
httpbin('post'),
json={'life': 42}
)
assert r.status_code == 200
assert 'application/json' in r.request.headers['Content-Type']
assert {'life': 42} == r.json()['json']
class TestContentEncodingDetection(unittest.TestCase):
@@ -1477,5 +1507,13 @@ def test_prepared_request_complete_copy():
)
assert_copy(p, p.copy())
def test_prepare_unicode_url():
p = PreparedRequest()
p.prepare(
method='GET',
url=u('http://www.example.com/üniçø∂é')
)
assert_copy(p, p.copy())
if __name__ == '__main__':
unittest.main()