Compare commits
51 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b5ff69201 | ||
|
|
0665129008 | ||
|
|
afd6482219 | ||
|
|
a23f22e5dc | ||
|
|
e00e50d01a | ||
|
|
1960c3c29d | ||
|
|
08f66a99b1 | ||
|
|
ab64052642 | ||
|
|
25a9c9fb22 | ||
|
|
f0beed8686 | ||
|
|
5a7d461230 | ||
|
|
d45eb53bc7 | ||
|
|
911e8aec8d | ||
|
|
9f89ebe0de | ||
|
|
526a0befc7 | ||
|
|
f0fe551dc9 | ||
|
|
f8e2d0e732 | ||
|
|
fcccc82282 | ||
|
|
3ddcc99131 | ||
|
|
70faca2a14 | ||
|
|
5f9fecd3aa | ||
|
|
6e780fad6d | ||
|
|
28b706da83 | ||
|
|
aa3347b2a3 | ||
|
|
f8a59c3e6f | ||
|
|
484916066a | ||
|
|
b3fbc810d2 | ||
|
|
1539d17366 | ||
|
|
a158abfa15 | ||
|
|
7d085b188c | ||
|
|
aaa3bf16a9 | ||
|
|
22a1f0917b | ||
|
|
78f48aef8f | ||
|
|
7b1b9df423 | ||
|
|
e23343ab17 | ||
|
|
b8affd9520 | ||
|
|
1790b1df17 | ||
|
|
60b4843678 | ||
|
|
0b42772663 | ||
|
|
a49db50b4a | ||
|
|
bfef8d99c8 | ||
|
|
dd271782e8 | ||
|
|
09da1921ff | ||
|
|
0769ee3b6d | ||
|
|
05de270d7a | ||
|
|
f1ba27faa2 | ||
|
|
8cb904b49d | ||
|
|
7e594eb121 | ||
|
|
4966d9c714 | ||
|
|
14da5cf180 | ||
|
|
6acce57271 |
@@ -7,3 +7,5 @@ env: HTTPBIN_URL=http://httpbin.org/
|
||||
script: make test
|
||||
install:
|
||||
- make test-deps
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
@@ -117,3 +117,4 @@ Patches and Suggestions
|
||||
- Stephen Zhuang (everbird)
|
||||
- Martijn Pieters
|
||||
- Jonatan Heyman
|
||||
- David Bonner <dbonner@gmail.com> @rascalking
|
||||
|
||||
@@ -74,7 +74,7 @@ Contribute
|
||||
----------
|
||||
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug. There is a Contributor Friendly tag for issues that should be ideal for people who are not very familiar with the codebase yet.
|
||||
#. Fork `the repository`_ on Github to start making your changes to the **develop** branch (or branch off of it).
|
||||
#. Fork `the repository`_ on Github to start making your changes to the **master** branch (or branch off of it).
|
||||
#. Write a test which shows that the bug was fixed or that the feature works as expected.
|
||||
#. Send a pull request and bug the maintainer until it gets merged and published. :) Make sure to add yourself to AUTHORS_.
|
||||
|
||||
|
||||
71
docs/api.rst
71
docs/api.rst
@@ -1,7 +1,7 @@
|
||||
.. _api:
|
||||
|
||||
API
|
||||
===
|
||||
Developer Interface
|
||||
===================
|
||||
|
||||
.. module:: requests
|
||||
|
||||
@@ -18,14 +18,6 @@ They all return an instance of the :class:`Response <Response>` object.
|
||||
|
||||
.. autofunction:: request
|
||||
|
||||
---------------------
|
||||
|
||||
|
||||
.. autoclass:: Response
|
||||
:inherited-members:
|
||||
|
||||
---------------------
|
||||
|
||||
.. autofunction:: head
|
||||
.. autofunction:: get
|
||||
.. autofunction:: post
|
||||
@@ -34,15 +26,22 @@ They all return an instance of the :class:`Response <Response>` object.
|
||||
.. autofunction:: delete
|
||||
|
||||
|
||||
-----------------
|
||||
Lower-Level Classes
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. autofunction:: session
|
||||
.. autoclass:: requests.Request
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: Response
|
||||
:inherited-members:
|
||||
|
||||
Request Sessions
|
||||
----------------
|
||||
|
||||
.. autoclass:: Session
|
||||
:inherited-members:
|
||||
|
||||
|
||||
|
||||
Exceptions
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -55,41 +54,6 @@ Exceptions
|
||||
.. autoexception:: TooManyRedirects
|
||||
|
||||
|
||||
.. _configurations:
|
||||
|
||||
Configurations
|
||||
--------------
|
||||
|
||||
.. automodule:: requests.defaults
|
||||
|
||||
|
||||
.. _async:
|
||||
|
||||
Async
|
||||
-----
|
||||
|
||||
.. module:: requests.async
|
||||
|
||||
|
||||
.. autofunction:: map
|
||||
.. autofunction:: request
|
||||
.. autofunction:: head
|
||||
.. autofunction:: get
|
||||
.. autofunction:: post
|
||||
.. autofunction:: put
|
||||
.. autofunction:: patch
|
||||
.. autofunction:: delete
|
||||
|
||||
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
These functions are used internally, but may be useful outside of
|
||||
Requests.
|
||||
|
||||
.. module:: requests.utils
|
||||
|
||||
Status Code Lookup
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
@@ -123,14 +87,6 @@ Encodings
|
||||
.. autofunction:: decode_gzip
|
||||
|
||||
|
||||
Internals
|
||||
---------
|
||||
|
||||
These items are an internal component to Requests, and should never be
|
||||
seen by the end user (developer). This part of the API documentation
|
||||
exists for those who are extending the functionality of Requests.
|
||||
|
||||
|
||||
Classes
|
||||
~~~~~~~
|
||||
|
||||
@@ -140,6 +96,9 @@ Classes
|
||||
.. autoclass:: requests.Request
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: requests.PreparedRequest
|
||||
:inherited-members:
|
||||
|
||||
.. _sessionapi:
|
||||
|
||||
.. autoclass:: requests.Session
|
||||
|
||||
@@ -54,30 +54,9 @@ Python 3 Support?
|
||||
Yes! Here's a list of Python platforms that are officially
|
||||
supported:
|
||||
|
||||
* cPython 2.6
|
||||
* cPython 2.7
|
||||
* cPython 3.1
|
||||
* cPython 3.2
|
||||
* PyPy-c 1.4
|
||||
* PyPy-c 1.5
|
||||
* PyPy-c 1.6
|
||||
* PyPy-c 1.7
|
||||
|
||||
|
||||
Keep-alive Support?
|
||||
-------------------
|
||||
|
||||
Yep!
|
||||
|
||||
|
||||
Proxy Support?
|
||||
--------------
|
||||
|
||||
You bet!
|
||||
|
||||
|
||||
SSL Verification?
|
||||
-----------------
|
||||
|
||||
Absolutely.
|
||||
|
||||
* Python 2.6
|
||||
* Python 2.7
|
||||
* Python 3.1
|
||||
* Python 3.2
|
||||
* Python 3.3
|
||||
* PyPy 1.9
|
||||
|
||||
@@ -1,27 +1,3 @@
|
||||
Modules
|
||||
=======
|
||||
|
||||
- `requests-oauth <https://github.com/maraujop/requests-oauth>`_, adds OAuth support to Requests.
|
||||
- `rauth <https://github.com/litl/rauth>`_, an alternative to requests-oauth, supports OAuth versions 1.0 and 2.0.
|
||||
- `FacePy <https://github.com/jgorset/facepy>`_, a Python wrapper to the Facebook API.
|
||||
- `robotframework-requests <https://github.com/bulkan/robotframework-requests>`_, a Robot Framework API wrapper.
|
||||
- `fullerene <https://github.com/bitprophet/fullerene>`_, a Graphite Dashboard.
|
||||
- `urbanairship-python <https://github.com/benjaminws/urbanairship-python>`_, a fork of the Urban Airship API wrapper.
|
||||
- `WhitespaceBot <https://github.com/Gunio/WhitespaceBot/>`_, a project that automatically forks repos, strips trailing whitespace, and sends a pull request.
|
||||
- `python-rexster <https://github.com/CulturePlex/python-rexster>`_, Rexter client that provides a simple interface for graph databases.
|
||||
- `daikon <https://github.com/neogenix/daikon>`_, a CLI for ElasticSearch.
|
||||
|
||||
Articles & Talks
|
||||
================
|
||||
- `Python for the Web <http://gun.io/blog/python-for-the-web/>`_ teaches how to use Python to interact with the web, using Requests.
|
||||
- `Daniel Greenfield's Review of Requests <http://pydanny.blogspot.com/2011/05/python-http-requests-for-humans.html>`_
|
||||
- `My 'Python for Humans' talk <http://python-for-humans.heroku.com>`_ ( `audio <http://codeconf.s3.amazonaws.com/2011/pycodeconf/talks/PyCodeConf2011%20-%20Kenneth%20Reitz.m4a>`_ )
|
||||
- `Issac Kelly's 'Consuming Web APIs' talk <http://issackelly.github.com/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
|
||||
- `Blog post about Requests via Yum <http://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
|
||||
- `Russian blog post introducing Requests <http://habrahabr.ru/blogs/python/126262/>`_
|
||||
- `French blog post introducing Requests <http://www.nicosphere.net/requests-urllib2-de-python-simplifie-2432/>`_
|
||||
|
||||
|
||||
Integrations
|
||||
============
|
||||
|
||||
@@ -36,29 +12,22 @@ To give it a try, simply::
|
||||
|
||||
import requests
|
||||
|
||||
Python for iOS
|
||||
--------------
|
||||
|
||||
Managed Packages
|
||||
Requests is built into the wonderful `Python for iOS <https://itunes.apple.com/us/app/python-2.7-for-ios/id485729872?mt=Python8>`_ runtime!
|
||||
|
||||
To give it a try, simply::
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
Articles & Talks
|
||||
================
|
||||
|
||||
Requests is available in a number of popular package formats. Of course,
|
||||
the ideal way to install Requests is via The Cheeseshop.
|
||||
|
||||
|
||||
Ubuntu & Debian
|
||||
---------------
|
||||
|
||||
Requests is available installed as a Debian package! Debian Etch Ubuntu, since Oneiric::
|
||||
|
||||
$ apt-get install python-requests
|
||||
|
||||
|
||||
Fedora and RedHat
|
||||
-----------------
|
||||
|
||||
You can easily install Requests v0.6.1 with yum on rpm-based systems::
|
||||
|
||||
$ yum install python-requests
|
||||
|
||||
|
||||
|
||||
|
||||
- `Python for the Web <http://gun.io/blog/python-for-the-web/>`_ teaches how to use Python to interact with the web, using Requests.
|
||||
- `Daniel Greenfield's Review of Requests <http://pydanny.blogspot.com/2011/05/python-http-requests-for-humans.html>`_
|
||||
- `My 'Python for Humans' talk <http://python-for-humans.heroku.com>`_ ( `audio <http://codeconf.s3.amazonaws.com/2011/pycodeconf/talks/PyCodeConf2011%20-%20Kenneth%20Reitz.m4a>`_ )
|
||||
- `Issac Kelly's 'Consuming Web APIs' talk <http://issackelly.github.com/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
|
||||
- `Blog post about Requests via Yum <http://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
|
||||
- `Russian blog post introducing Requests <http://habrahabr.ru/blogs/python/126262/>`_
|
||||
- `French blog post introducing Requests <http://www.nicosphere.net/requests-urllib2-de-python-simplifie-2432/>`_
|
||||
|
||||
41
docs/dev/philosophy.rst
Normal file
41
docs/dev/philosophy.rst
Normal file
@@ -0,0 +1,41 @@
|
||||
Development Philosophy
|
||||
======================
|
||||
|
||||
Requests is an open but opinionated library, created by an open but opinionated developer.
|
||||
|
||||
|
||||
Benevolent Dictator
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
`Kenneth Reitz <http://kennethreitz.org>`_ is the BDFL. He has final say in any decision related to Requests.
|
||||
|
||||
Values
|
||||
~~~~~~
|
||||
|
||||
- Simplicity is always better than functionality.
|
||||
- Listen to everyone, then disregard it.
|
||||
- The API is all that matters. Everything else is secondary.
|
||||
- Fit the 90% use-case. Ignore the nay-sayers.
|
||||
|
||||
Semantic Versioning
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For many years, the open source community has been plagued with version number dystonia. Numbers vary so greatly from project to project, they are practically meaningless.
|
||||
|
||||
Requests uses `Semantic Versioning <http://semver.org>`_. This specification seeks to put an end to this madness with a small set of practical guidelines for you and your colleagues to use in your next project.
|
||||
|
||||
Standard Library?
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Requests has no *active* plans to be included in the standard library. This decision has been discussed at length with Guido as well as numerous core developers.
|
||||
|
||||
Essentially, the standard library is where a library goes to die. It is appropriate for a module to be included when active development is no longer necessary.
|
||||
|
||||
Requests just reached v1.0.0. This huge milestone marks a major step in the right direction.
|
||||
|
||||
Linux Distro Packages
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Distributions have been made for many Linux repositories, including: Ubuntu, Debian, RHEL, and Arch.
|
||||
|
||||
These distributions are often aggressive forks. They are discouraged and not supported.
|
||||
@@ -6,38 +6,44 @@ Requests is under active development, and contributions are more than welcome!
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a feature idea or a bug.
|
||||
There is a Contributor Friendly tag for issues that should be ideal for people who are not very
|
||||
familiar with the codebase yet.
|
||||
#. Fork `the repository <https://github.com/kennethreitz/requests>`_ on Github to start making your
|
||||
changes to the **develop** branch (or branch off of it).
|
||||
#. Fork `the repository <https://github.com/kennethreitz/requests>`_ on Github andstart making your
|
||||
changes to a new branch.
|
||||
#. Write a test which shows that the bug was fixed or that the feature works as expected.
|
||||
#. Send a pull request and bug the maintainer until it gets merged and published. :)
|
||||
Make sure to add yourself to `AUTHORS <https://github.com/kennethreitz/requests/blob/develop/AUTHORS.rst>`_.
|
||||
Make sure to add yourself to `AUTHORS <https://github.com/kennethreitz/requests/blob/master/AUTHORS.rst>`_.
|
||||
|
||||
Development dependencies
|
||||
Development Dependencies
|
||||
------------------------
|
||||
|
||||
You'll need to install ``gunicorn`` and ``httpbin`` and various other dependencies in
|
||||
order to run requests' test suite::
|
||||
You'll need to install py.test in order to run the Requests' test suite::
|
||||
|
||||
$ virtualenv env
|
||||
$ . env/bin/activate
|
||||
$ make
|
||||
$ make test-deps
|
||||
$ make test
|
||||
py.test
|
||||
platform darwin -- Python 2.7.3 -- pytest-2.3.4
|
||||
collected 25 items
|
||||
|
||||
The ``Makefile`` has various useful targets for testing. For example, if you
|
||||
want to see how your pull request will behave with Travis-CI you would run
|
||||
``make travis``.
|
||||
test_requests.py .........................
|
||||
25 passed in 3.50 seconds
|
||||
|
||||
Versions of Python to Test On
|
||||
-----------------------------
|
||||
Runtime Environments
|
||||
--------------------
|
||||
|
||||
Officially (as of 26-Nov-2012), requests supports python 2.6-3.3. In the
|
||||
future, support for 3.1 and 3.2 may be dropped. In general you will need to
|
||||
test on at least one python 2 and one python 3 version. You can also set up
|
||||
Travis CI for your own fork before you submit a pull request so that you are
|
||||
assured your fork works. To use Travis CI for your fork and other projects see
|
||||
their `documentation <http://about.travis-ci.org/docs/user/getting-started/>`_.
|
||||
Requests currently supports the following versions of Python:
|
||||
|
||||
What Needs to be Done
|
||||
---------------------
|
||||
- Python 2.6
|
||||
- Python 2.7
|
||||
- Python 3.1
|
||||
- Python 3.2
|
||||
- Python 3.3
|
||||
- PyPy 1.9
|
||||
|
||||
- Documentation needs a roadmap.
|
||||
Support for Python 3.1 and 3.2 may be dropped at any time.
|
||||
|
||||
Google App Engine will never be officially supported. Pull requests for compatiblity will be accepted, as long as they don't complicate the codebase.
|
||||
|
||||
|
||||
Are you crazy?
|
||||
--------------
|
||||
|
||||
- SPDY support would be awesome. No C extensions.
|
||||
|
||||
@@ -38,7 +38,7 @@ Requests takes all of the work out of Python HTTP/1.1 — making your integrati
|
||||
Testimonials
|
||||
------------
|
||||
|
||||
Amazon, Google, Twilio, Mozilla, Heroku, PayPal, NPR, Obama for America, Transifex, Native Instruments, The Washington Post, Twitter, SoundCloud, Kippt, Readability, and Federal US Institutions use Requests internally. It has been downloaded over 1,000,000 times from PyPI.
|
||||
Amazon, Google, Twilio, Mozilla, Heroku, PayPal, NPR, Obama for America, Transifex, Native Instruments, The Washington Post, Twitter, SoundCloud, Kippt, Readability, and Federal US Institutions use Requests internally. It has been downloaded over 1,500,000 times from PyPI.
|
||||
|
||||
**Armin Ronacher**
|
||||
Requests is the perfect example how beautiful an API can be with the
|
||||
@@ -73,6 +73,7 @@ Requests is ready for today's web.
|
||||
- Multipart File Uploads
|
||||
- Connection Timeouts
|
||||
- ``.netrc`` support
|
||||
- Python 2.6—3.3
|
||||
- Thread-safe.
|
||||
|
||||
|
||||
@@ -119,8 +120,8 @@ this part of the documentation is for you.
|
||||
api
|
||||
|
||||
|
||||
Developer Guide
|
||||
---------------
|
||||
Contributor Guide
|
||||
-----------------
|
||||
|
||||
If you want to contribute to the project, this part of the documentation is for
|
||||
you.
|
||||
@@ -128,6 +129,7 @@ you.
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
dev/philosophy
|
||||
dev/internals
|
||||
dev/todo
|
||||
dev/authors
|
||||
|
||||
@@ -17,7 +17,7 @@ A session object has all the methods of the main Requests API.
|
||||
|
||||
Let's persist some cookies across requests::
|
||||
|
||||
s = requests.session()
|
||||
s = requests.Session()
|
||||
|
||||
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
|
||||
r = s.get("http://httpbin.org/cookies")
|
||||
@@ -26,15 +26,15 @@ Let's persist some cookies across requests::
|
||||
# '{"cookies": {"sessioncookie": "123456789"}}'
|
||||
|
||||
|
||||
Sessions can also be used to provide default data to the request methods::
|
||||
Sessions can also be used to provide default data to the request methods. This
|
||||
is done by providing data to the properties on a session object::
|
||||
|
||||
headers = {'x-test': 'true'}
|
||||
auth = ('user', 'pass')
|
||||
s = requests.Session()
|
||||
s.auth = ('user', 'pass')
|
||||
s.headers.update({'x-test': 'true'})
|
||||
|
||||
with requests.session(auth=auth, headers=headers) as c:
|
||||
|
||||
# both 'x-test' and 'x-test2' are sent
|
||||
c.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
|
||||
# both 'x-test' and 'x-test2' are sent
|
||||
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
|
||||
|
||||
|
||||
Any dictionaries that you pass to a request method will be merged with the session-level values that are set. The method-level parameters override session parameters.
|
||||
@@ -56,11 +56,11 @@ contains all of the information returned by the server and also contains the
|
||||
``Request`` object you created originally. Here is a simple request to get some
|
||||
very important information from Wikipedia's servers::
|
||||
|
||||
>>> response = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
|
||||
>>> r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
|
||||
|
||||
If we want to access the headers the server sent back to us, we do this::
|
||||
|
||||
>>> response.headers
|
||||
>>> r.headers
|
||||
{'content-length': '56170', 'x-content-type-options': 'nosniff', 'x-cache':
|
||||
'HIT from cp1006.eqiad.wmnet, MISS from cp1010.eqiad.wmnet', 'content-encoding':
|
||||
'gzip', 'age': '3080', 'content-language': 'en', 'vary': 'Accept-Encoding,Cookie',
|
||||
@@ -73,7 +73,7 @@ If we want to access the headers the server sent back to us, we do this::
|
||||
However, if we want to get the headers we sent the server, we simply access the
|
||||
request, and then the request's headers::
|
||||
|
||||
>>> response.request.headers
|
||||
>>> r.request.headers
|
||||
{'Accept-Encoding': 'identity, deflate, compress, gzip',
|
||||
'Accept': '*/*', 'User-Agent': 'python-requests/0.13.1'}
|
||||
|
||||
@@ -129,12 +129,6 @@ At this point only the response headers have been downloaded and the connection
|
||||
|
||||
You can further control the workflow by use of the :class:`Response.iter_content` and :class:`Response.iter_lines` methods, or reading from the underlying urllib3 :class:`urllib3.HTTPResponse` at :class:`Response.raw`.
|
||||
|
||||
Configuring Requests
|
||||
--------------------
|
||||
|
||||
Sometimes you may want to configure a request to customize its behavior. To do
|
||||
this, you can pass in a ``config`` dictionary to a request or session. See the :ref:`Configuration API Docs <configurations>` to learn more.
|
||||
|
||||
|
||||
Keep-Alive
|
||||
----------
|
||||
@@ -201,6 +195,7 @@ Let's pretend that we have a web service that will only respond if the
|
||||
::
|
||||
|
||||
from requests.auth import AuthBase
|
||||
|
||||
class PizzaAuth(AuthBase):
|
||||
"""Attaches HTTP Pizza Authentication to the given Request object."""
|
||||
def __init__(self, username):
|
||||
|
||||
@@ -19,7 +19,7 @@ Let's get started with some simple examples.
|
||||
|
||||
|
||||
Make a Request
|
||||
------------------
|
||||
--------------
|
||||
|
||||
Making a request with Requests is very simple.
|
||||
|
||||
@@ -175,12 +175,12 @@ dictionary of data will automatically be form-encoded when the request is made::
|
||||
>>> r = requests.post("http://httpbin.org/post", data=payload)
|
||||
>>> print r.text
|
||||
{
|
||||
// ...snip... //
|
||||
...
|
||||
"form": {
|
||||
"key2": "value2",
|
||||
"key1": "value1"
|
||||
},
|
||||
// ...snip... //
|
||||
...
|
||||
}
|
||||
|
||||
There are many times that you want to send data that is not form-encoded. If you pass in a ``string`` instead of a ``dict``, that data will be posted directly.
|
||||
@@ -205,11 +205,11 @@ Requests makes it simple to upload Multipart-encoded files::
|
||||
>>> r = requests.post(url, files=files)
|
||||
>>> r.text
|
||||
{
|
||||
// ...snip... //
|
||||
...
|
||||
"files": {
|
||||
"file": "<censored...binary...data>"
|
||||
},
|
||||
// ...snip... //
|
||||
...
|
||||
}
|
||||
|
||||
You can set the filename explicitly::
|
||||
@@ -220,11 +220,11 @@ You can set the filename explicitly::
|
||||
>>> r = requests.post(url, files=files)
|
||||
>>> r.text
|
||||
{
|
||||
// ...snip... //
|
||||
...
|
||||
"files": {
|
||||
"file": "<censored...binary...data>"
|
||||
},
|
||||
// ...snip... //
|
||||
...
|
||||
}
|
||||
|
||||
If you want, you can send strings to be received as files::
|
||||
@@ -235,11 +235,11 @@ If you want, you can send strings to be received as files::
|
||||
>>> r = requests.post(url, files=files)
|
||||
>>> r.text
|
||||
{
|
||||
// ...snip... //
|
||||
...
|
||||
"files": {
|
||||
"file": "some,data,to,send\\nanother,row,to,send\\n"
|
||||
},
|
||||
// ...snip... //
|
||||
...
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ is at <http://python-requests.org>.
|
||||
"""
|
||||
|
||||
__title__ = 'requests'
|
||||
__version__ = '1.0.3'
|
||||
__build__ = 0x01003
|
||||
__version__ = '1.0.4'
|
||||
__build__ = 0x01004
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__license__ = 'Apache 2.0'
|
||||
__copyright__ = 'Copyright 2012 Kenneth Reitz'
|
||||
|
||||
@@ -13,7 +13,7 @@ import socket
|
||||
from .models import Response
|
||||
from .packages.urllib3.poolmanager import PoolManager, proxy_from_url
|
||||
from .hooks import dispatch_hook
|
||||
from .compat import urlparse
|
||||
from .compat import urlparse, basestring
|
||||
from .utils import DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers
|
||||
from .structures import CaseInsensitiveDict
|
||||
from .packages.urllib3.exceptions import MaxRetryError
|
||||
@@ -75,7 +75,7 @@ class HTTPAdapter(BaseAdapter):
|
||||
conn.ca_certs = None
|
||||
|
||||
if cert:
|
||||
if len(cert) == 2:
|
||||
if not isinstance(cert, basestring):
|
||||
conn.cert_file = cert[0]
|
||||
conn.key_file = cert[1]
|
||||
else:
|
||||
|
||||
@@ -21,7 +21,7 @@ def request(method, url, **kwargs):
|
||||
:param method: method for the new :class:`Request` object.
|
||||
: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 or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object 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.
|
||||
@@ -32,6 +32,12 @@ def request(method, url, **kwargs):
|
||||
: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.
|
||||
:param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> import requests
|
||||
>>> req = requests.request('GET', 'http://httpbin.org/get')
|
||||
<Response [200]>
|
||||
"""
|
||||
|
||||
session = sessions.Session()
|
||||
@@ -74,7 +80,7 @@ def post(url, data=None, **kwargs):
|
||||
"""Sends a POST request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
@@ -85,7 +91,7 @@ def put(url, data=None, **kwargs):
|
||||
"""Sends a PUT request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
@@ -96,7 +102,7 @@ def patch(url, data=None, **kwargs):
|
||||
"""Sends a PATCH request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RequestEncodingMixin(object):
|
||||
|
||||
@property
|
||||
def path_url(self):
|
||||
"""Build the path URL to use."""
|
||||
@@ -147,7 +146,28 @@ class RequestHooksMixin(object):
|
||||
|
||||
|
||||
class Request(RequestHooksMixin):
|
||||
"""A user-created :class:`Request <Request>` object."""
|
||||
"""A user-created :class:`Request <Request>` object.
|
||||
|
||||
Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server.
|
||||
|
||||
:param method: HTTP method to use.
|
||||
: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 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.
|
||||
:param hooks: dictionary of callback hooks, for internal usage.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> import requests
|
||||
>>> req = requests.Request('GET', 'http://httpbin.org/get')
|
||||
>>> req.prepare()
|
||||
<PreparedRequest [GET]>
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
method=None,
|
||||
url=None,
|
||||
@@ -157,9 +177,9 @@ class Request(RequestHooksMixin):
|
||||
params=dict(),
|
||||
auth=None,
|
||||
cookies=None,
|
||||
timeout=None,
|
||||
hooks=None):
|
||||
|
||||
|
||||
# Default empty dicts for dict params.
|
||||
data = [] if data is None else data
|
||||
files = [] if files is None else files
|
||||
@@ -179,39 +199,56 @@ class Request(RequestHooksMixin):
|
||||
self.params = params
|
||||
self.auth = auth
|
||||
self.cookies = cookies
|
||||
# self.allow_redirects = allow_redirects
|
||||
# self.proxies = proxies
|
||||
self.hooks = hooks
|
||||
|
||||
def __repr__(self):
|
||||
return '<Request [%s]>' % (self.method)
|
||||
|
||||
def prepare(self):
|
||||
"""Constructs a PreparedRequest for transmission and returns it."""
|
||||
"""Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it."""
|
||||
p = PreparedRequest()
|
||||
|
||||
p.prepare_method(self.method)
|
||||
p.prepare_url(self.url, self.params)
|
||||
p.prepare_headers(self.headers)
|
||||
p.prepare_cookies(self.cookies)
|
||||
p.prepare_auth(self.auth)
|
||||
p.prepare_body(self.data, self.files)
|
||||
# Note that prepare_auth must be last to enable authentication schemes
|
||||
# such as OAuth to work on a fully prepared request.
|
||||
p.prepare_auth(self.auth)
|
||||
|
||||
return p
|
||||
|
||||
|
||||
class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
"""The :class:`PreparedRequest <PreparedRequest>` object."""
|
||||
"""The fully mutable :class:`PreparedRequest <PreparedRequest>` object,
|
||||
containing the exact bytes that will be sent to the server.
|
||||
|
||||
Generated from either a :class:`Request <Request>` object or manually.
|
||||
|
||||
Usage::
|
||||
|
||||
>>> import requests
|
||||
>>> req = requests.Request('GET', 'http://httpbin.org/get')
|
||||
>>> r = req.prepare()
|
||||
<PreparedRequest [GET]>
|
||||
|
||||
>>> s = requests.Session()
|
||||
>>> s.send(r)
|
||||
<Response [200]>
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
#: HTTP verb to send to the server.
|
||||
self.method = None
|
||||
#: HTTP URL to send the request to.
|
||||
self.url = None
|
||||
#: dictionary of HTTP headers.
|
||||
self.headers = None
|
||||
#: request body to send to the server.
|
||||
self.body = None
|
||||
self.params = None
|
||||
self.auth = None
|
||||
self.allow_redirects = None
|
||||
self.proxies = None
|
||||
#: dictionary of callback hooks, for internal usage.
|
||||
self.hooks = default_hooks()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -346,10 +383,8 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
|
||||
|
||||
class Response(object):
|
||||
"""The core :class:`Response <Response>` object. All
|
||||
:class:`Request <Request>` objects contain a
|
||||
:class:`response <Response>` attribute, which is an instance
|
||||
of this class.
|
||||
"""The :class:`Response <Response>` object, which contains a
|
||||
server's response to an HTTP request.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
@@ -408,7 +443,8 @@ class Response(object):
|
||||
|
||||
@property
|
||||
def apparent_encoding(self):
|
||||
"""The apparent encoding, provided by the lovely Charade library."""
|
||||
"""The apparent encoding, provided by the lovely Charade library
|
||||
(Thanks, Ian!)."""
|
||||
return chardet.detect(self.content)['encoding']
|
||||
|
||||
def iter_content(self, chunk_size=1, decode_unicode=False):
|
||||
|
||||
@@ -94,16 +94,13 @@ class SessionRedirectMixin(object):
|
||||
url = urljoin(resp.url, requote_uri(url))
|
||||
|
||||
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.4
|
||||
if resp.status_code is codes.see_other:
|
||||
if resp.status_code is codes.see_other and req.method != 'HEAD':
|
||||
method = 'GET'
|
||||
|
||||
# Do what the browsers do, despite standards...
|
||||
if resp.status_code in (codes.moved, codes.found) and req.method == 'POST':
|
||||
method = 'GET'
|
||||
|
||||
if (resp.status_code == 303) and req.method != 'HEAD':
|
||||
method = 'GET'
|
||||
|
||||
# Remove the cookie headers that were sent.
|
||||
headers = req.headers
|
||||
try:
|
||||
@@ -131,7 +128,17 @@ class SessionRedirectMixin(object):
|
||||
|
||||
|
||||
class Session(SessionRedirectMixin):
|
||||
"""A Requests session."""
|
||||
"""A Requests session.
|
||||
|
||||
Provides cookie persistience, connection-pooling, and configuration.
|
||||
|
||||
Basic Usage::
|
||||
|
||||
>>> import requests
|
||||
>>> s = requests.Session()
|
||||
>>> s.get('http://httpbin.org/get')
|
||||
200
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -140,7 +147,7 @@ class Session(SessionRedirectMixin):
|
||||
#: :class:`Session <Session>`.
|
||||
self.headers = default_headers()
|
||||
|
||||
#: Authentication tuple or object to attach to
|
||||
#: Default Authentication tuple or object to attach to
|
||||
#: :class:`Request <Request>`.
|
||||
self.auth = None
|
||||
|
||||
@@ -157,19 +164,19 @@ class Session(SessionRedirectMixin):
|
||||
#: representing multivalued query parameters.
|
||||
self.params = {}
|
||||
|
||||
#: Stream response content.
|
||||
#: Stream response content default.
|
||||
self.stream = False
|
||||
|
||||
#: SSL Verification.
|
||||
#: SSL Verification default.
|
||||
self.verify = True
|
||||
|
||||
#: SSL certificate.
|
||||
#: SSL certificate default.
|
||||
self.cert = None
|
||||
|
||||
#: Maximum number of redirects to follow.
|
||||
self.max_redirects = DEFAULT_REDIRECT_LIMIT
|
||||
|
||||
#: Should we trust the environment
|
||||
#: Should we trust the environment?
|
||||
self.trust_env = True
|
||||
|
||||
# Set up a CookieJar to be used by default
|
||||
@@ -245,7 +252,7 @@ class Session(SessionRedirectMixin):
|
||||
|
||||
# Create the Request.
|
||||
req = Request()
|
||||
req.method = method
|
||||
req.method = method.upper()
|
||||
req.url = url
|
||||
req.headers = headers
|
||||
req.files = files
|
||||
@@ -316,7 +323,7 @@ class Session(SessionRedirectMixin):
|
||||
"""Sends a POST request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
@@ -326,7 +333,7 @@ class Session(SessionRedirectMixin):
|
||||
"""Sends a PUT request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
@@ -336,7 +343,7 @@ class Session(SessionRedirectMixin):
|
||||
"""Sends a PATCH request. Returns :class:`Response` object.
|
||||
|
||||
:param url: URL for the new :class:`Request` object.
|
||||
:param data: (optional) Dictionary or bytes to send in the body of the :class:`Request`.
|
||||
:param data: (optional) Dictionary, bytes, or file-like object to send in the body of the :class:`Request`.
|
||||
:param \*\*kwargs: Optional arguments that ``request`` takes.
|
||||
"""
|
||||
|
||||
@@ -365,7 +372,12 @@ class Session(SessionRedirectMixin):
|
||||
return adapter
|
||||
|
||||
# Nothing matches :-/
|
||||
raise InvalidSchema('No connection adapters were found for \'%s\'' % url)
|
||||
raise InvalidSchema("No connection adapters were found for '%s'" % url)
|
||||
|
||||
def close(self):
|
||||
"""Closes all adapters and as such the session"""
|
||||
for _, v in self.adapters.items():
|
||||
v.close()
|
||||
|
||||
def mount(self, prefix, adapter):
|
||||
"""Registers a connection adapter to a prefix."""
|
||||
@@ -379,7 +391,7 @@ class Session(SessionRedirectMixin):
|
||||
setattr(self, attr, value)
|
||||
|
||||
|
||||
def session(**kwargs):
|
||||
def session():
|
||||
"""Returns a :class:`Session` for context-management."""
|
||||
|
||||
return Session(**kwargs)
|
||||
return Session()
|
||||
|
||||
@@ -86,6 +86,10 @@ class RequestsTestCase(unittest.TestCase):
|
||||
r = requests.get(httpbin('redirect', '1'))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_HTTP_302_ALLOW_REDIRECT_POST(self):
|
||||
r = requests.post(httpbin('status', '302'), data={'some': 'data'})
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_HTTP_200_OK_GET_WITH_PARAMS(self):
|
||||
heads = {'User-agent': 'Mozilla/5.0'}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user