Compare commits

...

556 Commits

Author SHA1 Message Date
Nate Prewitt
bd840450c0 v2.20.0 2018-10-17 22:32:22 -07:00
Nate Prewitt
7fd9267b3b remove final remnants from 2.6 2018-10-17 00:18:51 -07:00
Hugo Osvaldo Barrera
6ae8a21892 Add myself to AUTHORS
(Or rather, just update my email)
2018-10-16 20:34:56 -07:00
Hugo Osvaldo Barrera
89ab030cdb Use comprehensions whenever possible 2018-10-16 20:34:22 -07:00
Nate Prewitt
2c6a8426ae Merge pull request #4827 from webmaven/patch-1
CVE URLs update: www sub-subdomain no longer valid
2018-10-16 09:33:08 -07:00
Michael R. Bernstein
30be889651 CVE URLs update: www sub-subdomain no longer valid 2018-10-16 10:10:30 -06:00
Nate Prewitt
a6cd380c64 Merge pull request #4765 from requests/encapsulate_urllib3_exc
wrap url parsing exceptions from urllib3's PoolManager
2018-09-30 20:23:57 -06:00
Nate Prewitt
bbdbcc8f05 wrap url parsing exceptions from urllib3's PoolManager 2018-09-30 18:36:05 -06:00
Nate Prewitt
ff0c325014 Merge pull request #4805 from jdufresne/https
Prefer https:// for URLs throughout project
2018-09-30 18:27:23 -06:00
Jon Dufresne
b0ad2499c8 Prefer https:// for URLs throughout project 2018-09-30 17:14:40 -05:00
Jon Dufresne
8f20b7dc8f Remove dead link to unixstickers.com
The link does not link Requests stickers as the text suggests.
2018-09-30 14:03:59 -06:00
Nate Prewitt
207e83f6b6 Merge pull request #4802 from schafezp/patch-1
Update README.md to fix typo
2018-09-21 09:27:12 -07:00
Zachary Schafer
b3c8bb7bef Update README.md to fix typo
I noticed "Rquests" was used at the top of the readme instead of "Requests". If that was intentional then ignore this change.
2018-09-21 12:22:53 -04:00
Kenneth Reitz
d26f6314ab Update index.rst 2018-09-17 06:42:52 -04:00
Kenneth Reitz
dcf5617a5e Update index.rst 2018-09-17 06:42:21 -04:00
Kenneth Reitz
76cf1fa214 Update index.rst 2018-09-17 06:41:41 -04:00
Kenneth Reitz
05dd0b88a1 Update index.rst 2018-09-17 06:40:47 -04:00
Kenneth Reitz
3f024ff774 Update index.rst 2018-09-17 06:40:26 -04:00
Kenneth Reitz
cb1bd313e1 Update MANIFEST.in 2018-09-17 06:07:08 -04:00
Kenneth Reitz
efc4ea6ed7 Delete HISTORY.rst 2018-09-17 06:06:47 -04:00
Kenneth Reitz
5251882a03 history 2018-09-17 06:06:08 -04:00
Kenneth Reitz
02a5d7ba68 Update MANIFEST.in 2018-09-17 06:05:18 -04:00
Kenneth Reitz
eea96f94d9 Update setup.py 2018-09-17 06:05:03 -04:00
Kenneth Reitz
9866277c03 Delete README.rst 2018-09-17 06:03:42 -04:00
Kenneth Reitz
7675468068 Update README.md 2018-09-17 06:03:22 -04:00
Kenneth Reitz
fdcb717cf7 Merge branch 'master' of github.com:requests/requests 2018-09-17 06:00:56 -04:00
Kenneth Reitz
4e7e2707e3 readme 2018-09-17 05:59:57 -04:00
Kenneth Reitz
86914e2dda Update README.rst 2018-09-17 05:56:15 -04:00
Nate Prewitt
52473da631 Merge pull request #4791 from juozasget/patch-1
Tuple test_requirements was too long, PEP8
2018-09-15 21:44:26 +08:00
juozasget
b9dfc95cf2 Tuple test_requirements was too long, PEP8
Broken a long line into multiple lines inside tuple parenthesis.
2018-09-15 13:26:59 +03:00
Nate Prewitt
c292cabd1f Merge pull request #4787 from vinayak-mehta/patch-1
Fix broken essay link
2018-09-15 08:08:44 +08:00
Vinayak Mehta
5ef429efe3 Fix broken essay link 2018-09-15 03:43:30 +05:30
Nate Prewitt
c45d7c49ea Merge pull request #4718 from bmerry/fix-4716
Strip Authorization header whenever root URL changes
2018-09-14 20:08:04 +08:00
Bruce Merry
857e9b7ac2 Rework authorization stripping logic as discussed
The exception for http->https upgrade now requires the standard HTTP(S)
ports to be used, either implicitly (no port specified) or explicitly.
2018-09-14 10:44:43 +02:00
Bruce Merry
3331e2aecd Strip Authorization header whenever root URL changes
Previously the header was stripped only if the hostname changed, but in
an https -> http redirect that can leak the credentials on the wire
(#4716). Based on with RFC 7235 section 2.2, the header is now stripped
if the "canonical root URL" (scheme+authority) has changed, by checking
scheme, hostname and port.
2018-09-14 10:44:43 +02:00
Nate Prewitt
dd754d13de Merge pull request #4785 from alexwlchan/encounterd-of-the-third-kind
Fix a typo in a test docstring
2018-09-12 22:57:31 -07:00
Alex Chan
d1fab0b60c Fix a typo in a test docstring 2018-09-13 06:26:59 +01:00
Kenneth Reitz
8472dbd134 Merge pull request #4782 from sayzlim/master
Fix CSS error
2018-09-10 16:02:00 -04:00
Sayz Lim
0fc171091d Fix CSS error
Human error, I shouldn’t have moved the CTA.
2018-09-11 02:59:03 +07:00
Kenneth Reitz
15029e3b16 Merge pull request #4781 from sayzlim/master
Adjust padding and button placements
2018-09-10 15:35:07 -04:00
Sayz Lim
f18f12bcbc Merge branch 'master' of https://github.com/sayzlim/requests 2018-09-11 00:11:44 +07:00
Sayz Lim
ddbeb3025b Adjust padding and button placements
Move the CTA button so the version doesn’t overlap with it. Make the expanded ad more compact to take less vertical space.
2018-09-11 00:11:38 +07:00
Kenneth Reitz
0755c4cf1b Merge branch 'master' of github.com:requests/requests 2018-09-10 11:07:28 -04:00
Kenneth Reitz
e7cce354c1 ad by 2018-09-10 11:07:20 -04:00
Kenneth Reitz
6e8c27e5a8 Merge pull request #4780 from sayzlim/master
Correct fixed footer width
2018-09-10 11:06:14 -04:00
Kenneth Reitz
16f0280c31 Merge branch 'master' into master 2018-09-10 11:06:03 -04:00
Kenneth Reitz
79e28b7f03 Merge branch 'master' of github.com:requests/requests 2018-09-10 11:05:14 -04:00
Sayz Lim
c3ec370e2d Merge branch 'master' into master 2018-09-10 22:05:13 +07:00
Kenneth Reitz
e976ea839b no more stickers :-/ 2018-09-10 11:04:40 -04:00
Sayz Lim
08b6a78883 Correct fixed footer width 2018-09-10 21:52:30 +07:00
Kenneth Reitz
2072888e28 Merge pull request #4779 from sayzlim/master
Integrate Native CPC by BuySellAds
2018-09-10 10:49:30 -04:00
Sayz Lim
2297d33403 Integrate Native CPC by BuySellAds
Replacing Carbon zone key with the direct key and install CPC ad unit on the site.
2018-09-10 21:45:35 +07:00
Kenneth Reitz
a559d62f17 Revert "updates to docs"
This reverts commit f4818b2010.
2018-09-10 06:29:01 -04:00
Kenneth Reitz
f4818b2010 updates to docs 2018-09-10 06:26:52 -04:00
Kenneth Reitz
33b41c7880 updates 2018-08-29 03:29:14 -04:00
Kenneth Reitz
704abf1332 updates 2018-08-29 03:28:33 -04:00
Nate Prewitt
9cfd292da3 Merge pull request #4723 from kalefranz/fix-no_proxy-file-url
Fix assumed hostname when using a 'file' URI scheme adapter
2018-08-13 09:54:33 -07:00
Kale Franz
8023a01dba Fix assumed hostname when using a 'file' URI scheme adapter 2018-08-13 11:28:35 -05:00
Nate Prewitt
dffd5d435e Merge pull request #4678 from jdufresne/intersphinx
In docs, use intersphinx to link to Python documentation
2018-08-11 20:34:59 -07:00
Jon Dufresne
5aa6a9b654 In docs, use intersphinx to link to Python documentation
The intersphinx extension can generate automatic links to the
documentation of objects in other projects. It was already used for
urllib3. For complete details on intersphinx, see:

http://www.sphinx-doc.org/en/master/ext/intersphinx.html
2018-08-11 17:31:43 -07:00
Nate Prewitt
922aa406b5 updating HISTORY.rst 2018-08-11 12:54:21 -07:00
Nate Prewitt
489f58ced5 represent classifiers as list instead of tuple 2018-08-06 23:04:50 -07:00
Jon Dufresne
c8f3add5ed Update all documentation to show Python 3.7 is supported
Official support was added in 6686ac1730.
2018-08-02 10:55:40 -07:00
Nate Prewitt
285ab5b06b Merge pull request #4755 from dohvis/patch-1
Add return type on cookies.py
2018-08-02 10:53:43 -07:00
Dohyeon Kim
72d96a67ef Add return type on cookies.py
http://docs.python-requests.org/en/master/api/#api-cookies
2018-08-01 17:21:03 +09:00
Nate Prewitt
e4d214dd76 Merge pull request #4749 from derlin/master
make content-type's charset information case-insensitive
2018-07-24 09:42:27 -07:00
Lucy Linder
907c927d60 make content-type's charset information case-insensitive
see issue https://github.com/requests/requests/issues/4748 for more information
2018-07-24 18:13:50 +02:00
Eric Brown
6686ac1730 Add official Python 3.7 support (#4717)
* Add official Python 3.7 support

Python 3.7 was just released [1]. This is a small change to
enable support in requests.

Signed-off-by: Eric Brown <browne@vmware.com>
2018-07-24 07:44:37 -07:00
Nate Prewitt
8e43d34d1f Merge pull request #4701 from akaihola/4700-multivalued-list-form-encoded
Documentation and tests for form-encoded multivalued elements as lists
2018-07-20 09:56:28 -07:00
Antti Kaihola
9c92f757e6 Rolled multi-value form examples in documentation into one (#4700)
As suggested by @nateprewitt
2018-07-20 10:30:31 +03:00
Antti Kaihola
87fb312534 Add myself to the authors list 2018-07-20 10:30:31 +03:00
Antti Kaihola
9a8eb131c9 Documentation for multivalued form-encoded element as a list (#4700) 2018-07-20 10:30:31 +03:00
Antti Kaihola
691e9520ed Add test for multivalued form-encoded element as a list (#4700) 2018-07-20 10:30:31 +03:00
Steven M. Vascellaro
4d51e6d201 Remove unused httpbin parameters
httpbin is used to mock HTTP endpoints. In these methods, the parameter
goes unused.
2018-07-17 19:39:18 -07:00
Nate Prewitt
5aeec8b661 Merge pull request #4739 from moy/doc-list-of-tuples
Document that params and data can be list of tuples everywhere
2018-07-17 15:16:02 -07:00
Matthieu Moy
c008bf3883 Document that 'params' can also be a list of tuples
Like we just did for 'data', 'params' follows the same processing and
can also be a list of tuples.
2018-07-17 18:55:55 +02:00
Matthieu Moy
2d1b4482c5 Document that 'data' can be a list of tuples everywhere
The documentation for the 'data' parameter of various functions was
inconsistant. The low-level function, used by every convenience API,
internally uses RequestEncodingMixin._encode_params which accepts list
of tuples as well as dictionaries, hence every function taking a data
parameter also accepts a list of tuple.

Keep the documentation short, but provide a link to Request for
details.
2018-07-17 18:45:43 +02:00
Kenneth Reitz
f6e13ccfc4 Update MANIFEST.in 2018-07-12 14:16:01 -04:00
Ian Stapleton Cordasco
4499401a55 Merge pull request #4728 from yan12125/patch-1
Fix an invalid escape sequence
2018-07-09 07:19:50 -05:00
Chih-Hsuan Yen
b1a360c2f1 Fix an invalid escape sequence 2018-07-09 01:10:00 +08:00
Nate Prewitt
ef88b9faa6 Merge pull request #4713 from Stevoisiak/fix-docstring-param
Misspelled 'proxy' parameter in docstring
2018-06-26 13:32:32 -07:00
Steven M. Vascellaro
5d90638281 Misspelled 'proxy' parameter in docstring
The 'proxy' parameter was misspelled as 'proxies' in the docstring.
2018-06-26 14:58:18 -04:00
Nate Prewitt
9fc639d030 Merge pull request #4710 from Stevoisiak/remove-unused-sessions
Remove unused session variables
2018-06-26 09:50:40 -07:00
Steven M. Vascellaro
28da72b616 Remove unused session variables
Removed local session variables that go unused during testing.
2018-06-26 12:34:15 -04:00
Kenneth Reitz
943a5c8e89 Merge pull request #4709 from Stevoisiak/update-twitter-max-characters
Update max Twitter characters to 280
2018-06-25 14:11:39 -04:00
Steven M. Vascellaro
0c036feb89 Update max Twitter characters to 280
Twitter expanded the maximum character count per tweet from 140 to 280 in November 2017.
2018-06-25 12:56:14 -04:00
Kenneth Reitz
d79187143f Merge pull request #4708 from Stevoisiak/stack-overflow-typo
Change "StackOverflow" to "Stack Overflow"
2018-06-25 11:48:05 -04:00
Steven M. Vascellaro
3e4efeeb89 Change "StackOverflow" to "Stack Overflow"
Add a missing space when referring to "Stack Overflow".
2018-06-25 11:39:07 -04:00
Nate Prewitt
cd97ce90ba Merge pull request #4685 from Stevoisiak/patch-2
Note that session() should not be used
2018-06-21 12:09:06 -07:00
Steven M. Vascellaro
1c13c5e6f3 Document that requests.session() is depreciated
Adds a docstring note that `requests.session()` is depreciated. Users should
use `requests.Session()` in versions released after Requests v1.0.
2018-06-21 09:46:16 -04:00
Nate Prewitt
883caaf145 v2.19.1 2018-06-14 06:26:27 -07:00
Ian Stapleton Cordasco
2530323faf Merge pull request #4683 from martindurant/docstrings_for_optimize
Do not alter status_codes docstring if it is None
2018-06-13 10:24:45 -05:00
Martin Durant
8031ec76b8 Do not alter status_codes docstring if it is None
With PYTHONOPTIMIZE=2, the current code breaks with TypeError.
2018-06-12 17:52:50 -04:00
Nate Prewitt
991e8b76b7 v2.19.0
* Updated HISTORY.rst.
* Moved version pin for idna to allow recent 2.7 release.
* Updated version warning for urllib3 to allow 1.23.
* Updated metadata dunders in __version__.py.
* Removed Python 2.6 trove classifier.
* Removed Python 2.6 reference from README.rst.
2018-06-12 07:38:10 -07:00
Raymond Hettinger
7e297ed95b Separate collections from collections.abc 2018-06-11 22:14:59 -07:00
Laurent Bachelier
10915e3b0d Add a public method to get the cookie policy 2018-06-11 22:13:07 -07:00
Laurent Bachelier
ace0c200f4 Add cookie policy related tests 2018-06-11 22:13:07 -07:00
Laurent Bachelier
3ef49272f2 Copy cookie policy when copying a CookieJar
Without it, the cookie policy would get lost while making a request.
That would be invisible to the user if the default cookie policy wasn't
changed, of course.
2018-06-11 22:13:07 -07:00
Nate Prewitt
d1aeb7ea8c Merge pull request #4672 from requests/remove_2.6_refs
remove references to 2.6 support in documentation
2018-06-11 07:13:13 -07:00
Nate Prewitt
de64f0f23f port pyopenssl fix from urllib3 2018-06-10 14:49:13 -07:00
Nate Prewitt
bc46de58e6 remove references to 2.6 support in documentation 2018-06-10 14:48:59 -07:00
Nate Prewitt
16fd7e03a9 Merge pull request #4676 from jdufresne/doc-py3
Update Python 2 doc links to Python 3
2018-06-10 08:37:08 -07:00
Jon Dufresne
35a1874912 Update Python 2 doc links to Python 3
The Python 3 docs are better maintained and are the future of Python
development.
2018-06-09 20:29:41 -07:00
Nate Prewitt
d98f881118 Merge pull request #4669 from michael-k/patch-1
Allow urllib3 1.23
2018-06-05 06:35:08 -07:00
Michael
ac944b7439 Allow urllib3 1.23
https://github.com/urllib3/urllib3/blob/1.23/CHANGES.rst#123-2018-06-04
2018-06-05 12:06:03 +00:00
Ian Stapleton Cordasco
00fd4c8eb4 Merge pull request #4661 from ofek/patch-2
Response.content minor perf improvement
2018-05-26 19:00:25 -05:00
Ofek Lev
c1b828bc95 Response.content minor perf improvement 2018-05-26 18:20:27 -04:00
Nate Prewitt
fe8290b3d0 updating HISTORY.rst 2018-05-17 13:56:17 -07:00
Rajiv Mayani
8546a15587 The library raises NoneType error when file-pointer (fp) resolves to None.
>>> from requests import post
>>> r = post("https://example.com", files={"file-name": None})

However, when a param value or json field is None they are not included in the request body.

>>> from requests import get
>>> r = get("https://example.com", params={"file-name": None})
>>> r.request.url

This commit makes the beahviour consistent for files.
2018-05-17 13:56:17 -07:00
Ian Stapleton Cordasco
5f09f0ca7e Merge pull request #4631 from pradyunsg/patch-1
Add long_description_content_type to setup.py
2018-05-17 09:34:06 -05:00
Ian Stapleton Cordasco
8bffd3da5f Merge branch 'master' into patch-1 2018-05-17 09:12:26 -05:00
Nate Prewitt
9b5071cdb6 Merge pull request #4648 from requests/update_lock_file
bring Pipfile.lock up to date with current constraints
2018-05-16 12:31:48 -07:00
Nate Prewitt
c6db87978f bring Pipfile.lock up to date with current constraints 2018-05-16 07:39:43 -07:00
Nate Prewitt
f3fc892b90 bring HISTORY.rst up to date with recent changes 2018-05-16 07:35:44 -07:00
Ian Stapleton Cordasco
161acb6a50 Merge pull request #4410 from linuxlizard/master
Add SHA-256 and SHA-512 digest auth algorithms
2018-05-16 09:06:57 -05:00
Ian Stapleton Cordasco
371ee7cbec Merge branch 'master' into master 2018-05-16 08:46:26 -05:00
Ian Stapleton Cordasco
80e2637a83 Merge pull request #4647 from requests/appveyor_test
fix appveyor
2018-05-16 08:14:37 -05:00
Nate Prewitt
9055b33f6f install Requests separately on appveyor to fix builds 2018-05-15 23:06:43 -07:00
Nate Prewitt
9616f82905 Merge pull request #4625 from nicktimko/patch-1
Certifi.io broken
2018-05-14 09:22:10 -07:00
Nick Timkovich
919c168cdb Certifi.io broken
http://certifi.io/ -> https://certifiio.readthedocs.io/
2018-05-14 09:55:33 -05:00
Kenneth Reitz
adceafd79d Update issue templates 2018-05-13 16:51:44 -04:00
Kenneth Reitz
e02effb774 Merge pull request #4632 from mingrammer/update-license
Update license copyright to 2018
2018-05-13 13:30:57 -04:00
Julien Prigent
60a5a393d8 Add a comment about lowercase env. variables precedence over uppercase 2018-05-13 06:15:56 -07:00
Kenneth Reitz
9e1d8edcb7 Merge branch 'master' into update-license 2018-05-12 17:10:24 -04:00
Ian Stapleton Cordasco
1e8a3142d2 Merge pull request #4634 from vshih/patch-1
Spelling.
2018-05-08 06:12:32 -05:00
Victor Shih
71e402fe40 Spelling. 2018-05-07 10:51:53 -07:00
Pradyun Gedam
048c926b46 README is in ReST 2018-05-07 00:23:38 +05:30
mingrammer
41c455182b Update license copyright to 2018 2018-05-05 09:57:14 +09:00
Pradyun Gedam
5f306dbe99 Add long_description_content_type to setup.py
See:
- https://packaging.python.org/guides/making-a-pypi-friendly-readme/
- https://pypi.org/p/requests/
2018-05-04 16:43:25 +05:30
Nate Prewitt
239ee19431 Merge pull request #4612 from Obeyed/patch-1
update json param's description to avoid confusion
2018-04-30 08:00:19 -07:00
Elias Obeid
75c57985b0 update json param's description to avoid confusion
- the Request class doesn't accept JSON, but a JSON serializable object
2018-04-30 16:50:23 +02:00
Ian Stapleton Cordasco
11b82ca87c Merge pull request #4620 from requests/appveyor_fix
fix windows builds
2018-04-29 18:56:09 -05:00
Nate Prewitt
cd1278ef99 fix windows builds
Appveyor isn't able to replace the running executable. We'll run it
from inside the interpreter to fix build issues.
2018-04-29 10:27:20 -07:00
Ian Stapleton Cordasco
2de907ad77 Merge pull request #4596 from jdufresne/pypi
Update all pypi.python.org URLs to pypi.org
2018-04-19 05:41:37 -05:00
Jon Dufresne
165804b25e Update all pypi.python.org URLs to pypi.org
For details on the new PyPI, see the blog post:

https://pythoninsider.blogspot.ca/2018/04/new-pypi-launched-legacy-pypi-shutting.html
2018-04-18 20:28:19 -07:00
Nate Prewitt
b66908e7b6 Merge pull request #4547 from Saraislet/json-kwarg-docs
add comment about json parameter changing content-type
2018-03-16 12:42:55 -07:00
Hackbright Student
35af0b077f add comment about json parameter changing content-type 2018-03-16 12:34:24 -07:00
Kenneth Reitz
8246b82a16 niteo
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-13 11:28:31 -04:00
Kenneth Reitz
cd6eb30b20 party time
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 17:11:08 -04:00
Kenneth Reitz
e203d50e10 every day 2018-03-12 17:07:37 -04:00
Kenneth Reitz
b920c6e3f8 no hr
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 17:05:01 -04:00
Kenneth Reitz
6576370b7b cleanup
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 17:04:31 -04:00
Kenneth Reitz
85e536f7eb reorder
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 17:04:14 -04:00
Kenneth Reitz
130773a2d3 sidebar updates
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 17:02:06 -04:00
Kenneth Reitz
87872b9587 sponsored by™ 2018-03-12 16:59:11 -04:00
Kenneth Reitz
3de173e1c9 🍰 2018-03-12 16:54:00 -04:00
Kenneth Reitz
b5eacad638 patron sponsors
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 13:50:12 -04:00
Kenneth Reitz
b1ba9173d0 linode
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-12 13:48:12 -04:00
Kenneth Reitz
ee58368c9f typo
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-09 17:02:15 -05:00
Kenneth Reitz
cf0b8ed291 azure
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-09 16:50:13 -05:00
Kenneth Reitz
280c8b2a72 azure
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-09 16:47:27 -05:00
Kenneth Reitz
16b56d822e twilio!
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-09 11:07:37 -05:00
Kenneth Reitz
742610c6b9 linode
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 16:15:31 -05:00
Kenneth Reitz
eb692cb1e1 hiring
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:57:33 -05:00
Kenneth Reitz
f9a9233058 slack improvements
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:56:40 -05:00
Kenneth Reitz
9de992e22c sign off
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:43:27 -05:00
Kenneth Reitz
c063938abb individuals
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:42:17 -05:00
Kenneth Reitz
667367d6b9 better formatting
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:38:55 -05:00
Kenneth Reitz
8ce2fd2557 change order
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:36:29 -05:00
Kenneth Reitz
d8cc045a2e contact
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:35:39 -05:00
Kenneth Reitz
dc10a5dadd sponsors
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:34:07 -05:00
Kenneth Reitz
bf32936955 cleanup
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:33:26 -05:00
Kenneth Reitz
05b1401795 links
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:32:18 -05:00
Kenneth Reitz
873e8914c1 some
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:31:18 -05:00
Kenneth Reitz
c55258792b cleanup
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:30:33 -05:00
Kenneth Reitz
afad1aab14 community
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:28:55 -05:00
Kenneth Reitz
d05840d34d sponsors
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:28:41 -05:00
Kenneth Reitz
3323e65e96 track fundraiser on personal site
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 15:11:59 -05:00
Kenneth Reitz
74cf6fc38e \o/
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 09:19:28 -05:00
Kenneth Reitz
d91b70bd29 512
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-08 06:29:53 -05:00
Kenneth Reitz
5daa6cc63c $253
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 20:06:13 -05:00
Kenneth Reitz
0730b231ec $203
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 20:02:12 -05:00
Kenneth Reitz
77aa42943e more info
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 19:42:03 -05:00
Kenneth Reitz
b98027af9e donations
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 19:41:24 -05:00
Kenneth Reitz
8ce2c1a182 one time
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 19:27:15 -05:00
Kenneth Reitz
327a54d29d sidebar
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 19:24:45 -05:00
Kenneth Reitz
38a1947957 $10
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 19:11:45 -05:00
Kenneth Reitz
f8ade96762 sidebar
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 18:52:24 -05:00
Kenneth Reitz
665bb2a687 fix
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 18:49:49 -05:00
Kenneth Reitz
f21fd19ac5 goals
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 18:44:36 -05:00
Kenneth Reitz
f51c489d38 fix
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:41:09 -05:00
Kenneth Reitz
773eeff1a2 authors
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:40:38 -05:00
Kenneth Reitz
ac0a7ed152 fix
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:38:05 -05:00
Kenneth Reitz
a4f313a0e5 development
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:36:35 -05:00
Kenneth Reitz
8ca453a8d7 white
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:35:21 -05:00
Kenneth Reitz
c436165a2d gitignore
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:34:04 -05:00
Kenneth Reitz
97b28fdf7f top bar
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:33:51 -05:00
Kenneth Reitz
40f4b984ef index
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:18:27 -05:00
Kenneth Reitz
529c423fb5 support for Requests 3.0
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:15:59 -05:00
Kenneth Reitz
e292f302b7 different form
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 17:01:50 -05:00
Kenneth Reitz
c95b63736d links
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:56:58 -05:00
Kenneth Reitz
2d357f9c3b cleanup
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:55:18 -05:00
Kenneth Reitz
7fb1d70b86 fix fix fix
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:54:40 -05:00
Kenneth Reitz
c78c5002b5 important
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:51:30 -05:00
Kenneth Reitz
d123e9fe78 fix broken things
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:48:44 -05:00
Kenneth Reitz
8ad24ad430 experiment
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-03-07 16:44:57 -05:00
David Poole
85ec7d759e Merge branch 'master' into master 2018-03-05 09:07:12 -07:00
Kenneth Reitz
4ea09e49f7 .org
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-27 10:19:31 -05:00
Kenneth Reitz
06e788e253 <li><a href="http://html.python-requests.com/">Requests-HTML</a></li>
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-27 09:18:00 -05:00
Kenneth Reitz
27aad3666c Merge branch 'master' of github.com:requests/requests 2018-02-27 08:44:37 -05:00
Kenneth Reitz
44dbf8cf40 updated copyright year
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-27 08:44:29 -05:00
Kenneth Reitz
6e76aaea45 nike
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-22 08:34:32 -05:00
Jon Dufresne
265ef609d5 Remove remaining references to removed, vendored packages (#4499)
As the vendored packages were removing in version 2.16, all remaining
doc references should be replaced with newer practices.
2018-02-17 08:15:54 -06:00
Nate Prewitt
cafa3c16c2 Merge pull request #4497 from jdufresne/docs-certfi
Clarify docs that Requests always uses certs from certifi
2018-02-15 17:56:00 -08:00
Jon Dufresne
9c0db92249 Clarify docs that Requests always uses certs from certifi
Since commit 0d7de6430e, certifi is always
used for certificates. Certify became a hard dependency of the package
in 628633143d.

Now update the docs to clarify that Request will always use certificates
from certifi.
2018-02-14 05:47:34 -08:00
Kenneth Reitz
3c1d36b827 Merge branch 'master' of github.com:requests/requests
# Conflicts:
#	docs/_templates/sidebarintro.html
#	docs/_templates/sidebarlogo.html

Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-12 09:43:07 -05:00
Kenneth Reitz
3cd87fac5d new sidebar link
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2018-02-12 09:42:09 -05:00
Semen Zhydenko
22120d423e Fix typos
nonexistant -> nonexistent
neccessary -> necessary
2018-02-07 18:25:22 -06:00
Nate Prewitt
654da610e1 Merge pull request #4498 from jdufresne/ws
Trim trialing white space throughout the project
2018-02-05 08:37:19 -08:00
Jon Dufresne
e8205c0131 Trim trialing white space throughout the project
Many editors clean up trailing white space on save. By removing it all
in one go, it helps keep future diffs cleaner by avoiding spurious white
space changes on unrelated lines.
2018-02-05 06:23:53 -08:00
Ian Stapleton Cordasco
8da118dfeb Merge pull request #4493 from nateprewitt/3.7_testing
Start testing 3.7
2018-02-03 08:43:31 -06:00
Ian Stapleton Cordasco
d69c068ac2 Merge branch 'master' into 3.7_testing 2018-02-03 08:33:55 -06:00
Ian Stapleton Cordasco
3ad14bb54e Merge pull request #4496 from lolatravel/pass_send_kwargs_to_add_headers
Pass kwargs from adapter send call to add_headers, per documentation
2018-02-03 07:40:44 -06:00
Jonathan Elliott Blum
8e040523a4 pass kwargs from send call to add_headers, per documentation 2018-02-02 13:10:16 -05:00
Nate Prewitt
99533b0f0f start testing 3.7 2018-01-26 03:01:22 -08:00
Nate Prewitt
512066488e updating history 2018-01-21 11:06:33 -08:00
Nate Prewitt
d2e1130603 Merge pull request #4452 from nateprewitt/append_fragment_on_redirect
append previous url fragment on redirect
2018-01-21 10:41:46 -08:00
Nate Prewitt
f60324a3de append previous url fragment on redirect 2018-01-21 09:55:45 -08:00
Ian Stapleton Cordasco
f89c325fbe Merge pull request #4439 from nkonin/fix/certifi-broken-link
Fix broken link to Certifi
2018-01-21 08:36:31 -06:00
Ian Stapleton Cordasco
d55b81b964 Merge branch 'master' into fix/certifi-broken-link 2018-01-21 08:12:19 -06:00
Kenneth Reitz
6a74c70a3a merge 2018-01-20 09:02:15 -05:00
Kenneth Reitz
599a8f11f8 sidebar 2018-01-20 09:01:50 -05:00
Никита Конин
0813c865ee Fix broken link to Certifi 2018-01-18 20:14:33 +03:00
Ian Stapleton Cordasco
07372dc058 Merge pull request #4427 from ddormer/4275-use-hostname-not-netloc
Use hostname not netloc
2018-01-16 08:07:26 -06:00
Darren Dormer
2255c34a65 Fix DNS resolution by using hostname instead of netloc and strip username and password when comparing against proxy bypass items. 2018-01-16 10:18:06 +01:00
Nate Prewitt
020f96577f Merge pull request #4459 from jdufresne/pyreq
Pass python_requires argument to setuptools
2018-01-12 20:06:59 -08:00
Jon Dufresne
7cefa939f5 Pass python_requires argument to setuptools
Helps pip decide what version of the library to install.

https://packaging.python.org/tutorials/distributing-packages/#python-requires

> If your project only runs on certain Python versions, setting the
> python_requires argument to the appropriate PEP 440 version specifier
> string will prevent pip from installing the project on other Python
> versions.

https://setuptools.readthedocs.io/en/latest/setuptools.html#new-and-changed-setup-keywords

> python_requires
>
> A string corresponding to a version specifier (as defined in PEP 440)
> for the Python version, used to specify the Requires-Python defined in
> PEP 345.
2018-01-12 16:39:10 -08:00
Ian Stapleton Cordasco
b9d8e00cbc Merge pull request #4460 from jdufresne/py33
Remove unsupported Python 3.3 from tox.ini
2018-01-11 08:41:08 -06:00
Jon Dufresne
620a5391c3 Remove unsupported Python 3.3 from tox.ini
Python 3.3 is not a supported version so don't test it.
2018-01-10 18:37:22 -08:00
Nate Prewitt
c98e30b5cb Merge pull request #4451 from jdufresne/https
Prefer https over http for links in the documentation
2018-01-06 15:22:59 -08:00
Jon Dufresne
030dcce20c Prefer https over http for links in the documentation
- Fixed Read the Docs links
- Fixed GitHub links
- Fixed PyPI links
2018-01-06 11:23:50 -08:00
Ian Stapleton Cordasco
3dc84cde5b Merge pull request #4442 from DemetriosBairaktaris/master
Reduce overall memory usage by removing cgi dependency and writing a protected function
2018-01-04 16:32:39 -06:00
dbairaktaris1
e0ab287317 added more to test scenarios 2018-01-04 10:59:47 -06:00
dbairaktaris1
7deee699ad slice function removed 2018-01-04 10:48:17 -06:00
dbairaktaris1
cb0914407b Continue to refactor, remove list comprehension, add double quotes test case. 2018-01-04 10:30:50 -06:00
dbairaktaris1
80a790443e implement changes after code review 2018-01-03 23:41:41 -06:00
dbairaktaris1
071796d83f implement changes after code review 2018-01-03 23:40:08 -06:00
dbairaktaris1
1988d9cf72 Move nested function up to module level and rename. Add more tests for function. 2018-01-01 14:20:55 -06:00
dbairaktaris1
2dc51c887f added versions back 2018-01-01 00:43:13 -06:00
dbairaktaris1
19cfec28a8 CI 2017-12-31 22:18:19 -06:00
dbairaktaris1
cef0830419 clean 2017-12-31 15:02:39 -06:00
dbairaktaris1
d8666e1906 Reduce overall memory usage of Requests module by removing cgi module dependency in utils.py. Instead wrote a nested function to parse header and return content type and params. 2017-12-31 14:46:15 -06:00
David Poole
efacb9e312 Merge branch 'master' into master 2017-11-29 07:13:07 -07:00
David Poole
1e46cbb4f0 add test for HTTP Digest auth algorithms SHA-256 and SHA-512 2017-11-29 07:10:57 -07:00
Cory Benfield
24092b11d7 Merge pull request #4380 from afedchin/win10
utils: winreg module may not exist like on windows universal platform.
2017-11-27 20:39:15 +00:00
Anton Fedchin
351ec982bb update changelog 2017-11-25 17:21:59 +03:00
Anton Fedchin
714c9dc967 utils: winreg module may not exist like on windows universal platform. 2017-11-25 17:21:59 +03:00
Cory Benfield
d1fb1a29ab Merge pull request #4394 from zaneb/document-status_codes
Add documentation for available status codes
2017-11-23 20:19:12 +00:00
Cory Benfield
c2507013ab Merge branch 'master' into document-status_codes 2017-11-22 20:41:46 +00:00
Nate Prewitt
e68ef0ecad Merge pull request #4368 from danielroseman/patch-1
Clarify behaviour of `json` parameter.
2017-11-22 07:56:09 -08:00
Zane Bitter
19919b44c4 Add documentation for available status codes
There was no way to determine what actual names were available outside
of looking at the source code. They were not listed in the documentation
or accessible through the interactive help.

In addition, doing `pydoc requests.status_codes` displayed some pretty
unhelpful information - the utf-8 encoding string was included in the
module name, there was no description, and internal variables used for
initialisation leaked into the module scope:

    DATA
        code = 511
        codes = <lookup 'status_codes'>
        title = 'network_authentication'
        titles = ('network_authentication_required', 'network_auth', ...

This change prevents the internal variables from leaking, adds a
docstring (which has the side-effect of correcting the module name), and
appends information on the allowed status code names to the docstring
when the module is initialised.

The improved module documentation is then used in the API documentation
to provide another easy reference to the complete list of status codes.
2017-11-21 16:11:34 -05:00
Daniel Roseman
39446def39 Clarify behaviour of json parameter.
`json` is ignored if `data` or `files` is not empty.
2017-11-21 13:40:59 +00:00
Mingyuan Xia
acd2645444 #4373, fix possible winreg value type difference (#4377)
* #4373, fix possible winreg value type difference

* add a test for ProxyOverride and ProxyEnable on win32

* add tests for winreg key ProxyEnable with two possible types

* fixing AppVeyor failures
2017-11-20 20:01:04 +00:00
Ian Stapleton Cordasco
e4fc3539b4 Merge pull request #4390 from alexwlchan/ok-docs
[docs; tiny] Clarify that Response.ok will *only* return True/False
2017-11-20 07:18:00 -06:00
Alex Chan
775cde0914 Clarify that Response.ok will *only* return True/False 2017-11-20 09:16:35 +00:00
David Poole
a31531fb9c Merge branch 'master' into master 2017-11-19 08:45:25 -07:00
Cory Benfield
c3f2553114 Merge pull request #4387 from dave-shawley/clarify-docs
Clarify raw response reading in the quickstart.
2017-11-18 09:44:29 +00:00
Dave Shawley
7cc3d8dc6a docs/quickstart: clarify raw response reading. 2017-11-17 16:37:08 -05:00
Ian Stapleton Cordasco
6d69f944a4 Merge pull request #4384 from taleinat/quickstart_doc_http_to_html
Correct HTTP -> HTML in quickstart doc
2017-11-16 10:01:45 -06:00
Tal Einat
7f08ad3b6c Corrent HTTP -> HTML in quickstart doc 2017-11-16 09:59:00 +02:00
Nate Prewitt
d55de2d391 Merge pull request #4356 from nehaljwani/fix-4353
Check if host is invalid for proxy
2017-11-15 14:16:33 -08:00
Nehal J Wani
9a8a826f22 Check if host is invalid for proxy
According to RFC3986, the authority section can be empty for a given URL,
however, for a proxy URL, it shouldn't be. This patch adds a check to verify
that the parsed URL will have a valid host before creating the proxy manager.

Fixes #4353
2017-11-15 08:58:54 -05:00
David Poole
1dbaddd75e for RFC-7616 add SHA-256 and SHA-512 2017-11-08 18:32:59 -07:00
Cory Benfield
234f80af88 Merge pull request #4371 from Twistbioscience/zipfile_compat
support extraction of certificate bundle from a zip archive
2017-11-06 21:08:45 +00:00
Arthur Vigil
c86b09b3c6 support extraction of certificate bundle from a zip archive 2017-11-05 12:14:17 -08:00
Nate Prewitt
81b63419cb Merge pull request #4352 from alexwlchan/hooks-on-sessions
Add something to the docs about hooks on Session()
2017-10-24 11:50:03 -07:00
Alex Chan
c5ed41e00a Add an example of two hooks 2017-10-24 07:27:55 +01:00
Alex Chan
40c5a8b0c2 Clarify that a Session can have multiple hooks 2017-10-23 13:25:46 +01:00
Alex Chan
87f3b0a559 Switch to using dict literals, it's 2017 2017-10-23 13:25:31 +01:00
Alex Chan
2c4849defe Add something to the docs about hooks on Session() 2017-10-23 08:30:35 +01:00
Nate Prewitt
c4c031fc5c Merge pull request #4342 from jdufresne/wheel-license
Include license file in the generated wheel package
2017-10-21 16:53:01 -07:00
Jon Dufresne
1595e43812 Include license file in the generated wheel package
The wheel package format supports including the license file. This is
done using the [metadata] section in the setup.cfg file. For additional
information on this feature, see:

https://wheel.readthedocs.io/en/stable/index.html#including-the-license-in-the-generated-wheel-file
2017-10-21 16:39:48 -07:00
Cory Benfield
8982efa9e4 Merge pull request #4349 from alvarogzp/patch-1
Fix case-insensitive comparison in Session.get_adapter
2017-10-21 06:26:31 -07:00
Alvaro Gutierrez Perez
2afc1cb37b Merge branch 'master' into patch-1 2017-10-21 03:24:55 +02:00
Cory Benfield
db9da3e0d2 Merge pull request #4316 from methane/no-platform
Avoid importing platform
2017-10-19 17:47:40 -07:00
INADA Naoki
a05aac7007 avoid import platform
platform module is relatively large: it takes about 5ms to import
2017-10-20 02:49:22 +09:00
Alvaro Gutierrez Perez
d165b18b6e Split test in two better-defined tests 2017-10-19 17:04:48 +02:00
Alvaro Gutierrez Perez
e11989e8ec Add test for Session.get_adapter() prefix matching 2017-10-19 16:50:13 +02:00
Alvaro Gutierrez Perez
af88af64e6 Add test for Session.get_adapter() case-insensitivity 2017-10-19 16:50:13 +02:00
Alvaro Gutierrez Perez
d3f14af44d Fix case-insensitive comparison in get_adapter()
While trying to get the prefix for an url, the url was lowered before comparing but the prefix not, so if it contains non-lowercase characters (eg. https://api.example.com/sOmE_WeiRD_pReFIX/), it won't match.
2017-10-18 19:27:06 +02:00
Nate Prewitt
54ad3d6dcc Merge pull request #4343 from jdufresne/classifier
Add missing trove classifier to document Python2 support
2017-10-16 01:21:19 -07:00
Jon Dufresne
c14bd018ad Add missing trove classifier to document Python2 support 2017-10-15 19:48:10 -07:00
Nate Prewitt
e86df6e0eb Merge pull request #4341 from hugovk/patch-1
Python 3.7 not officially supported yet
2017-10-15 13:35:52 -07:00
Hugo
ec5804c706 Python 3.3 has already been dropped (#4231) 2017-10-15 20:04:51 +03:00
Hugo
4316af7ae8 Python 3.7 not officially supported yet 2017-10-15 19:52:19 +03:00
Cory Benfield
8c4f78448a Merge pull request #4332 from PrimordialHelios/pyopenssl-warning
Warn about possible slowness on older versions of pyOpenSSL
2017-10-14 08:41:02 -07:00
Taylor Rose
15054aa390 Warn user about possible slowdown when using cryptography version <
1.3.4
2017-10-14 09:00:58 -04:00
Kenneth Reitz
9713289e74 Merge branch 'master' of github.com:requests/requests 2017-09-25 11:04:47 -04:00
Kenneth Reitz
e6afc37be5 new pipfile with new syntax
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-25 11:04:38 -04:00
Ian Stapleton Cordasco
5eb0811ef8 Merge pull request #4305 from sigmavirus24/fix-pypi-display
Fix the invalid restructured text in HISTORY file
2017-09-23 16:21:48 -05:00
Ian Stapleton Cordasco
40c8bcf70c Fix the invalid restructured text in HISTORY file
This was breaking the display of our long_description on PyPI.
2017-09-23 15:54:14 -05:00
Kenneth Reitz
0eb9a4c161 stickers
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-19 13:23:15 -04:00
Kenneth Reitz
cda429aa5d Merge pull request #4295 from requests/pipenv
pipfile (work in progress)
2017-09-17 11:58:46 -04:00
Kenneth Reitz
28ae74dbad update tests
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:46:33 -04:00
Kenneth Reitz
a9d05f06cd remove requirements.txt
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:39:53 -04:00
Kenneth Reitz
d552132464 run coverage w/ pipenv
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:36:54 -04:00
Kenneth Reitz
c3ecb825c4 don't test on 2.6
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:30:26 -04:00
Kenneth Reitz
70a4ae744c pip install pipenv
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:26:22 -04:00
Kenneth Reitz
4c300c2067 pipfile
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-09-17 11:24:05 -04:00
Kenneth Reitz
fdb9b753b4 Update authors.rst 2017-09-05 11:31:16 -04:00
Kenneth Reitz
4bda7b66e7 Update updates.rst 2017-09-04 16:21:57 -04:00
Kenneth Reitz
068d8863d1 Update support.rst 2017-09-04 16:21:04 -04:00
Kenneth Reitz
c49f3643ae Update release-process.rst 2017-09-04 16:20:03 -04:00
Kenneth Reitz
328cff252d Update out-there.rst 2017-09-04 16:19:36 -04:00
Kenneth Reitz
c57bd07a34 Update faq.rst 2017-09-04 16:19:01 -04:00
Kenneth Reitz
0d82afa0c3 Update recommended.rst 2017-09-04 16:18:00 -04:00
Kenneth Reitz
18e37c9368 Update todo.rst 2017-09-04 16:14:48 -04:00
Kenneth Reitz
389da34fc9 Update philosophy.rst 2017-09-04 16:14:07 -04:00
Kenneth Reitz
8ef20d5c36 Update contributing.rst 2017-09-04 16:13:08 -04:00
Kenneth Reitz
e63d481a7a Update authors.rst 2017-09-04 16:12:38 -04:00
Kenneth Reitz
f3eeb38542 Update vulnerabilities.rst 2017-09-04 16:11:52 -04:00
Kenneth Reitz
afaaae185c Update authentication.rst 2017-09-04 16:10:49 -04:00
Kenneth Reitz
8af65a1eca Update quickstart.rst 2017-09-04 16:09:51 -04:00
Kenneth Reitz
c04b044b30 Update advanced.rst 2017-09-04 16:09:08 -04:00
Kenneth Reitz
530198e0c0 Update install.rst 2017-09-04 16:08:22 -04:00
Kenneth Reitz
8c57515696 Update intro.rst 2017-09-04 16:05:57 -04:00
Kenneth Reitz
175452a6b6 Update index.rst 2017-09-04 16:04:07 -04:00
Kenneth Reitz
e35c829b59 Update index.rst 2017-09-04 16:03:49 -04:00
Kenneth Reitz
1ad51b0a41 Update index.rst 2017-09-04 15:55:53 -04:00
Kenneth Reitz
8be8105c42 Update advanced.rst 2017-09-04 15:53:26 -04:00
Kenneth Reitz
49ec082a77 Update recommended.rst 2017-09-04 15:50:38 -04:00
Kenneth Reitz
0488c640e2 Update index.rst 2017-09-04 15:46:47 -04:00
Kenneth Reitz
8371b56d0f Delete extensions.rst 2017-09-04 15:46:24 -04:00
Kenneth Reitz
830c18e4f9 Update index.rst 2017-09-04 15:45:28 -04:00
Kenneth Reitz
2c438cacd1 Create extensions.rst 2017-09-04 15:44:57 -04:00
Kenneth Reitz
9c8ae76928 Update index.rst 2017-09-04 15:40:02 -04:00
Kenneth Reitz
d5a05469f1 Update README.rst 2017-09-04 15:38:13 -04:00
Kenneth Reitz
e22e3a5059 Update README.rst 2017-09-04 15:37:24 -04:00
Kenneth Reitz
054ad4aa67 Update README.rst 2017-09-04 12:59:01 -04:00
Kenneth Reitz
b9638ec7be taste 2017-09-01 13:10:52 -04:00
Kenneth Reitz
940c1246e0 taste 2017-09-01 13:10:29 -04:00
Kenneth Reitz
e0e5b2e3aa Update philosophy.rst 2017-08-29 16:16:52 -04:00
Kenneth Reitz
96b9a3f0fc Update setup.py 2017-08-28 12:25:26 -04:00
Cory Benfield
657e44ad9a Merge pull request #4265 from PascalVA/patch-2
fixed syntax for code block for prepared requests
2017-08-28 10:39:26 +01:00
Pascal Van Acker
ac9a3e5320 fixed syntax for code block for prepared requests 2017-08-28 11:14:05 +02:00
Cory Benfield
6b21682712 Merge pull request #4264 from PascalVA/patch-1
Add environment info to prepared requests docs
2017-08-28 10:08:07 +01:00
Pascal Van Acker
785c733415 Add environment info to prepared requests
When using prepared requests, the environment is not taken into account. This should be reflected in the documentation.
2017-08-28 10:58:44 +02:00
Kenneth Reitz
369be8afd0 pretty little note
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-08-28 02:01:36 -04:00
Kenneth Reitz
572d2f4534 Python 2 Death Sentence™
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-08-28 01:50:35 -04:00
Kenneth Reitz
7e20b9193a Update index.rst 2017-08-28 01:33:45 -04:00
Kenneth Reitz
ad1aff52a0 Update index.rst 2017-08-28 01:33:32 -04:00
Kenneth Reitz
3a6dec9827 Update index.rst 2017-08-28 01:29:29 -04:00
Kenneth Reitz
3cceee3459 Update install.rst 2017-08-27 23:16:32 -04:00
Kenneth Reitz
dd57439fa5 Update README.rst 2017-08-27 23:13:50 -04:00
Cory Benfield
f09e462165 Merge pull request #4261 from Lukasa/fix-broken-tests
Pin to httpbin 0.5.0.
2017-08-27 14:00:37 +01:00
Cory Benfield
3a2ea9deba Pin to httpbin 0.5.0 2017-08-27 08:54:01 +01:00
Kenneth Reitz
5dcbdb50fc docs update 2017-08-25 22:12:34 -04:00
Kenneth Reitz
8ad09b68ea coinbin.org 2017-08-25 22:02:03 -04:00
Kenneth Reitz
88dc33522d Merge branch 'master' of https://github.com/requests/requests 2017-08-20 20:56:54 -04:00
Kenneth Reitz
e5666b93cf btc
Signed-off-by: Kenneth Reitz <me@kennethreitz.org>
2017-08-20 20:56:48 -04:00
Cory Benfield
554a210f88 Merge pull request #4245 from remram44/fix-headers-links
Fix parse_header_links on empty header
2017-08-17 20:34:06 +01:00
Remi Rampin
8e411d0f99 Add test case for empty Link: header 2017-08-17 12:56:45 -04:00
Remi Rampin
7d190ef010 Add entry in HISTORY.rst 2017-08-17 12:56:38 -04:00
Remi Rampin
965ada6f66 Fix parse_header_links on empty header 2017-08-16 22:10:20 -04:00
Cory Benfield
af9dd61fcb Prepare for new release 2017-08-15 14:24:20 +01:00
Cory Benfield
a3d7cf3f27 v2.18.4 2017-08-15 14:22:52 +01:00
Cory Benfield
3c5ecfc9f5 Merge pull request #4240 from mgasvoda/master
Adding header name to exception
2017-08-12 15:41:27 +01:00
mgasvoda
d528106876 Adding record to history 2017-08-12 10:23:45 -04:00
mgasvoda
cbc7c2d1c9 Modifying tests to include header name info 2017-08-11 17:18:58 -04:00
mgasvoda
e36083b89c Adding space after colon 2017-08-11 16:19:43 -04:00
mgasvoda
308343508b Removing trailing whitespace 2017-08-11 16:14:13 -04:00
mgasvoda
ba21d14976 Improving message formatting 2017-08-11 16:12:36 -04:00
mgasvoda
cee8fae65e Adding header name to exception
Adds the name of the header to the invalid header exception raised on TypeError.
2017-08-11 15:37:57 -04:00
Kenneth Reitz
1c2022cf86 Merge pull request #4231 from Lukasa/drop-3.3-support
Drop Python 3.3 support.
2017-08-10 14:03:36 -04:00
Kenneth Reitz
8480cf937a Merge pull request #4237 from robinske/doc-import
Adds import statement to front page of docs for clarity and quicker start up
2017-08-10 14:02:57 -04:00
Kelley Robinson
f6952a9b8d Merge branch 'master' into doc-import 2017-08-10 10:33:22 -07:00
kelley
d758f0cf97 Adds import statement to front page of docs for clarity and quicker start up 2017-08-10 10:23:43 -07:00
Cory Benfield
c31a450c55 Remove references to 3.3 from the docs 2017-08-09 19:40:52 +01:00
Cory Benfield
0a2dc74ecb Drop Python 3.3 support 2017-08-09 19:03:04 +01:00
Cory Benfield
f78a57936b Merge pull request #4229 from NikosVlagoidis/issue#3863
Fixes issue #3863
2017-08-09 18:56:40 +01:00
NikosVlagoidis
218978601f Fix issue #3863 2017-08-09 20:18:43 +03:00
NikosVlagoidis
cb9620780f Update advanced.rst 2017-08-09 18:52:26 +03:00
Nikolaos Vlagoidis
963c78853f Fixes issue #3863 2017-08-09 15:38:45 +03:00
Kenneth Reitz
b670b61d54 Update AUTHORS.rst 2017-08-08 19:16:39 -04:00
Cory Benfield
9ec2005d9f Merge pull request #4223 from Lukasa/widen-idna-pin
Allow IDNA 2.6
2017-08-08 15:42:54 +01:00
Cory Benfield
f4ddf00c36 Allow IDNA 2.6 2017-08-08 13:32:15 +01:00
Cory Benfield
248f122970 Merge pull request #4217 from nikolas/patch-1
fix typo in changelog
2017-08-02 15:38:46 +01:00
Nik Nyby
be8ce365ab fix typo in changelog 2017-08-02 10:26:41 -04:00
Cory Benfield
3393dc8221 Prepare changelog for next release 2017-08-02 14:24:02 +01:00
Cory Benfield
7c67c4adf9 v2.18.3 2017-08-02 14:22:44 +01:00
Ian Stapleton Cordasco
2a4dd64fb4 Merge pull request #4210 from Lukasa/sslerror
Make sure we raise SSLError.
2017-07-29 06:27:17 -05:00
Cory Benfield
9e0fb37fff Changelog for #4209 2017-07-29 12:13:55 +01:00
Cory Benfield
4f49f6b3ed Correctly raise SSLError from urllib3. 2017-07-29 12:12:11 +01:00
Cory Benfield
8b3f20ca91 Add failing test for #4209 2017-07-29 12:09:04 +01:00
Nate Prewitt
fdf426125b Merge pull request #4182 from alexwlchan/idna-version
Add idna version info to requests.help
2017-07-27 14:54:09 -06:00
Alex Chan
d6b57c6fb2 Changelog entry 2017-07-27 21:33:44 +01:00
Alex Chan
39b121d791 Add idna version info to requests.help 2017-07-27 21:33:42 +01:00
Nate Prewitt
12c7456789 Merge pull request #4174 from alex/patch-2
Removed legacy fallback for python3.2
2017-07-27 09:51:33 -06:00
Alex Gaynor
2629c0906e Merge branch 'master' into patch-2 2017-07-27 11:19:32 -04:00
Cory Benfield
205755834d Merge pull request #4207 from markjszy/master
remove legacy super() call
2017-07-27 05:40:03 +01:00
Mark Szymanski
e2f5a135c3 remove legacy super() call 2017-07-26 19:21:45 -05:00
Cory Benfield
8de858f0de Merge pull request #4206 from jvanasco/feature-redirects
some docs on request redirect detection
2017-07-26 20:57:22 +01:00
jonathan vanasco
667896c557 some docs on request redirect detection 2017-07-26 15:32:07 -04:00
Cory Benfield
2b6f1e6236 Merge pull request #4204 from browniebroke/patch-1
Correct urllib3 compatibility comment
2017-07-26 11:03:57 +01:00
Bruno Alla
b77c1a3deb Correct urllib3 compatibility comment
So that it's in line with the code. I saw the warning raised recently and had to dive into the code for exact compatibility, but I stopped after reading the comment rather than the code. 
Maybe a better solution would be to surface the supported versions in the warning, but I see it was changed recently in https://github.com/requests/requests/pull/4144/
2017-07-26 10:23:01 +01:00
Cory Benfield
9e8d403a21 Prepare changelog for next release 2017-07-25 16:23:50 +01:00
Cory Benfield
6cc891fd32 v2.18.2 2017-07-25 16:21:48 +01:00
Cory Benfield
49c44a0c08 Merge pull request #4198 from andportnoy/patch-1
redundant comma
2017-07-21 07:05:10 +01:00
Andrey Portnoy
c6e18b04e3 redundant comma 2017-07-20 20:49:24 -07:00
Ian Stapleton Cordasco
c10b8384e4 Merge pull request #4196 from Lukasa/require-next-urllib3
Allow urllib3 1.22
2017-07-20 06:52:11 -05:00
Cory Benfield
8d1228cd19 Allow urllib3 1.22 2017-07-20 10:08:50 +01:00
Cory Benfield
8e227aeb89 Merge pull request #4195 from requests/requests/sessions-mount-docstring-clarity
Use 'prefix' instead of 'key' in session docstring
2017-07-20 09:13:06 +01:00
Alex Muller
d8c2fdf92f Use 'prefix' instead of 'key' in session docstring
This commit makes the API docs more clear. The 'key' is an
implementation detail.
2017-07-20 10:06:34 +02:00
Cory Benfield
cada19b300 Merge pull request #4192 from koobs/patch-2
Add requirements.txt to MANIFEST.in
2017-07-15 07:39:01 +01:00
Kubilay Kocak
c6a80640d1 Add requirements.txt to MANIFEST.in 2017-07-15 14:44:57 +10:00
Kenneth Reitz
649efc8c9b Merge branch 'master' of github.com:kennethreitz/requests 2017-07-06 17:57:37 -04:00
Kenneth Reitz
14176d1d63 no more stickers 2017-07-06 17:57:28 -04:00
Cory Benfield
1ea4e21958 Merge pull request #4183 from requests/fix_help_ssl_check
Fix help ssl check
2017-07-04 09:16:02 +01:00
Nate Prewitt
51feabbc27 test ssl version check functions as expected in python 2.6 2017-07-04 00:33:16 -06:00
Nate Prewitt
f6e07bb27f fix OPENSSL_VERSION_NUMBER check on Python2.6's ssl module 2017-07-03 17:21:56 -06:00
Alex Gaynor
c054a722bb Removed legacy fallback for python3.2 2017-06-25 12:51:15 -04:00
Kenneth Reitz
bbeb1c32d2 Merge branch 'master' of github.com:kennethreitz/requests 2017-06-16 18:31:19 -04:00
Kenneth Reitz
1263b8660d stickers 2017-06-16 18:30:39 -04:00
Cory Benfield
2fde9ee407 Setup HISTORY for next release 2017-06-14 18:52:03 +01:00
Cory Benfield
51de61f914 v2.18.1 2017-06-14 18:50:53 +01:00
Cory Benfield
dd13b13479 Prepare for next release cycle 2017-06-14 16:45:03 +01:00
Cory Benfield
d93b37cee7 Prepare v2.18.0 2017-06-14 16:43:40 +01:00
Kenneth Reitz
a5b8f8d40a Merge branch 'master' of github.com:kennethreitz/requests 2017-06-11 18:10:11 -04:00
Kenneth Reitz
a8972a5bd2 attempt new ads 2017-06-11 18:10:05 -04:00
Cory Benfield
bb4326c676 Merge pull request #4152 from felixonmars/patch-1
Fix a typo: paramters -> parameters
2017-06-11 18:34:36 +01:00
Felix Yan
a0f0258eee Fix a typo: paramters -> parameters 2017-06-12 01:27:11 +08:00
Cory Benfield
c5901ac893 Merge pull request #4151 from mayhewj/remove-exec
Remove exec permission from files that shouldn't have it
2017-06-11 10:26:51 +01:00
Justin Mayhew
c6a6347156 Remove exec permission from files that shouldn't have it 2017-06-10 20:38:45 -03:00
Cory Benfield
132040cc03 Merge pull request #4134 from mlcrazy/master
Raise exceptions in utils.set_environ
2017-06-09 19:34:56 +01:00
mlcrazy
613f61d77c Merge remote-tracking branch 'upstream/master' 2017-06-09 14:32:27 -04:00
mlcrazy
edcc894a2e Adds to AUTHORS 2017-06-09 14:29:28 -04:00
mlcrazy
761e39b443 Adds changelog entry for #4134 2017-06-09 14:16:32 -04:00
mlcrazy
1d7fd6c8b3 Fixes error swallowing in set_environ 2017-06-09 14:10:47 -04:00
Kenneth Reitz
b3d138e0fd Merge pull request #4140 from Lukasa/issue/4138
Clearer makefile for building README.
2017-06-09 13:30:56 -04:00
Kenneth Reitz
8a8b71f786 Merge branch 'master' into issue/4138 2017-06-09 13:27:02 -04:00
Cory Benfield
2872f17ab8 Merge pull request #4145 from gaojiuli/patch-1
typo
2017-06-09 10:04:40 +01:00
JiuLi Gao
22d12b0501 typo 2017-06-09 16:56:14 +08:00
Nate Prewitt
13eb907c48 Merge pull request #4144 from nateprewitt/move_compat_to_warn
Convert version compatibility checks to warnings
2017-06-08 19:40:07 -06:00
Nate Prewitt
d8e2367809 convert version compatibility checks to warning 2017-06-08 15:21:25 -06:00
Cory Benfield
f8ccc60498 Clearer makefile for building README 2017-06-07 13:50:00 +01:00
Cory Benfield
4f1b17c9c1 Merge pull request #4137 from edmorley/response-context-manager
Allow Requests.Response to be used as a context manager
2017-06-07 08:51:41 +01:00
Ed Morley
4847f5b8cd Allow Requests.Response to be used as a context manager
This saves having to wrap the call to requests with
`contextlib.closing()`, allowing it to be used directly in a
`with` statement, like so:

```
with requests.get('http://httpbin.org/get', stream=True) as r:
    # Do things with the response here.
```

Fixes #4136.
2017-06-06 23:30:47 +01:00
Kenneth Reitz
40ce8144d1 Merge pull request #4135 from edmorley/gitignore-pytest-cache
Add the pytest .cache/ directory to .gitignore
2017-06-06 18:00:38 -04:00
Ed Morley
5a616ee980 Add the pytest .cache/ directory to .gitignore
For example, when a pytest run fails, it saves failure metadata to:
`.cache/v/cache/lastfailed`
2017-06-06 22:44:22 +01:00
Nate Prewitt
b6ee4b2156 Merge pull request #4129 from felixonmars/fix-typo
Fix a typo: verison -> version
2017-06-05 22:07:28 -06:00
Felix Yan
0abb69b1cb Fix a typo: verison -> version 2017-06-06 12:01:41 +08:00
Cory Benfield
56971482af Merge pull request #4114 from cyberjacob/master
Catch error if multiprocessing is not available or is unable to determine the number of CPUs
2017-05-30 13:54:31 +01:00
Jacob Mansfield
98bbf8d170 Catch error if multiprocessing is not available or is unable to determine the number of CPUs 2017-05-30 13:47:55 +01:00
Cory Benfield
d3a4d06238 Begin dev section of README 2017-05-30 11:49:05 +01:00
Kenneth Reitz
152faa2a0f change development philosophy docs to reflect reality 2017-05-29 23:46:50 -04:00
Kenneth Reitz
e41c2c2d96 remove note about cacerts.pem 2017-05-29 23:43:53 -04:00
Kenneth Reitz
3ca2722802 improve development instructions 2017-05-29 23:41:48 -04:00
Kenneth Reitz
310d7f8a9b update development documentation 2017-05-29 23:40:44 -04:00
Kenneth Reitz
01f982da50 remove "are you crazy?" section 2017-05-29 23:38:48 -04:00
Kenneth Reitz
ba509635a3 fix sidebars 2017-05-29 23:36:50 -04:00
Kenneth Reitz
008ab18a77 improve installation docs 2017-05-29 23:33:51 -04:00
Kenneth Reitz
67831abaaf improve install docs 2017-05-29 23:33:25 -04:00
Kenneth Reitz
0f57faba70 fix github stars 2017-05-29 23:26:50 -04:00
Kenneth Reitz
35f2e55308 improve installation instructions 2017-05-29 23:26:15 -04:00
Kenneth Reitz
77ae596e8b Merge branch 'master' of github.com:kennethreitz/requests 2017-05-29 23:25:31 -04:00
Kenneth Reitz
84114419a0 improve install documentation syntax 2017-05-29 23:25:21 -04:00
Kenneth Reitz
500fe3ee03 Merge pull request #4108 from requests/flake8-improvements
flake8 improvements
2017-05-29 23:08:03 -04:00
Kenneth Reitz
d78ec90e7b cleanup utils.py 2017-05-29 23:04:45 -04:00
Kenneth Reitz
04ed1e5122 cleanup sessions.py 2017-05-29 23:02:23 -04:00
Kenneth Reitz
33619268f9 cleanup models.py 2017-05-29 23:00:09 -04:00
Kenneth Reitz
e5894e99b7 improve flake8 help.py 2017-05-29 22:58:01 -04:00
Kenneth Reitz
6495190b00 cleanup help.py (flake8) 2017-05-29 22:55:08 -04:00
Kenneth Reitz
5b363d1a57 improve line continuations for flake8 2017-05-29 22:54:23 -04:00
Kenneth Reitz
f6a4ab02da fix empty lines for flake8 2017-05-29 22:44:33 -04:00
Kenneth Reitz
5fa4e74d61 fix flake8 indent error 2017-05-29 22:43:12 -04:00
Kenneth Reitz
7fc48b099e ignore undefined names in flake8 2017-05-29 22:41:51 -04:00
Kenneth Reitz
3fa02a1336 flake8 ignore lambda expressions 2017-05-29 22:41:07 -04:00
Kenneth Reitz
e55d3d0658 fix spaces in api.py 2017-05-29 22:40:37 -04:00
Kenneth Reitz
7c3861a322 fix flake8 for EOF in __init__.py 2017-05-29 22:40:09 -04:00
Kenneth Reitz
7c2618eb82 flake8: import statement improvements 2017-05-29 22:37:43 -04:00
Kenneth Reitz
4e1bbe1288 ignore line continuations for flake8 2017-05-29 22:35:33 -04:00
Kenneth Reitz
cfc3db06cf ignore import statements for flake8 2017-05-29 22:34:32 -04:00
Kenneth Reitz
5091c15bd7 v2.17.3 2017-05-29 17:54:15 -04:00
Kenneth Reitz
dcb8277975 v2.17.2 2017-05-29 17:52:03 -04:00
Kenneth Reitz
412e3a20a9 2.17.1 2017-05-29 17:52:03 -04:00
Kenneth Reitz
17084cd6d8 Merge pull request #4106 from silverlogic/master
Fix requests.packages not having package attributes
2017-05-29 17:31:49 -04:00
Ryan Pineo
1278ecdf71 Fix requests.packages not having package attributes
Fixes #4104
2017-05-29 17:27:10 -04:00
Kenneth Reitz
2d763c90ae v2.17.1 2017-05-29 15:59:00 -04:00
Kenneth Reitz
db076c098e Merge pull request #4103 from untitaker/issue4102
Preserve identity of unbundled deps
2017-05-29 15:45:39 -04:00
Markus Unterwaditzer
588e8f7f64 Preserve identity of unbundled deps
Fix #4102
2017-05-29 21:41:59 +02:00
Kenneth Reitz
593cd18202 Merge branch 'master' of github.com:kennethreitz/requests 2017-05-29 14:28:23 -04:00
Kenneth Reitz
2daf1cbad9 fix manifest file 2017-05-29 14:28:17 -04:00
Kenneth Reitz
71d8f289b0 Update index.rst 2017-05-29 13:28:54 -04:00
Kenneth Reitz
44c9b7e93b Update README.rst 2017-05-29 13:28:18 -04:00
Kenneth Reitz
916d171f2b Merge branch 'master' of github.com:kennethreitz/requests 2017-05-29 13:17:57 -04:00
Kenneth Reitz
3857431159 v2.17.0 2017-05-29 13:17:49 -04:00
Kenneth Reitz
4ad4670583 Merge pull request #4099 from requests/requests-namespace
Requests namespace
2017-05-29 13:15:20 -04:00
Kenneth Reitz
68076a7f81 Merge pull request #4100 from bcongdon/remove-redirect-cache
Remove session redirect cache
2017-05-29 13:14:42 -04:00
Benjamin Congdon
86f8cb8a35 Remove session redirect cache 2017-05-29 09:53:24 -07:00
Kenneth Reitz
7f14db17c8 new requests namespace 2017-05-29 12:11:43 -04:00
Kenneth Reitz
14c1102e0f new installation location 2017-05-29 12:08:28 -04:00
Kenneth Reitz
c77911ca0f Merge pull request #4094 from kennethreitz/flake8
Flake8
2017-05-29 01:53:26 -04:00
Kenneth Reitz
5a2e5af3a4 try junit 2017-05-29 01:51:06 -04:00
Kenneth Reitz
31fc69ec0d empty commit 2017-05-29 01:39:42 -04:00
Kenneth Reitz
88b435e7e8 only flake8 the right directory 2017-05-29 01:36:00 -04:00
Kenneth Reitz
60226cc25c empty commit 2017-05-29 01:32:26 -04:00
Kenneth Reitz
8ddba4662d no piping to a file 2017-05-28 22:06:04 -04:00
Kenneth Reitz
cd2beaf04a flake8report.txt 2017-05-28 21:54:13 -04:00
Kenneth Reitz
58501d1ec7 docutils 2017-05-28 21:43:29 -04:00
Kenneth Reitz
beccd21146 bunk change 2017-05-28 21:42:09 -04:00
Kenneth Reitz
0622b5c54e flake8 2017-05-28 21:38:27 -04:00
Kenneth Reitz
821774cf47 Update requirements.txt 2017-05-28 21:29:35 -04:00
Kenneth Reitz
78349914c8 Merge pull request #4086 from kennethreitz/travis2
try this travis file
2017-05-28 11:38:51 -07:00
Kenneth Reitz
2ccecf6dbd skip for now 2017-05-28 13:05:09 -04:00
Kenneth Reitz
8af1d9331f fix 2017-05-28 13:03:26 -04:00
Kenneth Reitz
ef34a85378 better ci file 2017-05-28 12:55:59 -04:00
Kenneth Reitz
55014bcc48 try this travis file 2017-05-28 12:51:27 -04:00
Kenneth Reitz
303eca03f3 no more pipenv 2017-05-28 12:37:34 -04:00
Kenneth Reitz
e02eb69fcc that doesn't work on windows 2017-05-28 12:33:56 -04:00
Kenneth Reitz
2936a77678 speed up appveyor 2017-05-28 12:30:58 -04:00
Kenneth Reitz
e6e3589c36 number of cores for travis 2017-05-28 12:14:27 -04:00
Kenneth Reitz
c3a00771e3 todo 2017-05-28 00:43:54 -04:00
Kenneth Reitz
16c8241a81 v2.16.5 2017-05-28 00:35:36 -04:00
Kenneth Reitz
1dfa631dae updates to travis ci 2017-05-27 23:54:53 -04:00
Kenneth Reitz
1fa168eea4 tox.ini 2017-05-27 23:52:44 -04:00
Kenneth Reitz
8b5fa606ec improvements to help utility 2017-05-27 23:51:22 -04:00
Kenneth Reitz
148ab30d70 Merge pull request #4083 from kennethreitz/faster-ci
faster ci (test)
2017-05-27 20:37:37 -07:00
Kenneth Reitz
8d0c2537ee better comments 2017-05-27 23:34:56 -04:00
Kenneth Reitz
458008653c detox 2017-05-27 23:33:13 -04:00
Kenneth Reitz
679d368e3e setup.py improvements 2017-05-27 23:27:38 -04:00
Kenneth Reitz
7384fe71d6 let's see what this breaks 2017-05-27 23:22:49 -04:00
Kenneth Reitz
94331723d1 try again 2017-05-27 23:19:59 -04:00
Kenneth Reitz
b565b79858 skip that 2017-05-27 23:14:06 -04:00
Kenneth Reitz
a00d14a61f pytest 2017-05-27 23:11:01 -04:00
Kenneth Reitz
dc70edf17d try this 2017-05-27 23:09:38 -04:00
Kenneth Reitz
68fda6bcf2 see if that fixes things 2017-05-27 23:07:24 -04:00
Kenneth Reitz
141ce93445 test 2017-05-27 23:04:12 -04:00
Kenneth Reitz
6abe1ff933 update 2017-05-27 23:02:45 -04:00
Kenneth Reitz
3d425ac191 try this 2017-05-27 23:00:30 -04:00
Kenneth Reitz
0ff28d7421 faster 2017-05-27 22:57:45 -04:00
Kenneth Reitz
2758b8b0f0 improve speed of travis-ci 2017-05-27 22:56:43 -04:00
Kenneth Reitz
6746b2540d faster 2017-05-27 22:55:22 -04:00
Kenneth Reitz
03944f4cd6 restore old behavior 2017-05-27 20:33:32 -04:00
Kenneth Reitz
4a28ffcfe9 try this 2017-05-27 20:28:30 -04:00
Kenneth Reitz
b6d51d9f2b change test configuration 2017-05-27 20:25:11 -04:00
Kenneth Reitz
2edb553036 so frustrating 2017-05-27 20:23:02 -04:00
Kenneth Reitz
cffa0effe0 remove pytest-mock 2017-05-27 20:21:29 -04:00
Kenneth Reitz
76a66c41d6 final attempt 2017-05-27 20:19:42 -04:00
Kenneth Reitz
19a1379ff5 >=2.7 2017-05-27 20:17:33 -04:00
Kenneth Reitz
057689bb8a grr 2017-05-27 20:16:32 -04:00
Kenneth Reitz
88f28325c9 pytest 2017-05-27 20:15:17 -04:00
Kenneth Reitz
62afdabb30 blah 2017-05-27 20:11:04 -04:00
Kenneth Reitz
2468058fea better requirements 2017-05-27 20:09:58 -04:00
Kenneth Reitz
e4d8571080 concurrency in coverage report 2017-05-27 20:08:08 -04:00
Kenneth Reitz
048997daa0 better requirements 2017-05-27 20:07:35 -04:00
Kenneth Reitz
c166c4f5d4 remove circle.yml 2017-05-27 20:01:08 -04:00
Kenneth Reitz
f4b488b7f8 try removing that 2017-05-27 19:59:19 -04:00
Kenneth Reitz
cd4c701186 xdist 2017-05-27 19:57:40 -04:00
Kenneth Reitz
8e93b100da lets give this a try 2017-05-27 19:44:54 -04:00
Kenneth Reitz
276024b170 fix tests 2017-05-27 19:33:40 -04:00
Kenneth Reitz
6af910610f omg 2017-05-27 19:31:31 -04:00
Kenneth Reitz
1d76cb3572 cleanup tests (make them faster) 2017-05-27 19:30:13 -04:00
Kenneth Reitz
03e5f5daf3 socks needed for tests 2017-05-27 19:16:16 -04:00
Kenneth Reitz
b9a004a22b improvements 2017-05-27 17:25:44 -04:00
Kenneth Reitz
2e67c86075 merge 2017-05-27 17:24:06 -04:00
Gary Wu
21972c4601 fix #3902 Add proposed documentation change for post data 2017-03-01 13:04:11 -06:00
68 changed files with 4231 additions and 2281 deletions

34
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@@ -0,0 +1,34 @@
---
name: Bug report
about: Create a report to help us improve
---
Summary.
## Expected Result
What you expected.
## Actual Result
What happened instead.
## Reproduction Steps
```python
import requests
```
## System Information
$ python -m requests.help
```
<paste here>
```
This command is only available on Requests v2.16.4 and greater. Otherwise,
please provide some basic information about your system (Python version,
operating system, &c).

7
.github/ISSUE_TEMPLATE/Custom.md vendored Normal file
View File

@@ -0,0 +1,7 @@
---
name: Request for Help
about: Guidance on using Requests.
---
Please refer to our [Stack Overflow tag](https://stackoverflow.com/questions/tagged/python-requests) for guidance.

View File

@@ -0,0 +1,7 @@
---
name: Feature request
about: Suggest an idea for this project
---
Requests is not accepting feature requests at this time.

4
.gitignore vendored
View File

@@ -5,7 +5,7 @@ nosetests.xml
junit-report.xml
pylint.txt
toy.py
tox.ini
.cache/
cover/
build/
docs/_build
@@ -21,3 +21,5 @@ t.py
t2.py
dist
/.mypy_cache/

View File

@@ -1,22 +1,42 @@
sudo: false
language: python
python:
- "2.6"
- "2.7"
- "3.3"
- "3.4"
- "3.5"
- "3.6"
- "3.7-dev"
# - "pypy" -- appears to hang
# - "pypy3"
# command to install dependencies
install: "make"
# command to run tests
script:
- |
if [[ "$TRAVIS_PYTHON_VERSION" != "2.6" ]] ; then make test-readme; fi
- make coverage
after_success:
- pipenv run codecov
- make ci
cache: pip
jobs:
include:
- stage: test
script:
- make test-readme
- make ci
python: '2.7'
- stage: test
script:
- make test-readme
- make ci
python: '3.4'
- stage: test
script:
- make test-readme
- make ci
python: '3.5'
- stage: test
script:
- make test-readme
- make ci
python: '3.6'
- stage: test
script:
- make test-readme
- make ci
python: '3.7'
dist: xenial
sudo: true
- stage: coverage
python: 3.6
script: codecov

32
AUTHORS.rst Executable file → Normal file
View File

@@ -1,20 +1,17 @@
Requests is written and maintained by Kenneth Reitz and
various contributors:
Keepers of the Four Crystals
````````````````````````````
Keepers of the Crystals
```````````````````````
- Kenneth Reitz <me@kennethreitz.org> `@kennethreitz <https://github.com/kennethreitz>`_, Keeper of the Master Crystal.
- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_.
- Nate Prewitt <nate.prewitt@gmail.com> `@nateprewitt <https://github.com/nateprewitt>`_.
Previous Keepers of Crystals
````````````````````````````
- Cory Benfield <cory@lukasa.co.uk> `@lukasa <https://github.com/lukasa>`_
- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_
- Nate Prewitt <nate.prewitt@gmail.com> `@nateprewitt <https://github.com/nateprewitt>`_
Urllib3
```````
- Andrey Petrov <andrey.petrov@shazow.net>
Patches and Suggestions
@@ -128,7 +125,7 @@ Patches and Suggestions
- Bryce Boe <bbzbryce@gmail.com> (`@bboe <https://github.com/bboe>`_)
- Colin Dunklau <colin.dunklau@gmail.com> (`@cdunklau <https://github.com/cdunklau>`_)
- Bob Carroll <bob.carroll@alum.rit.edu> (`@rcarz <https://github.com/rcarz>`_)
- Hugo Osvaldo Barrera <hugo@osvaldobarrera.com.ar> (`@hobarrera <https://github.com/hobarrera>`_)
- Hugo Osvaldo Barrera <hugo@barrera.io> (`@hobarrera <https://github.com/hobarrera>`_)
- Łukasz Langa <lukasz@langa.pl>
- Dave Shawley <daveshawley@gmail.com>
- James Clarke (`@jam <https://github.com/jam>`_)
@@ -181,3 +178,14 @@ Patches and Suggestions
- Jonathan Vanasco (`@jvanasco <https://github.com/jvanasco>`_)
- David Fontenot (`@davidfontenot <https://github.com/davidfontenot>`_)
- Shmuel Amar (`@shmuelamar <https://github.com/shmuelamar>`_)
- Gary Wu (`@garywu <https://github.com/garywu>`_)
- Ryan Pineo (`@ryanpineo <https://github.com/ryanpineo>`_)
- Ed Morley (`@edmorley <https://github.com/edmorley>`_)
- Matt Liu <liumatt@gmail.com> (`@mlcrazy <https://github.com/mlcrazy>`_)
- Taylor Hoff <primdevs@protonmail.com> (`@PrimordialHelios <https://github.com/PrimordialHelios>`_)
- Arthur Vigil (`@ahvigil <https://github.com/ahvigil>`_)
- Nehal J Wani (`@nehaljwani <https://github.com/nehaljwani>`_)
- Demetrios Bairaktaris (`@DemetriosBairaktaris <https://github.com/demetriosbairaktaris>`_)
- Darren Dormer (`@ddormer <https://github.com/ddormer>`_)
- Rajiv Mayani (`@mayani <https://github.com/mayani>`_)
- Antti Kaihola (`@akaihola <https://github.com/akaihola>`_)

1623
HISTORY.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,10 @@
Copyright 2017 Kenneth Reitz
Copyright 2018 Kenneth Reitz
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,

View File

@@ -1,2 +1,2 @@
include README.rst LICENSE NOTICE HISTORY.rst pytest.ini requests/cacert.pem
include README.md LICENSE NOTICE HISTORY.md pytest.ini requirements.txt Pipfile Pipfile.lock
recursive-include tests *.py

View File

@@ -1,24 +1,22 @@
.PHONY: docs
init:
pip install pipenv
pipenv install --dev
pipenv run pip install -e .[socks]
pip install pipenv --upgrade
pipenv install --dev --skip-lock
test:
# This runs all of the tests. To run an individual test, run py.test with
# the -k flag, like "py.test -k test_path_is_not_double_encoded"
pipenv run py.test tests
# This runs all of the tests, on both Python 2 and Python 3.
detox
ci:
pipenv run py.test -n 8 --boxed --junitxml=report.xml
test-readme:
pipenv run python setup.py check -r -s
@pipenv run python setup.py check --restructuredtext --strict && ([ $$? -eq 0 ] && echo "README.rst and HISTORY.rst ok") || echo "Invalid markup in README.rst or HISTORY.rst!"
flake8:
pipenv run flake8 --ignore=E501,F401,E128,E402,E731,F821 requests
coverage:
pipenv run py.test --cov-config .coveragerc --verbose --cov-report term --cov-report xml --cov=requests tests
certs:
curl http://ci.kennethreitz.org/job/ca-bundle/lastSuccessfulBuild/artifact/cacerts.pem -o requests/cacert.pem
publish:
pip install 'twine>=1.5.0'
python setup.py sdist bdist_wheel
@@ -27,4 +25,4 @@ publish:
docs:
cd docs && make html
@echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m"
@echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m"

20
Pipfile
View File

@@ -1,14 +1,24 @@
[[source]]
url = "https://pypi.python.org/simple"
url = "https://pypi.org/simple/"
verify_ssl = true
name = "pypi"
[dev-packages]
pytest = ">=2.8.0"
codecov = "*"
pytest-httpbin = "==0.0.7"
pytest-httpbin = ">=0.0.7"
pytest-mock = "*"
pytest-cov = "*"
pytest-xdist = "*"
alabaster = "*"
readme_renderer = "*"
Sphinx = "<=1.5.5"
PySocks = "*"
readme-renderer = "*"
sphinx = "<=1.5.5"
pysocks = "*"
docutils = "*"
"flake8" = "*"
tox = "*"
detox = "*"
httpbin = ">=0.7.0"
[packages]
"e1839a8" = {path = ".", editable = true, extras = ["socks"]}

603
Pipfile.lock generated
View File

@@ -1,116 +1,641 @@
{
"_meta": {
"hash": {
"sha256": "a26ef57f42fa3da7d70d1c1decb4e6445a6ff66e47c9094ddc9ab8e1f4c0a5b6"
"sha256": "0735b243455d8e924fbd05188ed435bfd3917f4acdade9b9e8f14741f3fc47e9"
},
"pipfile-spec": 6,
"requires": {},
"sources": [
{
"url": "https://pypi.python.org/simple",
"name": "pypi",
"url": "https://pypi.org/simple/",
"verify_ssl": true
}
]
},
"default": {},
"default": {
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"e1839a8": {
"editable": true,
"extras": [
"socks"
],
"path": "."
},
"idna": {
"hashes": [
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
],
"version": "==2.6"
},
"pysocks": {
"hashes": [
"sha256:3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672"
],
"version": "==1.6.8"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
}
},
"develop": {
"alabaster": {
"hashes": [
"sha256:2eef172f44e8d301d25aff8068fddd65f767a3f04b5f15b0f4922f113aa1c732",
"sha256:37cdcb9e9954ed60912ebc1ca12a9d12178c26637abdf124e3cde2341c257fe0"
],
"index": "pypi",
"version": "==0.7.10"
},
"appdirs": {
"version": "==1.4.3"
"apipkg": {
"hashes": [
"sha256:2e38399dbe842891fe85392601aab8f40a8f4cc5a9053c326de35a1cc0297ac6",
"sha256:65d2aa68b28e7d31233bb2ba8eb31cda40e4671f8ac2d6b241e358c9652a74b9"
],
"version": "==1.4"
},
"attrs": {
"hashes": [
"sha256:4b90b09eeeb9b88c35bc642cbac057e45a5fd85367b985bd2809c62b7b939265",
"sha256:e0d0eb91441a3b53dab4d9b743eafc1ac44476296a2053b6ca3af0b139faf87b"
],
"version": "==18.1.0"
},
"babel": {
"version": "==2.4.0"
"hashes": [
"sha256:8ce4cb6fdd4393edd323227cba3a077bceb2a6ce5201c902c65e730046f41f14",
"sha256:ad209a68d7162c4cff4b29cdebe3dec4cef75492df501b0049a9433c96ce6f80"
],
"version": "==2.5.3"
},
"bleach": {
"hashes": [
"sha256:b8fa79e91f96c2c2cd9fd1f9eda906efb1b88b483048978ba62fef680e962b34",
"sha256:eb7386f632349d10d9ce9d4a838b134d4731571851149f9cc2c05a9a837a9a44"
],
"version": "==2.1.3"
},
"blinker": {
"hashes": [
"sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"
],
"version": "==1.4"
},
"brotlipy": {
"hashes": [
"sha256:07194f4768eb62a4f4ea76b6d0df6ade185e24ebd85877c351daa0a069f1111a",
"sha256:091b299bf36dd6ef7a06570dbc98c0f80a504a56c5b797f31934d2ad01ae7d17",
"sha256:09ec3e125d16749b31c74f021aba809541b3564e5359f8c265cbae442810b41a",
"sha256:0be698678a114addcf87a4b9496c552c68a2c99bf93cf8e08f5738b392e82057",
"sha256:0fa6088a9a87645d43d7e21e32b4a6bf8f7c3939015a50158c10972aa7f425b7",
"sha256:1ea4e578241504b58f2456a6c69952c88866c794648bdc74baee74839da61d44",
"sha256:2699945a0a992c04fc7dc7fa2f1d0575a2c8b4b769f2874a08e8eae46bef36ae",
"sha256:2a80319ae13ea8dd60ecdc4f5ccf6da3ae64787765923256b62c598c5bba4121",
"sha256:2e5c64522364a9ebcdf47c5744a5ddeb3f934742d31e61ebfbbc095460b47162",
"sha256:36def0b859beaf21910157b4c33eb3b06d8ce459c942102f16988cca6ea164df",
"sha256:3a3e56ced8b15fbbd363380344f70f3b438e0fd1fcf27b7526b6172ea950e867",
"sha256:3c1d5e2cf945a46975bdb11a19257fa057b67591eb232f393d260e7246d9e571",
"sha256:50ca336374131cfad20612f26cc43c637ac0bfd2be3361495e99270883b52962",
"sha256:5de6f7d010b7558f72f4b061a07395c5c3fd57f0285c5af7f126a677b976a868",
"sha256:637847560d671657f993313ecc6c6c6666a936b7a925779fd044065c7bc035b9",
"sha256:653faef61241bf8bf99d73ca7ec4baa63401ba7b2a2aa88958394869379d67c7",
"sha256:786afc8c9bd67de8d31f46e408a3386331e126829114e4db034f91eacb05396d",
"sha256:79aaf217072840f3e9a3b641cccc51f7fc23037496bd71e26211856b93f4b4cb",
"sha256:7e31f7adcc5851ca06134705fcf3478210da45d35ad75ec181e1ce9ce345bb38",
"sha256:8b39abc3256c978f575df5cd7893153277216474f303e26f0e43ba3d3969ef96",
"sha256:9448227b0df082e574c45c983fa5cd4bda7bfb11ea6b59def0940c1647be0c3c",
"sha256:96bc59ff9b5b5552843dc67999486a220e07a0522dddd3935da05dc194fa485c",
"sha256:a07647886e24e2fb2d68ca8bf3ada398eb56fd8eac46c733d4d95c64d17f743b",
"sha256:af65d2699cb9f13b26ec3ba09e75e80d31ff422c03675fcb36ee4dabe588fdc2",
"sha256:b4c98b0d2c9c7020a524ca5bbff42027db1004c6571f8bc7b747f2b843128e7a",
"sha256:c6cc0036b1304dd0073eec416cb2f6b9e37ac8296afd9e481cac3b1f07f9db25",
"sha256:d2c1c724c4ac375feb2110f1af98ecdc0e5a8ea79d068efb5891f621a5b235cb",
"sha256:dc6c5ee0df9732a44d08edab32f8a616b769cc5a4155a12d2d010d248eb3fb07",
"sha256:fd1d1c64214af5d90014d82cee5d8141b13d44c92ada7a0c0ec0679c6f15a471"
],
"version": "==0.7.0"
},
"certifi": {
"hashes": [
"sha256:13e698f54293db9f89122b0581843a782ad0934a4fe0172d2a980ba77fc61bb7",
"sha256:9fa520c1bacfb634fa7af20a76bcbd3d5fb390481724c597da32c719a7dca4b0"
],
"version": "==2018.4.16"
},
"cffi": {
"hashes": [
"sha256:151b7eefd035c56b2b2e1eb9963c90c6302dc15fbd8c1c0a83a163ff2c7d7743",
"sha256:1553d1e99f035ace1c0544050622b7bc963374a00c467edafac50ad7bd276aef",
"sha256:1b0493c091a1898f1136e3f4f991a784437fac3673780ff9de3bcf46c80b6b50",
"sha256:2ba8a45822b7aee805ab49abfe7eec16b90587f7f26df20c71dd89e45a97076f",
"sha256:3c85641778460581c42924384f5e68076d724ceac0f267d66c757f7535069c93",
"sha256:3eb6434197633b7748cea30bf0ba9f66727cdce45117a712b29a443943733257",
"sha256:4c91af6e967c2015729d3e69c2e51d92f9898c330d6a851bf8f121236f3defd3",
"sha256:770f3782b31f50b68627e22f91cb182c48c47c02eb405fd689472aa7b7aa16dc",
"sha256:79f9b6f7c46ae1f8ded75f68cf8ad50e5729ed4d590c74840471fc2823457d04",
"sha256:7a33145e04d44ce95bcd71e522b478d282ad0eafaf34fe1ec5bbd73e662f22b6",
"sha256:857959354ae3a6fa3da6651b966d13b0a8bed6bbc87a0de7b38a549db1d2a359",
"sha256:87f37fe5130574ff76c17cab61e7d2538a16f843bb7bca8ebbc4b12de3078596",
"sha256:95d5251e4b5ca00061f9d9f3d6fe537247e145a8524ae9fd30a2f8fbce993b5b",
"sha256:9d1d3e63a4afdc29bd76ce6aa9d58c771cd1599fbba8cf5057e7860b203710dd",
"sha256:a36c5c154f9d42ec176e6e620cb0dd275744aa1d804786a71ac37dc3661a5e95",
"sha256:ae5e35a2c189d397b91034642cb0eab0e346f776ec2eb44a49a459e6615d6e2e",
"sha256:b0f7d4a3df8f06cf49f9f121bead236e328074de6449866515cea4907bbc63d6",
"sha256:b75110fb114fa366b29a027d0c9be3709579602ae111ff61674d28c93606acca",
"sha256:ba5e697569f84b13640c9e193170e89c13c6244c24400fc57e88724ef610cd31",
"sha256:be2a9b390f77fd7676d80bc3cdc4f8edb940d8c198ed2d8c0be1319018c778e1",
"sha256:d5d8555d9bfc3f02385c1c37e9f998e2011f0db4f90e250e5bc0c0a85a813085",
"sha256:e55e22ac0a30023426564b1059b035973ec82186ddddbac867078435801c7801",
"sha256:e90f17980e6ab0f3c2f3730e56d1fe9bcba1891eeea58966e89d352492cc74f4",
"sha256:ecbb7b01409e9b782df5ded849c178a0aa7c906cf8c5a67368047daab282b184",
"sha256:ed01918d545a38998bfa5902c7c00e0fee90e957ce036a4000a88e3fe2264917",
"sha256:edabd457cd23a02965166026fd9bfd196f4324fe6032e866d0f3bd0301cd486f",
"sha256:fdf1c1dc5bafc32bc5d08b054f94d659422b05aba244d6be4ddc1c72d9aa70fb"
],
"version": "==1.11.5"
},
"chardet": {
"hashes": [
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
],
"version": "==3.0.4"
},
"click": {
"hashes": [
"sha256:29f99fc6125fbc931b758dc053b3114e55c77a6e4c6c3a2674a2dc986016381d",
"sha256:f15516df478d5a56180fbf80e68f206010e6d160fc39fa508b65e035fd75130b"
],
"version": "==6.7"
},
"cmarkgfm": {
"hashes": [
"sha256:0186dccca79483e3405217993b83b914ba4559fe9a8396efc4eea56561b74061",
"sha256:1a625afc6f62da428df96ec325dc30866cc5781520cbd904ff4ec44cf018171c",
"sha256:275905bb371a99285c74931700db3f0c078e7603bed383e8cf1a09f3ee05a3de",
"sha256:50098f1c4950722521f0671e54139e0edc1837d63c990cf0f3d2c49607bb51a2",
"sha256:50ed116d0b60a07df0dc7b180c28569064b9d37d1578d4c9021cff04d725cb63",
"sha256:61a72def110eed903cd1848245897bcb80d295cd9d13944d4f9f30cba5b76655",
"sha256:64186fb75d973a06df0e6ea12879533b71f6e7ba1ab01ffee7fc3e7534758889",
"sha256:665303d34d7f14f10d7b0651082f25ebf7107f29ef3d699490cac16cdc0fc8ce",
"sha256:70b18f843aec58e4e64aadce48a897fe7c50426718b7753aaee399e72df64190",
"sha256:761ee7b04d1caee2931344ac6bfebf37102ffb203b136b676b0a71a3f0ea3c87",
"sha256:811527e9b7280b136734ed6cb6845e5fbccaeaa132ddf45f0246cbe544016957",
"sha256:987b0e157f70c72a84f3c2f9ef2d7ab0f26c08f2bf326c12c087ff9eebcb3ff5",
"sha256:9fc6a2183d0a9b0974ec7cdcdad42bd78a3be674cc3e65f87dd694419b3b0ab7",
"sha256:c573ea89dd95d41b6d8cf36799c34b6d5b1eac4aed0212dee0f0a11fb7b01e8f",
"sha256:c5f1b9e8592d2c448c44e6bc0d91224b16ea5f8293908b1561de1f6d2d0658b1",
"sha256:cbe581456357d8f0674d6a590b1aaf46c11d01dd0a23af147a51a798c3818034",
"sha256:cf219bec69e601fe27e3974b7307d2f06082ab385d42752738ad2eb630a47d65",
"sha256:d08bad67fa18f7e8ff738c090628ee0cbf0505d74a991c848d6d04abfe67b697",
"sha256:d6f716d7b1182bf35862b5065112f933f43dd1aa4f8097c9bcfb246f71528a34",
"sha256:e08e479102627641c7cb4ece421c6ed4124820b1758765db32201136762282d9",
"sha256:e20ac21418af0298437d29599f7851915497ce9f2866bc8e86b084d8911ee061",
"sha256:e25f53c37e319241b9a412382140dffac98ca756ba8f360ac7ab5e30cad9670a",
"sha256:f20900f16377f2109783ae9348d34bc80530808439591c3d3df73d5c7ef1a00c"
],
"version": "==0.4.2"
},
"codecov": {
"version": "==2.0.9"
"hashes": [
"sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788",
"sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4"
],
"index": "pypi",
"version": "==2.0.15"
},
"configparser": {
"hashes": [
"sha256:5308b47021bc2340965c371f0f058cc6971a04502638d4244225c49d80db273a"
],
"markers": "python_version < '3.2'",
"version": "==3.5.0"
},
"contextlib2": {
"hashes": [
"sha256:509f9419ee91cdd00ba34443217d5ca51f5a364a404e1dce9e8979cea969ca48",
"sha256:f5260a6e679d2ff42ec91ec5252f4eeffdcf21053db9113bd0a8e4d953769c00"
],
"markers": "python_version < '3.2'",
"version": "==0.5.5"
},
"coverage": {
"version": "==4.4.1"
"hashes": [
"sha256:03481e81d558d30d230bc12999e3edffe392d244349a90f4ef9b88425fac74ba",
"sha256:0b136648de27201056c1869a6c0d4e23f464750fd9a9ba9750b8336a244429ed",
"sha256:104ab3934abaf5be871a583541e8829d6c19ce7bde2923b2751e0d3ca44db60a",
"sha256:15b111b6a0f46ee1a485414a52a7ad1d703bdf984e9ed3c288a4414d3871dcbd",
"sha256:198626739a79b09fa0a2f06e083ffd12eb55449b5f8bfdbeed1df4910b2ca640",
"sha256:1c383d2ef13ade2acc636556fd544dba6e14fa30755f26812f54300e401f98f2",
"sha256:28b2191e7283f4f3568962e373b47ef7f0392993bb6660d079c62bd50fe9d162",
"sha256:2eb564bbf7816a9d68dd3369a510be3327f1c618d2357fa6b1216994c2e3d508",
"sha256:337ded681dd2ef9ca04ef5d93cfc87e52e09db2594c296b4a0a3662cb1b41249",
"sha256:3a2184c6d797a125dca8367878d3b9a178b6fdd05fdc2d35d758c3006a1cd694",
"sha256:3c79a6f7b95751cdebcd9037e4d06f8d5a9b60e4ed0cd231342aa8ad7124882a",
"sha256:3d72c20bd105022d29b14a7d628462ebdc61de2f303322c0212a054352f3b287",
"sha256:3eb42bf89a6be7deb64116dd1cc4b08171734d721e7a7e57ad64cc4ef29ed2f1",
"sha256:4635a184d0bbe537aa185a34193898eee409332a8ccb27eea36f262566585000",
"sha256:56e448f051a201c5ebbaa86a5efd0ca90d327204d8b059ab25ad0f35fbfd79f1",
"sha256:5a13ea7911ff5e1796b6d5e4fbbf6952381a611209b736d48e675c2756f3f74e",
"sha256:69bf008a06b76619d3c3f3b1983f5145c75a305a0fea513aca094cae5c40a8f5",
"sha256:6bc583dc18d5979dc0f6cec26a8603129de0304d5ae1f17e57a12834e7235062",
"sha256:701cd6093d63e6b8ad7009d8a92425428bc4d6e7ab8d75efbb665c806c1d79ba",
"sha256:7608a3dd5d73cb06c531b8925e0ef8d3de31fed2544a7de6c63960a1e73ea4bc",
"sha256:76ecd006d1d8f739430ec50cc872889af1f9c1b6b8f48e29941814b09b0fd3cc",
"sha256:7aa36d2b844a3e4a4b356708d79fd2c260281a7390d678a10b91ca595ddc9e99",
"sha256:7d3f553904b0c5c016d1dad058a7554c7ac4c91a789fca496e7d8347ad040653",
"sha256:7e1fe19bd6dce69d9fd159d8e4a80a8f52101380d5d3a4d374b6d3eae0e5de9c",
"sha256:8c3cb8c35ec4d9506979b4cf90ee9918bc2e49f84189d9bf5c36c0c1119c6558",
"sha256:9d6dd10d49e01571bf6e147d3b505141ffc093a06756c60b053a859cb2128b1f",
"sha256:9e112fcbe0148a6fa4f0a02e8d58e94470fc6cb82a5481618fea901699bf34c4",
"sha256:ac4fef68da01116a5c117eba4dd46f2e06847a497de5ed1d64bb99a5fda1ef91",
"sha256:b8815995e050764c8610dbc82641807d196927c3dbed207f0a079833ffcf588d",
"sha256:be6cfcd8053d13f5f5eeb284aa8a814220c3da1b0078fa859011c7fffd86dab9",
"sha256:c1bb572fab8208c400adaf06a8133ac0712179a334c09224fb11393e920abcdd",
"sha256:de4418dadaa1c01d497e539210cb6baa015965526ff5afc078c57ca69160108d",
"sha256:e05cb4d9aad6233d67e0541caa7e511fa4047ed7750ec2510d466e806e0255d6",
"sha256:e4d96c07229f58cb686120f168276e434660e4358cc9cf3b0464210b04913e77",
"sha256:f3f501f345f24383c0000395b26b726e46758b71393267aeae0bd36f8b3ade80",
"sha256:f8a923a85cb099422ad5a2e345fe877bbc89a8a8b23235824a93488150e45f6e"
],
"version": "==4.5.1"
},
"decorator": {
"version": "==4.0.11"
"hashes": [
"sha256:2c51dff8ef3c447388fe5e4453d24a2bf128d3a4c32af3fabef1f01c6851ab82",
"sha256:c39efa13fbdeb4506c476c9b3babf6a718da943dab7811c206005a4a956c080c"
],
"version": "==4.3.0"
},
"detox": {
"hashes": [
"sha256:cb24895a0e4f95c0bcb1087a201c453600e075568af00848e91518fb2b984568",
"sha256:f3119bca4444f1e8a1d7189b064c52cfdd9a89ad3a1c921d78b49bf7f5dc5b1b"
],
"index": "pypi",
"version": "==0.12"
},
"docutils": {
"version": "==0.13.1"
"hashes": [
"sha256:02aec4bd92ab067f6ff27a38a38a41173bf01bed8f89157768c1573f53e474a6",
"sha256:51e64ef2ebfb29cae1faa133b3710143496eca21c530f3f71424d77687764274",
"sha256:7a4bd47eaf6596e1295ecb11361139febe29b084a87bf005bf899f9a42edc3c6"
],
"index": "pypi",
"version": "==0.14"
},
"enum34": {
"hashes": [
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
"sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
],
"markers": "python_version < '3.4'",
"version": "==1.1.6"
},
"eventlet": {
"hashes": [
"sha256:06cffa55b335cc4fc32d0079242a81e8a9cddf2581d64d5f0543e2d412b26ca8",
"sha256:554a50dad7abee0a9775b0780ce9d9c0bd9123dda4743c46d4314170267c6c47"
],
"version": "==0.23.0"
},
"execnet": {
"hashes": [
"sha256:a7a84d5fa07a089186a329528f127c9d73b9de57f1a1131b82bb5320ee651f6a",
"sha256:fc155a6b553c66c838d1a22dba1dc9f5f505c43285a878c6f74a79c024750b83"
],
"version": "==1.5.0"
},
"flake8": {
"hashes": [
"sha256:7253265f7abd8b313e3892944044a365e3f4ac3fcdcfb4298f55ee9ddf188ba0",
"sha256:c7841163e2b576d435799169b78703ad6ac1bbb0f199994fc05f700b2a90ea37"
],
"index": "pypi",
"version": "==3.5.0"
},
"flask": {
"version": "==0.12.2"
},
"funcsigs": {
"hashes": [
"sha256:2271c0070dbcb5275fad4a82e29f23ab92682dc45f9dfbc22c02ba9b9322ce48",
"sha256:a080b744b7e345ccfcbc77954861cb05b3c63786e93f2b3875e0913d44b43f05"
],
"version": "==1.0.2"
},
"funcsigs": {
"hashes": [
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
],
"markers": "python_version < '3.3'",
"version": "==1.0.2"
},
"future": {
"hashes": [
"sha256:e39ced1ab767b5936646cedba8bcce582398233d6a627067d4c6a454c90cfedb"
],
"version": "==0.16.0"
},
"greenlet": {
"hashes": [
"sha256:09ef2636ea35782364c830f07127d6c7a70542b178268714a9a9ba16318e7e8b",
"sha256:0fef83d43bf87a5196c91e73cb9772f945a4caaff91242766c5916d1dd1381e4",
"sha256:1b7df09c6598f5cfb40f843ade14ed1eb40596e75cd79b6fa2efc750ba01bb01",
"sha256:1fff21a2da5f9e03ddc5bd99131a6b8edf3d7f9d6bc29ba21784323d17806ed7",
"sha256:42118bf608e0288e35304b449a2d87e2ba77d1e373e8aa221ccdea073de026fa",
"sha256:50643fd6d54fd919f9a0a577c5f7b71f5d21f0959ab48767bd4bb73ae0839500",
"sha256:58798b5d30054bb4f6cf0f712f08e6092df23a718b69000786634a265e8911a9",
"sha256:5b49b3049697aeae17ef7bf21267e69972d9e04917658b4e788986ea5cc518e8",
"sha256:75c413551a436b462d5929255b6dc9c0c3c2b25cbeaee5271a56c7fda8ca49c0",
"sha256:769b740aeebd584cd59232be84fdcaf6270b8adc356596cdea5b2152c82caaac",
"sha256:ad2383d39f13534f3ca5c48fe1fc0975676846dc39c2cece78c0f1f9891418e0",
"sha256:b417bb7ff680d43e7bd7a13e2e08956fa6acb11fd432f74c97b7664f8bdb6ec1",
"sha256:b6ef0cabaf5a6ecb5ac122e689d25ba12433a90c7b067b12e5f28bdb7fb78254",
"sha256:c2de19c88bdb0366c976cc125dca1002ec1b346989d59524178adfd395e62421",
"sha256:c7b04a6dc74087b1598de8d713198de4718fa30ec6cbb84959b26426c198e041",
"sha256:f8f2a0ae8de0b49c7b5b2daca4f150fdd9c1173e854df2cce3b04123244f9f45",
"sha256:fcfadaf4bf68a27e5dc2f42cbb2f4b4ceea9f05d1d0b8f7787e640bed2801634"
],
"version": "==0.4.13"
},
"html5lib": {
"hashes": [
"sha256:20b159aa3badc9d5ee8f5c647e5efd02ed2a66ab8d354930bd9ff139fc1dc0a3",
"sha256:66cb0dcfdbbc4f9c3ba1a63fdb511ffdbd4f513b2b6d81b80cd26ce6b3fb3736"
],
"version": "==1.0.1"
},
"httpbin": {
"version": "==0.5.0"
"hashes": [
"sha256:7a04b5904c80b7aa04dd0a6af6520d68ce17a5db175e66a64b971f8e93d73a26",
"sha256:cbb37790c91575f4f15757f42ad41d9f729eb227d5edbe89e4ec175486db8dfa"
],
"index": "pypi",
"version": "==0.7.0"
},
"idna": {
"hashes": [
"sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f",
"sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4"
],
"version": "==2.6"
},
"imagesize": {
"version": "==0.7.1"
"hashes": [
"sha256:3620cc0cadba3f7475f9940d22431fc4d407269f1be59ec9b8edcca26440cf18",
"sha256:5b326e4678b6925158ccc66a9fa3122b6106d7c876ee32d7de6ce59385b96315"
],
"version": "==1.0.0"
},
"itsdangerous": {
"hashes": [
"sha256:cbb3fcf8d3e33df861709ecaf89d9e6629cff0a217bc2848f1b41cd30d360519"
],
"version": "==0.24"
},
"jinja2": {
"version": "==2.9.6"
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
],
"version": "==2.10"
},
"markupsafe": {
"hashes": [
"sha256:a6be69091dac236ea9c6bc7d012beab42010fa914c459791d627dad4910eb665"
],
"version": "==1.0"
},
"mccabe": {
"hashes": [
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
],
"version": "==0.6.1"
},
"mock": {
"hashes": [
"sha256:5ce3c71c5545b472da17b72268978914d0252980348636840bd34a00b5cc96c1",
"sha256:b158b6df76edd239b8208d481dc46b6afd45a846b7812ff0ce58971cf5bc8bba"
],
"markers": "python_version < '3.0'",
"version": "==2.0.0"
},
"packaging": {
"version": "==16.8"
"more-itertools": {
"hashes": [
"sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea",
"sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e",
"sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"
],
"version": "==4.1.0"
},
"pbr": {
"version": "==3.0.0"
"hashes": [
"sha256:680bf5ba9b28dd56e08eb7c267991a37c7a5f90a92c2e07108829931a50ff80a",
"sha256:6874feb22334a1e9a515193cba797664e940b763440c88115009ec323a7f2df5"
],
"version": "==4.0.3"
},
"pluggy": {
"hashes": [
"sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff",
"sha256:d345c8fe681115900d6da8d048ba67c25df42973bda370783cd58826442dcd7c",
"sha256:e160a7fcf25762bb60efc7e171d4497ff1d8d2d75a3d0df7a21b76821ecbf5c5"
],
"version": "==0.6.0"
},
"py": {
"version": "==1.4.33"
"hashes": [
"sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881",
"sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"
],
"version": "==1.5.3"
},
"pycodestyle": {
"hashes": [
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
],
"version": "==2.3.1"
},
"pycparser": {
"hashes": [
"sha256:99a8ca03e29851d96616ad0404b4aad7d9ee16f25c9f9708a11faf2810f7b226"
],
"version": "==2.18"
},
"pyflakes": {
"hashes": [
"sha256:08bd6a50edf8cffa9fa09a463063c425ecaaf10d1eb0335a7e8b1401aef89e6f",
"sha256:8d616a382f243dbf19b54743f280b80198be0bca3a5396f1d2e1fca6223e8805"
],
"version": "==1.6.0"
},
"pygments": {
"version": "==2.2.0"
},
"pyparsing": {
"hashes": [
"sha256:78f3f434bcc5d6ee09020f92ba487f95ba50f1e3ef83ae96b9d5ffa1bab25c5d",
"sha256:dbae1046def0efb574852fab9e90209b23f556367b5a320c0bcb871c77c3e8cc"
],
"version": "==2.2.0"
},
"pysocks": {
"version": "==1.6.7"
"hashes": [
"sha256:3fe52c55890a248676fd69dc9e3c4e811718b777834bcaab7a8125cf9deac672"
],
"version": "==1.6.8"
},
"pytest": {
"version": "==3.0.7"
"hashes": [
"sha256:54713b26c97538db6ff0703a12b19aeaeb60b5e599de542e7fca0ec83b9038e8",
"sha256:829230122facf05a5f81a6d4dfe6454a04978ea3746853b2b84567ecf8e5c526"
],
"index": "pypi",
"version": "==3.5.1"
},
"pytest-cov": {
"hashes": [
"sha256:03aa752cf11db41d281ea1d807d954c4eda35cfa1b21d6971966cc041bbf6e2d",
"sha256:890fe5565400902b0c78b5357004aab1c814115894f4f21370e2433256a3eeec"
],
"index": "pypi",
"version": "==2.5.1"
},
"pytest-forked": {
"hashes": [
"sha256:e4500cd0509ec4a26535f7d4112a8cc0f17d3a41c29ffd4eab479d2a55b30805",
"sha256:f275cb48a73fc61a6710726348e1da6d68a978f0ec0c54ece5a5fae5977e5a08"
],
"version": "==0.2"
},
"pytest-httpbin": {
"version": "==0.0.7"
"hashes": [
"sha256:8cd57e27418a7d7d205fcc9802eea246ed06170e3065abfa76c6d9b40553592c",
"sha256:d3919c5df0b644454129c0066a8ae62db40ac54bacb4cfd89d8cfa58615a4b42"
],
"index": "pypi",
"version": "==0.3.0"
},
"pytest-mock": {
"version": "==1.6.0"
},
"pytz": {
"version": "==2017.2"
},
"requests": {
"version": "==2.14.2"
},
"setuptools": {
"version": "==35.0.2"
},
"six": {
"hashes": [
"sha256:53801e621223d34724926a5c98bd90e8e417ce35264365d39d6c896388dcc928",
"sha256:d89a8209d722b8307b5e351496830d5cc5e192336003a485443ae9adeb7dd4c0"
],
"index": "pypi",
"version": "==1.10.0"
},
"pytest-xdist": {
"hashes": [
"sha256:be2662264b035920ba740ed6efb1c816a83c8a22253df7766d129f6a7bfdbd35",
"sha256:e8f5744acc270b3e7d915bdb4d5f471670f049b6fbd163d4cbd52203b075d30f"
],
"index": "pypi",
"version": "==1.22.2"
},
"pytz": {
"hashes": [
"sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555",
"sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749"
],
"version": "==2018.4"
},
"raven": {
"hashes": [
"sha256:1c641e5ebc2d4185560608e253970ca0d4b98475f4edf67735015a415f9e1d48",
"sha256:95aecf76c414facaddbb056f3e98c7936318123e467728f2e50b3a66b65a6ef7"
],
"version": "==6.8.0"
},
"readme-renderer": {
"hashes": [
"sha256:bde909eaa84d65b7942f7e6998c8b427b90b568b2630ff0306f4ca75f6d2a909",
"sha256:e7e43a7ba49f08c3cb660d0f2e25b561f6b10b36c63f029060230aab2dc2875e"
],
"index": "pypi",
"version": "==20.0"
},
"requests": {
"hashes": [
"sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b",
"sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e"
],
"version": "==2.18.4"
},
"six": {
"hashes": [
"sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9",
"sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"
],
"version": "==1.11.0"
},
"snowballstemmer": {
"hashes": [
"sha256:919f26a68b2c17a7634da993d91339e288964f93c274f1343e3bbbe2096e1128",
"sha256:9f3bcd3c401c3e862ec0ebe6d2c069ebc012ce142cce209c098ccb5b09136e89"
],
"version": "==1.2.1"
},
"sphinx": {
"hashes": [
"sha256:11f271e7a9398385ed730e90f0bb41dc3815294bdcd395b46ed2d033bc2e7d87",
"sha256:4064ea6c56feeb268838cb8fbbee507d0c3d5d92fa63a7df935a916b52c9e2f5"
],
"index": "pypi",
"version": "==1.5.5"
},
"tox": {
"hashes": [
"sha256:96efa09710a3daeeb845561ebbe1497641d9cef2ee0aea30db6969058b2bda2f",
"sha256:9ee7de958a43806402a38c0d2aa07fa8553f4d2c20a15b140e9f771c2afeade0"
],
"index": "pypi",
"version": "==3.0.0"
},
"urllib3": {
"hashes": [
"sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b",
"sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f"
],
"version": "==1.22"
},
"virtualenv": {
"hashes": [
"sha256:1d7e241b431e7afce47e77f8843a276f652699d1fa4f93b9d8ce0076fd7b0b54",
"sha256:e8e05d4714a1c51a2f5921e62f547fcb0f713ebbe959e0a7f585cc8bef71d11f"
],
"version": "==15.2.0"
},
"webencodings": {
"hashes": [
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
],
"version": "==0.5.1"
},
"werkzeug": {
"version": "==0.12.2"
"hashes": [
"sha256:c3fd7a7d41976d9f44db327260e263132466836cef6f91512889ed60ad26557c",
"sha256:d5da73735293558eb1651ee2fddc4d0dedcfa06538b8813a2e20011583c9e49b"
],
"version": "==0.14.1"
}
}
}

107
README.md Normal file
View File

@@ -0,0 +1,107 @@
Requests: HTTP for Humans™
==========================
[![image](https://img.shields.io/pypi/v/requests.svg)](https://pypi.org/project/requests/)
[![image](https://img.shields.io/pypi/l/requests.svg)](https://pypi.org/project/requests/)
[![image](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests/)
[![codecov.io](https://codecov.io/github/requests/requests/coverage.svg?branch=master)](https://codecov.io/github/requests/requests)
[![image](https://img.shields.io/github/contributors/requests/requests.svg)](https://github.com/requests/requests/graphs/contributors)
[![image](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/kennethreitz)
**If you're interested in financially supporting Kenneth Reitz open source, consider [visiting this link](https://cash.me/$KennethReitz). Your support helps tremendously with sustainability of motivation, as Open Source is no longer part of my day job.**
Requests is the only *Non-GMO* HTTP library for Python, safe for human
consumption.
![image](https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg)
Behold, the power of Requests:
``` {.sourceCode .python}
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'disk_usage': 368627, u'private_gists': 484, ...}
```
See [the similar code, sans Requests](https://gist.github.com/973705).
[![image](https://raw.githubusercontent.com/requests/requests/master/docs/_static/requests-logo-small.png)](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 are 100% automatic, thanks to
[urllib3](https://github.com/shazow/urllib3).
Besides, all the cool kids are doing it. Requests is one of the most
downloaded Python packages of all time, pulling in over 11,000,000
downloads every month. You don't want to be left out!
Feature Support
---------------
Requests is ready for today's web.
- International Domains and URLs
- Keep-Alive & Connection Pooling
- Sessions with Cookie Persistence
- Browser-style SSL Verification
- Basic/Digest Authentication
- Elegant Key/Value Cookies
- Automatic Decompression
- Automatic Content Decoding
- Unicode Response Bodies
- Multipart File Uploads
- HTTP(S) Proxy Support
- Connection Timeouts
- Streaming Downloads
- `.netrc` Support
- Chunked Requests
Requests officially supports Python 2.7 & 3.43.7, and runs great on
PyPy.
Installation
------------
To install Requests, simply use [pipenv](http://pipenv.org/) (or pip, of
course):
``` {.sourceCode .bash}
$ pipenv install requests
✨🍰✨
```
Satisfaction guaranteed.
Documentation
-------------
Fantastic documentation is available at
<http://docs.python-requests.org/>, for a limited time only.
How to Contribute
-----------------
1. 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](https://github.com/requests/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open)
tag for issues that should be ideal for people who are not very
familiar with the codebase yet.
2. Fork [the repository](https://github.com/requests/requests) on
GitHub to start making your changes to the **master** branch (or
branch off of it).
3. Write a test which shows that the bug was fixed or that the feature
works as expected.
4. Send a pull request and bug the maintainer until it gets merged and
published. :) Make sure to add yourself to
[AUTHORS](https://github.com/requests/requests/blob/master/AUTHORS.rst).

View File

@@ -1,117 +0,0 @@
Requests: HTTP for Humans
=========================
.. image:: https://img.shields.io/pypi/v/requests.svg
:target: https://pypi.python.org/pypi/requests
.. image:: https://img.shields.io/pypi/l/requests.svg
:target: https://pypi.python.org/pypi/requests
.. image:: https://img.shields.io/pypi/pyversions/requests.svg
:target: https://pypi.python.org/pypi/requests
.. image:: https://travis-ci.org/kennethreitz/requests.svg?branch=master
:target: https://travis-ci.org/kennethreitz/requests
.. image:: https://codecov.io/github/kennethreitz/requests/coverage.svg?branch=master
:target: https://codecov.io/github/kennethreitz/requests
:alt: codecov.io
.. image:: https://img.shields.io/github/contributors/kennethreitz/requests.svg
:target: https://github.com/kennethreitz/requests/graphs/contributors
.. image:: https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg
:target: https://saythanks.io/to/kennethreitz
Requests is the only *Non-GMO* HTTP library for Python, safe for human
consumption.
**Warning:** Recreational use of the Python standard library for HTTP may result in dangerous side-effects,
including: security vulnerabilities, verbose code, reinventing the wheel,
constantly reading documentation, depression, headaches, or even death.
Behold, the power of Requests:
.. code-block:: python
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
>>> r.status_code
200
>>> r.headers['content-type']
'application/json; charset=utf8'
>>> r.encoding
'utf-8'
>>> r.text
u'{"type":"User"...'
>>> r.json()
{u'disk_usage': 368627, u'private_gists': 484, ...}
See `the similar code, sans Requests <https://gist.github.com/973705>`_.
.. image:: https://raw.githubusercontent.com/kennethreitz/requests/master/docs/_static/requests-logo-small.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
are 100% automatic, thanks to `urllib3 <https://github.com/shazow/urllib3>`_.
Besides, all the cool kids are doing it. Requests is one of the most
downloaded Python packages of all time, pulling in over 11,000,000 downloads
every month. You don't want to be left out!
Feature Support
---------------
Requests is ready for today's web.
- International Domains and URLs
- Keep-Alive & Connection Pooling
- Sessions with Cookie Persistence
- Browser-style SSL Verification
- Basic/Digest Authentication
- Elegant Key/Value Cookies
- Automatic Decompression
- Automatic Content Decoding
- Unicode Response Bodies
- Multipart File Uploads
- HTTP(S) Proxy Support
- Connection Timeouts
- Streaming Downloads
- ``.netrc`` Support
- Chunked Requests
Requests officially supports Python 2.62.7 & 3.33.7, and runs great on PyPy.
Installation
------------
To install Requests, simply:
.. code-block:: bash
$ pip install requests
✨🍰✨
Satisfaction, guaranteed.
Documentation
-------------
Fantastic documentation is available at http://docs.python-requests.org/, for a limited time only.
How to 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 **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_.
.. _`the repository`: http://github.com/kennethreitz/requests
.. _AUTHORS: https://github.com/kennethreitz/requests/blob/master/AUTHORS.rst
.. _Contributor Friendly: https://github.com/kennethreitz/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open

View File

@@ -226,4 +226,4 @@ function main () {
InstallPip $env:PYTHON
}
main
main

View File

@@ -1,5 +1,5 @@
# AppVeyor.yml from https://github.com/ogrisel/python-appveyor-demo
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
# License: CC0 1.0 Universal: https://creativecommons.org/publicdomain/zero/1.0/
build: off
@@ -10,11 +10,6 @@ environment:
PYTHON_ARCH: "64"
TOXENV: "py27"
- PYTHON: "C:\\Python33-x64"
PYTHON_VERSION: "3.3.x"
PYTHON_ARCH: "64"
TOXENV: "py33"
- PYTHON: "C:\\Python34-x64"
PYTHON_VERSION: "3.4.x"
PYTHON_ARCH: "64"
@@ -30,8 +25,13 @@ environment:
PYTHON_ARCH: "64"
TOXENV: "py36"
- PYTHON: "C:\\Python37-x64"
PYTHON_VERSION: "3.7.x"
PYTHON_ARCH: "64"
TOXENV: "py37"
install:
# Install Python (from the official .msi of http://python.org) and pip when
# Install Python (from the official .msi of https://www.python.org/) and pip when
# not already installed.
- ps: if (-not(Test-Path($env:PYTHON))) { & _appveyor\install.ps1 }
@@ -46,8 +46,9 @@ install:
# Upgrade to the latest version of pip to avoid it displaying warnings
# about it being out of date.
- "pip install --disable-pip-version-check --user --upgrade pip"
- "python -m pip install --upgrade pip wheel"
- "C:\\MinGW\\bin\\mingw32-make"
- "pipenv install -e .[socks] --skip-lock"
test_script:
- "C:\\MinGW\\bin\\mingw32-make coverage"

182
docs/_static/custom.css vendored Normal file
View File

@@ -0,0 +1,182 @@
body > div.document > div.sphinxsidebar > div > form > table > tbody > tr:nth-child(2) > td > select {
width: 100%!important;
}
#python27 > a {
color: white;
}
/* Carbon by BuySellAds */
#carbonads {
display: block;
overflow: hidden;
margin: 1.5em 0 2em;
padding: 1em;
border: solid 1px #cccccc;
border-radius: 2px;
background-color: #eeeeee;
text-align: center;
line-height: 1.5;
}
#carbonads a {
border-bottom: 0;
}
#carbonads span {
display: block;
overflow: hidden;
}
.carbon-img {
display: block;
margin: 0 auto 1em;
text-align: center;
}
.carbon-text {
display: block;
margin-bottom: 1em;
}
.carbon-poweredby {
display: block;
text-transform: uppercase;
letter-spacing: 1px;
font-size: 10px;
line-height: 1;
}
/* Native CPC by BuySellAds */
.native-js {
visibility: hidden;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", Helvetica, Arial,
sans-serif;
opacity: 0;
transition: all .25s ease-in-out;
transform: translateY(calc(100% - 35px));
flex-flow: column nowrap;
}
.native-js[data-state=visible] {
position: fixed;
bottom: 0;
left: 0;
right: 0;
visibility: visible;
box-shadow: 0 -1px 4px 1px hsla(0, 0%, 0%, .15);
opacity: 1;
}
.native-js[data-state=visible]:hover {
transform: translateY(0);
}
.native-img {
margin-right: 20px;
max-height: 50px;
border-radius: 3px;
}
.native-sponsor {
margin: 10px 20px;
text-align: center;
text-transform: uppercase;
letter-spacing: .5px;
font-size: 12px;
transition: all .3s ease-in-out;
transform-origin: left;
}
.native-js[data-state=visible]:hover .native-sponsor {
margin: 0 20px;
opacity: 0;
transform: scaleY(0);
}
.native-flex {
display: flex;
padding: 0 20px 30px;
text-decoration: none;
flex-flow: row nowrap;
align-items: center;
}
.native-flex:hover {
text-decoration: none;
}
.native-main {
display: flex;
flex-flow: row nowrap;
align-items: center;
}
.native-details {
display: flex;
margin-right: 30px;
flex-flow: column nowrap;
}
.native-company {
margin-bottom: 4px;
text-transform: uppercase;
letter-spacing: 2px;
font-size: 10px;
}
.native-desc {
letter-spacing: 1px;
font-weight: 300;
line-height: 1.4;
}
.native-cta {
padding: 10px 14px;
border-radius: 3px;
box-shadow: 0 6px 13px 0 hsla(0, 0%, 0%, .15);
text-transform: uppercase;
white-space: nowrap;
letter-spacing: 1px;
font-weight: 400;
font-size: 12px;
transition: all .3s ease-in-out;
transform: translateY(-1px);
}
.native-cta:hover {
box-shadow: none;
transform: translateY(1px);
}
@media only screen and (min-width: 320px) and (max-width: 759px) {
.native-flex {
flex-direction: column;
flex-wrap: wrap;
}
.native-img {
margin: 0;
}
.native-details {
margin: 0;
}
.native-main {
flex-direction: column;
margin-bottom: 20px;
text-align: center;
flex-wrap: wrap;
align-content: center;
}
}

131
docs/_static/native.js vendored Normal file
View File

@@ -0,0 +1,131 @@
var _native = (function () {
var _options = {}
var _construct = function (e) {
var defaultOptions = {
carbonZoneKey: '',
fallback: '',
ignore: 'false',
placement: '',
prefix: 'native',
targetClass: 'native-ad'
}
if (typeof e === 'undefined') return defaultOptions
Object.keys(defaultOptions).forEach((key, index) => {
if (typeof e[key] === 'undefined') {
e[key] = defaultOptions[key]
}
})
return e
}
var init = function (zone, options) {
_options = _construct(options)
let jsonUrl = `https://srv.buysellads.com/ads/${zone}.json?callback=_native_go`
if (_options['placement'] !== '') {
jsonUrl += '&segment=placement:' + _options['placement']
}
if (_options['ignore'] === 'true') {
jsonUrl += '&ignore=yes'
}
let srv = document.createElement('script')
srv.src = jsonUrl
document.getElementsByTagName('head')[0].appendChild(srv)
}
var carbon = function (e) {
let srv = document.createElement('script')
srv.src = '//cdn.carbonads.com/carbon.js?serve=' + e['carbonZoneKey'] + '&placement=' + e['placement']
srv.id = '_carbonads_js'
return srv
}
var sanitize = function (ads) {
return ads
.filter(ad => {
return Object.keys(ad).length > 0
})
.filter(ad => {
return ad.hasOwnProperty('statlink')
})
}
var pixel = function (p, timestamp) {
let c = ''
if (p) {
p.split('||').forEach((pixel, index) => {
c += `<img src="${pixel.replace('[timestamp]', timestamp)}" style="display:none;" height="0" width="0" />`
})
}
return c
}
var options = function () {
return _options
}
return {
carbon: carbon,
init: init,
options: options,
pixel: pixel,
sanitize: sanitize
}
})({})
var _native_go = function (json) {
let options = _native.options()
let ads = _native.sanitize(json['ads'])
let selectedClass = document.querySelectorAll('.' + options['targetClass'])
if (ads.length < 1) {
selectedClass.forEach((className, index) => {
let selectedTarget = document.getElementsByClassName(options['targetClass'])[index]
if (options['fallback'] !== '' || options['carbonZoneKey'] !== '') selectedTarget.setAttribute('data-state', 'visible')
selectedTarget.innerHTML = options['fallback']
if (options['carbonZoneKey'] !== '') selectedTarget.appendChild(_native.carbon(options))
})
// End at this line if no ads are found, avoiding unnecessary steps
return
}
selectedClass.forEach((className, index) => {
let selectedTarget = document.getElementsByClassName(options['targetClass'])[index]
let adElement = selectedTarget.innerHTML
let prefix = options['prefix']
let ad = ads[index]
if (ad && className) {
let adInnerHtml = adElement
.replace(new RegExp('#' + prefix + '_bg_color#', 'g'), ad['backgroundColor'])
.replace(new RegExp('#' + prefix + '_bg_color_hover#', 'g'), ad['backgroundHoverColor'])
.replace(new RegExp('#' + prefix + '_company#', 'g'), ad['company'])
.replace(new RegExp('#' + prefix + '_cta#', 'g'), ad['callToAction'])
.replace(new RegExp('#' + prefix + '_cta_bg_color#', 'g'), ad['ctaBackgroundColor'])
.replace(new RegExp('#' + prefix + '_cta_bg_color_hover#', 'g'), ad['ctaBackgroundHoverColor'])
.replace(new RegExp('#' + prefix + '_cta_color#', 'g'), ad['ctaTextColor'])
.replace(new RegExp('#' + prefix + '_cta_color_hover#', 'g'), ad['ctaTextColorHover'])
.replace(new RegExp('#' + prefix + '_desc#', 'g'), ad['description'])
.replace(new RegExp('#' + prefix + '_index#', 'g'), prefix + '-' + ad['i'])
.replace(new RegExp('#' + prefix + '_img#', 'g'), ad['image'])
.replace(new RegExp('#' + prefix + '_small_img#', 'g'), ad['smallImage'])
.replace(new RegExp('#' + prefix + '_link#', 'g'), ad['statlink'])
.replace(new RegExp('#' + prefix + '_logo#', 'g'), ad['logo'])
.replace(new RegExp('#' + prefix + '_color#', 'g'), ad['textColor'])
.replace(new RegExp('#' + prefix + '_color_hover#', 'g'), ad['textColorHover'])
.replace(new RegExp('#' + prefix + '_title#', 'g'), ad['title'])
selectedTarget.innerHTML = null
selectedTarget.innerHTML += adInnerHtml + _native.pixel(ad['pixel'], ad['timestamp'])
selectedTarget.setAttribute('data-state', 'visible')
} else {
selectedTarget.innerHTML = null
selectedTarget.style.display = 'none'
}
})
}

View File

@@ -26,6 +26,7 @@
</style>
<!-- Analytics tracking for Kenneth. -->
<script type="text/javascript">
var _gauges = _gauges || [];
@@ -42,6 +43,7 @@
})();
</script>
<!-- There are no more hacks. -->
<!-- இڿڰۣ-ڰۣ— -->
<!-- Love, Kenneth Reitz -->
@@ -51,4 +53,51 @@
var easter_egg = new Konami('http://fortunes.herokuapp.com/random/raw');
</script>
<!-- That was not a hack. That was art. -->
<!-- That was not a hack. That was art. -->
<!-- Native CPC by BuySellAds -->
<script src="{{ pathto('_static/', 1) }}/native.js"></script>
<script>
_native.init("CK7D62JU", {
targetClass: 'native-js'
});
</script>
<div class="native-js">
<div class="native-sponsor">Sponsored Ad by #native_company# — Learn More</div>
<a href="#native_link#" class="native-flex">
<style>
.native-js {
background: linear-gradient(-30deg, #native_bg_color#E5, #native_bg_color#E5 45%, #native_bg_color# 45%) #fff;
}
.native-details,
.native-sponsor {
color: #native_color# !important;
}
.native-details:hover {
color: #native_color_hover# !important;
}
.native-cta {
color: #native_cta_color#;
background-color: #native_cta_bg_color#;
}
.native-cta:hover {
color: #native_cta_color_hover;
background-color: #native_cta_bg_color_hover#;
}
</style>
<div class="native-main">
<img class="native-img" src="#native_logo#">
<div class="native-details">
<span class="native-company">#native_title#</span>
<span class="native-desc">#native_desc#</span>
</div>
<span class="native-cta">#native_cta#</span>
</div>
</a>
</div>

View File

@@ -5,7 +5,7 @@
</p>
<p>
<iframe src="http://ghbtns.com/github-btn.html?user=kennethreitz&repo=requests&type=watch&count=true&size=large"
<iframe src="https://ghbtns.com/github-btn.html?user=requests&repo=requests&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
@@ -13,38 +13,29 @@
Requests is an elegant and simple HTTP library for Python, built for
human beings.
</p>
<p>Sponsored by <strong><a href="https://linode.com/">Linode</a></strong> and <a href="http://docs.python-requests.org/en/master/community/sponsors/#patron-sponsors">other wonderful organizations</a>.</p>
<h3>The Hitchhiker's Guide to Python</h3>
<p>This guide is now available in tangible book form!</p>
<a href="https://www.amazon.com/Hitchhikers-Guide-Python-Practices-Development/dp/1491933178/ref=as_li_ss_il?ie=UTF8&linkCode=li2&tag=bookforkind-20&linkId=804806ebdacaf3b56567347f3afbdbca" target="_blank"><img border="0" src="https://ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=1491933178&Format=_SL160_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=bookforkind-20" ></a><img src="//ir-na.amazon-adsystem.com/e/ir?t=bookforkind-20&l=li2&o=1&a=1491933178" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<p>All proceeds are being directly donated to the <a href="https://djangogirls.org">DjangoGirls</a> organization.</p>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=CKYI5K3E&placement=pythonrequestsorg" id="_carbonads_js"></script>
<h3>Stay Informed</h3>
<p>Receive updates on new releases and upcoming projects.</p>
<p><iframe src="http://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false"
<p><iframe src="https://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false"
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>
<p><a href="https://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
<h3>Other Projects</h3>
<p>More <a href="http://kennethreitz.org/">Kenneth Reitz</a> projects:</p>
<p>More <a href="https://www.kennethreitz.org/">Kenneth Reitz</a> projects:</p>
<ul>
<li><a href="http://edmsynths.com/">edmsynths.com</a></li>
<li><a href="https://html.python-requests.org/">Requests-HTML</a></li>
<li><a href="http://howtopython.org/">howtopython.org</a></li>
<li><a href="http://pipenv.org/">pipenv</a></li>
<li><a href="http://pep8.org/">pep8.org</a></li>
<li><a href="http://httpbin.org/">httpbin.org</a></li>
<li><a href="http://python-guide.org">The Python Guide</a></li>
<li><a href="https://pep8.org/">pep8.org</a></li>
<li><a href="https://httpbin.org/">httpbin.org</a></li>
<li><a href="https://docs.python-guide.org/">The Python Guide</a></li>
<li><a href="https://github.com/kennethreitz/maya">Maya: Datetimes for Humans</a></li>
<li><a href="https://github.com/kennethreitz/records">Records: SQL for Humans</a></li>
<li><a href="http://www.git-legit.org">Legit: Git for Humans</a></li>
@@ -58,9 +49,9 @@
<p></p>
<li><a href="http://github.com/kennethreitz/requests">Requests @ GitHub</a></li>
<li><a href="http://pypi.python.org/pypi/requests">Requests @ PyPI</a></li>
<li><a href="http://github.com/kennethreitz/requests/issues">Issue Tracker</a></li>
<li><a href="https://github.com/requests/requests">Requests @ GitHub</a></li>
<li><a href="https://pypi.org/project/requests/">Requests @ PyPI</a></li>
<li><a href="https://github.com/requests/requests/issues">Issue Tracker</a></li>
<li><a href="http://docs.python-requests.org/en/latest/community/updates/#software-updates">Release History</a></li>
</ul>
@@ -78,3 +69,41 @@
<li><a href="http://es.python-requests.org/">Spanish</a></li>
</ul>
<div class="native-js">
<div class="native-sponsor">Sponsored by #native_company# — Learn More</div>
<a href="#native_link#" class="native-flex">
<style>
.native-js {
background: linear-gradient(-30deg, #native_bg_color#E5, #native_bg_color#E5 45%, #native_bg_color# 45%) #fff;
}
.native-details,
.native-sponsor,
.native-bsa {
color: #native_color# !important;
}
.native-details:hover {
color: #native_color_hover# !important;
}
.native-cta {
color: #native_cta_color#;
background-color: #native_cta_bg_color#;
}
.native-cta:hover {
color: #native_cta_color_hover;
background-color: #native_cta_bg_color_hover#;
}
</style>
<div class="native-main">
<img class="native-img" src="#native_logo#">
<div class="native-details">
<span class="native-company">#native_title#</span>
<span class="native-desc">#native_desc#</span>
</div>
</div>
<span class="native-cta">#native_cta#</span>
</a>
</div>

View File

@@ -4,35 +4,29 @@
</a>
</p>
<p>
<iframe src="http://ghbtns.com/github-btn.html?user=kennethreitz&repo=requests&type=watch&count=true&size=large"
<iframe src="https://ghbtns.com/github-btn.html?user=requests&repo=requests&type=watch&count=true&size=large"
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
</p>
<p>
Requests is an elegant and simple HTTP library for Python, built for
human beings. You are currently looking at the documentation of the
development release.
</p>
<p>Sponsored by <strong><a href="https://linode.com/">Linode</a></strong> and <a href="http://docs.python-requests.org/en/master/community/sponsors/#patron-sponsors">other wonderful organizations</a>.</p>
<h3>Stay Informed</h3>
<p>Receive updates on new releases and upcoming projects.</p>
<p><a href="http://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
<p><a href="https://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
<hr/>
<h3>The Hitchhiker's Guide to Python</h3>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=pythonrequestsorg" id="_carbonads_js"></script>
<p>This guide is now available in tangible book form!</p>
<a href="https://www.amazon.com/Hitchhikers-Guide-Python-Practices-Development/dp/1491933178/ref=as_li_ss_il?ie=UTF8&linkCode=li2&tag=bookforkind-20&linkId=804806ebdacaf3b56567347f3afbdbca" target="_blank"><img border="0" src="https://ws-na.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=1491933178&Format=_SL160_&ID=AsinImage&MarketPlace=US&ServiceVersion=20070822&WS=1&tag=bookforkind-20" ></a><img src="//ir-na.amazon-adsystem.com/e/ir?t=bookforkind-20&l=li2&o=1&a=1491933178" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />
<p>All proceeds are being directly donated to the <a href="https://djangogirls.org">DjangoGirls</a> organization.</p>
<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"
<p><iframe src="https://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false"
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>
@@ -40,13 +34,14 @@
<h3>Other Projects</h3>
<p>More <a href="http://kennethreitz.org/">Kenneth Reitz</a> projects:</p>
<p>More <a href="https://www.kennethreitz.org/">Kenneth Reitz</a> projects:</p>
<ul>
<li><a href="http://edmsynths.com/">edmsynths.com</a></li>
<li><a href="https://html.python-requests.org/">Requests-HTML</a></li>
<li><a href="http://howtopython.org/">howtopython.org</a></li>
<li><a href="http://pipenv.org/">pipenv</a></li>
<li><a href="http://pep8.org/">pep8.org</a></li>
<li><a href="http://httpbin.org/">httpbin.org</a></li>
<li><a href="http://python-guide.org">The Python Guide</a></li>
<li><a href="https://pep8.org/">pep8.org</a></li>
<li><a href="https://httpbin.org/">httpbin.org</a></li>
<li><a href="https://docs.python-guide.org/">The Python Guide</a></li>
<li><a href="https://github.com/kennethreitz/maya">Maya: Datetimes for Humans</a></li>
<li><a href="https://github.com/kennethreitz/records">Records: SQL for Humans</a></li>
<li><a href="http://www.git-legit.org">Legit: Git for Humans</a></li>
@@ -66,4 +61,3 @@
<li><a href="http://it.python-requests.org/">Italian</a></li>
<li><a href="http://es.python-requests.org/">Spanish</a></li>
</ul>

View File

@@ -109,17 +109,7 @@ Status Code Lookup
.. autoclass:: requests.codes
::
>>> requests.codes['temporary_redirect']
307
>>> requests.codes.teapot
418
>>> requests.codes['\o/']
200
.. automodule:: requests.status_codes
Migrating to 1.x
@@ -149,7 +139,7 @@ API Changes
s = requests.Session() # formerly, session took parameters
s.auth = auth
s.headers.update(headers)
r = s.get('http://httpbin.org/headers')
r = s.get('https://httpbin.org/headers')
* All request hooks have been removed except 'response'.
@@ -191,11 +181,11 @@ API Changes
logging.basicConfig() # you need to initialize logging, otherwise you will not see anything from requests
logging.getLogger().setLevel(logging.DEBUG)
requests_log = logging.getLogger("requests.packages.urllib3")
requests_log = logging.getLogger("urllib3")
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True
requests.get('http://httpbin.org/headers')
requests.get('https://httpbin.org/headers')
@@ -207,8 +197,8 @@ license from the ISC_ license to the `Apache 2.0`_ license. The Apache 2.0
license ensures that contributions to Requests are also covered by the Apache
2.0 license.
.. _ISC: http://opensource.org/licenses/ISC
.. _Apache 2.0: http://opensource.org/licenses/Apache-2.0
.. _ISC: https://opensource.org/licenses/ISC
.. _Apache 2.0: https://opensource.org/licenses/Apache-2.0
Migrating to 2.x
@@ -223,7 +213,7 @@ For more details on the changes in this release including new APIs, links
to the relevant GitHub issues and some of the bug fixes, read Cory's blog_
on the subject.
.. _blog: http://lukasa.co.uk/2013/09/Requests_20/
.. _blog: https://lukasa.co.uk/2013/09/Requests_20/
API Changes

View File

@@ -3,6 +3,8 @@
Frequently Asked Questions
==========================
.. image:: https://farm5.staticflickr.com/4290/35294660055_42c02b2316_k_d.jpg
This part of the documentation answers common questions about Requests.
Encoded Data?
@@ -54,12 +56,11 @@ Python 3 Support?
Yes! Here's a list of Python platforms that are officially
supported:
* Python 2.6
* Python 2.7
* Python 3.3
* Python 3.4
* Python 3.5
* Python 3.6
* Python 3.7
* PyPy
What are "hostname doesn't match" errors?
@@ -69,7 +70,7 @@ These errors occur when :ref:`SSL certificate verification <verification>`
fails to match the certificate the server responds with to the hostname
Requests thinks it's contacting. If you're certain the server's SSL setup is
correct (for example, because you can visit the site with your browser) and
you're using Python 2.6 or 2.7, a possible explanation is that you need
you're using Python 2.7, a possible explanation is that you need
Server-Name-Indication.
`Server-Name-Indication`_, or SNI, is an official extension to SSL where the

View File

@@ -1,6 +1,8 @@
Integrations
============
.. image:: https://farm5.staticflickr.com/4239/34450900674_15863ddea0_k_d.jpg
Python for iOS
--------------
@@ -13,10 +15,10 @@ To give it a try, simply::
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 Greenfeld'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/>`_
- `Python for the Web <https://www.gun.io/blog/python-for-the-web>`_ teaches how to use Python to interact with the web, using Requests.
- `Daniel Greenfeld's Review of Requests <https://pydanny.blogspot.com/2011/05/python-http-requests-for-humans.html>`_
- `My 'Python for Humans' talk <http://python-for-humans.heroku.com>`_ ( `audio <https://codeconf.s3.amazonaws.com/2011/pycodeconf/talks/PyCodeConf2011%20-%20Kenneth%20Reitz.m4a>`_ )
- `Issac Kelly's 'Consuming Web APIs' talk <https://issackelly.github.com/Consuming-Web-APIs-with-Python-Talk/slides/slides.html>`_
- `Blog post about Requests via Yum <https://arunsag.wordpress.com/2011/08/17/new-package-python-requests-http-for-humans/>`_
- `Russian blog post introducing Requests <https://habr.com/post/126262/>`_
- `Sending JSON in Requests <http://www.coglib.com/~icordasc/blog/2014/11/sending-json-in-requests.html>`_

View File

@@ -3,6 +3,8 @@
Recommended Packages and Extensions
===================================
.. image:: https://farm5.staticflickr.com/4218/35224319272_cfc0e621fb_k_d.jpg
Requests has a great variety of powerful and useful third-party extensions.
This page provides an overview of some of the best of them.
@@ -13,7 +15,7 @@ Certifi CA Bundle
validating the trustworthiness of SSL certificates while verifying the
identity of TLS hosts. It has been extracted from the Requests project.
.. _Certifi: http://certifi.io/en/latest/
.. _Certifi: https://github.com/certifi/python-certifi
CacheControl
------------
@@ -32,7 +34,15 @@ but do not belong in Requests proper. This library is actively maintained
by members of the Requests core team, and reflects the functionality most
requested by users within the community.
.. _Requests-Toolbelt: http://toolbelt.readthedocs.io/en/latest/index.html
.. _Requests-Toolbelt: https://toolbelt.readthedocs.io/en/latest/index.html
Requests-Threads
----------------
`Requests-Threads` is a Requests session that returns the amazing Twisted's awaitable Deferreds instead of Response objects. This allows the use of ``async``/``await`` keyword usage on Python 3, or Twisted's style of programming, if desired.
.. _Requests-Threads: https://github.com/requests/requests-threads
Requests-OAuthlib
-----------------
@@ -52,6 +62,3 @@ Betamax
A VCR imitation designed only for Python-Requests.
.. _betamax: https://github.com/sigmavirus24/betamax

View File

@@ -1,6 +1,8 @@
Release Process and Rules
=========================
.. image:: https://farm5.staticflickr.com/4215/34450901614_b74ae720db_k_d.jpg
.. versionadded:: v2.6.2
Starting with the version to be released after ``v2.6.2``, the following rules
@@ -17,19 +19,18 @@ Breaking changes are changes that break backwards compatibility with prior
versions. If the project were to change the ``text`` attribute on a
``Response`` object to a method, that would only happen in a Major release.
Major releases may also include miscellaneous bug fixes and upgrades to
vendored packages. The core developers of Requests are committed to providing
a good user experience. This means we're also committed to preserving
backwards compatibility as much as possible. Major releases will be infrequent
and will need strong justifications before they are considered.
Major releases may also include miscellaneous bug fixes. The core developers of
Requests are committed to providing a good user experience. This means we're
also committed to preserving backwards compatibility as much as possible. Major
releases will be infrequent and will need strong justifications before they are
considered.
Minor Releases
--------------
A minor release will not include breaking changes but may include
miscellaneous bug fixes and upgrades to vendored packages. If the previous
version of Requests released was ``v10.2.7`` a minor release would be
versioned as ``v10.3.0``.
A minor release will not include breaking changes but may include miscellaneous
bug fixes. If the previous version of Requests released was ``v10.2.7`` a minor
release would be versioned as ``v10.3.0``.
Minor releases will be backwards compatible with releases that have the same
major version number. In other words, all versions that would start with

View File

@@ -0,0 +1,96 @@
Community Sponsors
==================
**tl;dr**: Requests development is currently `funded by the Python community <https://www.kennethreitz.org/requests3>`_, and
some wonderful organizations that utilize the software in their businesses.
-------------------
Requests is one of the most heavilyutilized Python packages in the world.
It is used by major corporations worldwide for all tasks, both small and large — from writing oneoff scripts to orchestrating millions of dollars of critical infrastructure.
It's even embedded within pip, that tool that you use to install packages and deploy with every day!
After losing our primary open source maintainer (who was sponsored by a company to work on Requests, and other projects, fulltime), we are seeking community financial contributions towards the development of Requests 3.0.
Patron Sponsors
----------------
`Linode — SSD Cloud Hosting & Linux Servers <https://www.linode.com>`_
//////////////////////////////////////////////////////////////////////
Whether youre just getting started or deploying a complex system, launching a Linode cloud server has never been easier. They offer the fastest hardware and network in the industry with scalable environments, and their 24x7 customer support team is always standing by to help with any questions.
✨🍰✨
//////
----------------------------------
This slot is reserved for ethical organizations willing to invest $10,000 or more in Requests per year.
By becoming a patronlevel sponsor, your organization will receive the following benefits:
- Prominent placement on the Requests documentation sidebar (~11,000 uniques / day).
- Honorable mention here, with logo.
- Peace of mind knowing that the infrastructure you rely on is being actively maintained.
Organizations that sign up will be listed in order — first come first serve!
Major Sponsors
--------------
The following organizations have significantly contributed towards Requests' sustainability:
`Slack — Bring your team together <https://slack.com>`_
///////////////////////////////////////////////////////
Slack was extremely kind to be the first organization to generously donate a large sum towards the `2018 Requests 3.0 fundraiser <https://www.kennethreitz.org/requests3>`_, surpassing our entire fundraising goal immediately! They are helping the world become a better place through connectiveness, and reducing the amount of email we all have
to deal with on a daily basis.
P.S. They're `hiring <https://slack.com/careers#openings>`_!
`Twilio — Voice, SMS, and Video for Humans <https://www.twilio.com>`_
/////////////////////////////////////////////////////////////////////
Twilio was the second organization to generously donate a large sum towards the `2018 Requests 3.0 fundraiser <https://www.kennethreitz.org/requests3>`_, matching the donation of Slack! They are helping the world become a better place through interconnectivity,
providing easytouse APIs, and empowering developers world-over to help humans communicate in meaningful and effictive ways.
`Azure Cloud Developer Advocates <https://developer.microsoft.com/en-us/advocates/>`_
/////////////////////////////////////////////////////////////////////////////////////
Azure was the third organization to generously donate a large sum towards the `2018 Requests 3.0 fundraiser <https://www.kennethreitz.org/requests3>`_, matching the donation of Twilio! Awesome group of generous folks :)
`Niteo — Web Systems Development <https://www.niteoweb.com>`_
/////////////////////////////////////////////////////////////
Niteo was the fourth company to generously donate towards the `2018 Requests 3.0 fundraiser <https://www.kennethreitz.org/requests3>`_. Niteo is a company employing tech enthusiasts from all over the world
who love to build great stuff.
`Heroku <https://heroku.com/python>`_
/////////////////////////////////////
Heroku has allowed Kenneth Reitz to work on some open source projects during work hours,
including Requests (but mostly Pipenv), from timetotime, so they are listed
here as an honorable mention.
----------------
If your organization is interested in becoming either a sponsor or a patron, please `send us an email <mailto:me@kennethreitz.org>`_.
Individual Sponsors
-------------------
Countless individuals, too many to list here, have individually contributed towards the sustainability of the Requests
project over the years. Some, financially, others, with code. Contributions (from humans) of all kinds are greatly
appreciated.
✨🍰✨

View File

@@ -3,20 +3,22 @@
Support
=======
.. image:: https://farm5.staticflickr.com/4198/34080352913_5c13ffb336_k_d.jpg
If you have questions or issues about Requests, there are several options:
StackOverflow
Stack Overflow
-------------
If your question does not contain sensitive (possibly proprietary)
information or can be properly anonymized, please ask a question on
`StackOverflow <https://stackoverflow.com/questions/tagged/python-requests>`_
`Stack Overflow <https://stackoverflow.com/questions/tagged/python-requests>`_
and use the tag ``python-requests``.
Send a Tweet
------------
If your question is less than 140 characters, feel free to send a tweet to
If your question is less than 280 characters, feel free to send a tweet to
`@kennethreitz <https://twitter.com/kennethreitz>`_,
`@sigmavirus24 <https://twitter.com/sigmavirus24>`_, or
`@lukasaoz <https://twitter.com/lukasaoz>`_.
@@ -26,7 +28,7 @@ File an Issue
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>`_.
`file an issue on GitHub <https://github.com/requests/requests/issues>`_.
E-mail

View File

@@ -4,6 +4,8 @@
Community Updates
=================
.. image:: https://farm5.staticflickr.com/4244/34080354873_516c283ad0_k_d.jpg
If you'd like to stay up to date on the community and development of Requests,
there are several options:
@@ -12,7 +14,7 @@ GitHub
------
The best way to track the development of Requests is through
`the GitHub repo <https://github.com/kennethreitz/requests>`_.
`the GitHub repo <https://github.com/requests/requests>`_.
Twitter
-------
@@ -27,4 +29,3 @@ Release and Version History
===========================
.. include:: ../../HISTORY.rst

View File

@@ -1,6 +1,8 @@
Vulnerability Disclosure
========================
.. image:: https://farm5.staticflickr.com/4211/34709353644_b041e9e1c2_k_d.jpg
If you think you have found a potential security vulnerability in requests,
please email `sigmavirus24 <mailto:graffatcolmingov@gmail.com>`_ and
`Lukasa <mailto:cory@lukasa.co.uk>`_ directly. **Do not file a public issue.**
@@ -95,11 +97,11 @@ Previous CVEs
- Fixed in 2.6.0
- `CVE 2015-2296 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2015-2296>`_,
- `CVE 2015-2296 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=2015-2296>`_,
reported by Matthew Daley of `BugFuzz <https://bugfuzz.com/>`_.
- Fixed in 2.3.0
- `CVE 2014-1829 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1829>`_
- `CVE 2014-1829 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1829>`_
- `CVE 2014-1830 <http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1830>`_
- `CVE 2014-1830 <http://cve.mitre.org/cgi-bin/cvename.cgi?name=2014-1830>`_

View File

@@ -58,7 +58,7 @@ master_doc = 'index'
# General information about the project.
project = u'Requests'
copyright = u'MMXVII. A <a href="http://kennethreitz.com/pages/open-projects.html">Kenneth Reitz</a> Project'
copyright = u'MMXVIII. A <a href="http://kennethreitz.com/pages/open-projects.html">Kenneth Reitz</a> Project'
author = u'Kenneth Reitz'
# The version info for the project you're documenting, acts as replacement for
@@ -126,10 +126,11 @@ html_theme = 'alabaster'
# documentation.
html_theme_options = {
'show_powered_by': False,
'github_user': 'kennethreitz',
'github_user': 'requests',
'github_repo': 'requests',
'github_banner': True,
'show_related': False
'show_related': False,
'note_bg': '#FFF59C'
}
# Add any paths that contain custom themes here, relative to this directory.
@@ -375,4 +376,7 @@ epub_exclude_files = ['search.html']
# If false, no index is generated.
#epub_use_index = True
intersphinx_mapping = {'urllib3': ('http://urllib3.readthedocs.io/en/latest', None)}
intersphinx_mapping = {
'python': ('https://docs.python.org/3/', None),
'urllib3': ('https://urllib3.readthedocs.io/en/latest', None),
}

View File

@@ -1,5 +1,6 @@
Authors
=======
.. image:: https://static1.squarespace.com/static/533ad9bde4b098d084a846b1/t/534f6e1ce4b09b70f38ee6c1/1432265542589/DSCF3147.jpg?format=2500w
.. include:: ../../AUTHORS.rst

View File

@@ -3,6 +3,8 @@
Contributor's Guide
===================
.. image:: https://farm5.staticflickr.com/4237/35550408335_7671fde302_k_d.jpg
If you're reading this, you're probably interested in contributing to Requests.
Thank you very much! Open source projects live-and-die based on the support
they receive from others, and the fact that you're even considering
@@ -39,7 +41,7 @@ including reporting bugs or requesting features. This golden rule is
**All contributions are welcome**, as long as
everyone involved is treated with respect.
.. _be cordial or be on your way: http://kennethreitz.org/be-cordial-or-be-on-your-way/
.. _be cordial or be on your way: https://www.kennethreitz.org/essays/be-cordial-or-be-on-your-way
.. _early-feedback:
@@ -155,7 +157,7 @@ model methods (e.g. ``__repr__``) are typically the exception to this rule.
Thanks for helping to make the world a better place!
.. _PEP 8: http://pep8.org
.. _PEP 8: https://pep8.org/
.. _line continuations: https://www.python.org/dev/peps/pep-0008/#indentation
Documentation Contributions
@@ -187,7 +189,7 @@ through the `GitHub issues`_, **both open and closed**, to confirm that the bug
hasn't been reported before. Duplicate bug reports are a huge drain on the time
of other contributors, and should be avoided as much as possible.
.. _GitHub issues: https://github.com/kennethreitz/requests/issues
.. _GitHub issues: https://github.com/requests/requests/issues
Feature Requests
@@ -203,4 +205,4 @@ while keeping an open ear and mind.
If you believe there is a feature missing, feel free to raise a feature
request, but please do be aware that the overwhelming likelihood is that your
feature request will not be accepted.
feature request will not be accepted.

View File

@@ -1,15 +1,17 @@
Development Philosophy
======================
.. image:: https://farm5.staticflickr.com/4231/34484831073_636008a23d_k_d.jpg
Requests is an open but opinionated library, created by an open but opinionated developer.
Management Style
~~~~~~~~~~~~~~~~
`Kenneth Reitz <http://kennethreitz.org>`_ is the BDFL. He has final say in any decision related to the Requests project. Kenneth is responsible for the direction and form of the library. In addition to making decisions based on technical merit, he is responsible for making decisions based on the development philosophy of Requests. Only Kenneth may merge code into Requests.
`Kenneth Reitz <https://www.kennethreitz.org/>`_ is the BDFL. He has final say in any decision related to the Requests project. Kenneth is responsible for the direction and form of the library, as well as its presentation. In addition to making decisions based on technical merit, he is responsible for making decisions based on the development philosophy of Requests.
`Ian Cordasco <http://www.coglib.com/~icordasc/>`_ and `Cory Benfield <https://lukasa.co.uk/about/>`_ are the core contributors. They are responsible for triaging bug reports, reviewing pull requests and ensuring that Kenneth is kept up to speed with developments around the library. The day-to-day managing of the project is done by the core contributors. They are responsible for making judgements about whether or not a feature request is likely to be accepted by Kenneth. They do not have the authority to change code or merge code changes, though they may change documentation. Their word is not final.
`Ian Cordasco <http://www.coglib.com/~icordasc/>`_ and `Cory Benfield <https://lukasa.co.uk/about/>`_ are the core contributors. They are responsible for triaging bug reports, reviewing pull requests and ensuring that Kenneth is kept up to speed with developments around the library. The day-to-day managing of the project is done by the core contributors. They are responsible for making judgements about whether or not a feature request is likely to be accepted by Kenneth. Their word is, in some ways, more final than Kenneth's.
Values
~~~~~~
@@ -24,13 +26,17 @@ 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.
Requests uses `Semantic Versioning <https://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.
.. raw:: html
<script async class="speakerdeck-embed" data-id="68f22f0841734d848315c618111b13ea" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
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.
Linux Distro Packages

View File

@@ -1,16 +1,18 @@
How to Help
===========
.. image:: https://farm5.staticflickr.com/4290/34450900104_bc1d424213_k_d.jpg
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 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 and start making your
#. Fork `the repository <https://github.com/requests/requests>`_ on GitHub and start making your
changes to a new branch.
#. Write a test which shows that the bug was fixed.
#. 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/master/AUTHORS.rst>`_.
Make sure to add yourself to `AUTHORS <https://github.com/requests/requests/blob/master/AUTHORS.rst>`_.
Feature Freeze
--------------
@@ -23,10 +25,11 @@ Development Dependencies
You'll need to install py.test in order to run the Requests' test suite::
$ pip install pipenv
$ pipenv lock
$ pipenv install --dev
$ pipenv run py.test tests
$ venv .venv
$ source .venv/bin/activate
$ make
$ python setup.py test
============================= test session starts ==============================
platform darwin -- Python 3.4.4, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
...
@@ -41,31 +44,21 @@ You'll need to install py.test in order to run the Requests' test suite::
============== 442 passed, 1 skipped, 2 xpassed in 46.48 seconds ===============
You can also run ``$ make tests`` to run against all supported Python versions, using tox/detox.
Runtime Environments
--------------------
Requests currently supports the following versions of Python:
- Python 2.6
- Python 2.7
- Python 3.3
- Python 3.4
- Python 3.5
- Python 3.6
- Python 3.7
- PyPy
Google AppEngine is not officially supported although support is available
with the `Requests-Toolbelt`_.
.. _Requests-Toolbelt: http://toolbelt.readthedocs.io/
Are you crazy?
--------------
- SPDY support would be awesome. No C extensions.
Downstream Repackaging
----------------------
If you are repackaging Requests, please note that you must also redistribute the ``cacerts.pem`` file in order to get correct SSL functionality.
.. _Requests-Toolbelt: https://toolbelt.readthedocs.io/

View File

@@ -3,25 +3,22 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Requests: HTTP for Humans
=========================
Requests: HTTP for Humans
==========================
Release v\ |version|. (:ref:`Installation <install>`)
.. image:: https://img.shields.io/pypi/l/requests.svg
:target: https://pypi.python.org/pypi/requests
:target: https://pypi.org/project/requests/
.. image:: https://img.shields.io/pypi/wheel/requests.svg
:target: https://pypi.python.org/pypi/requests
:target: https://pypi.org/project/requests/
.. image:: https://img.shields.io/pypi/pyversions/requests.svg
:target: https://pypi.python.org/pypi/requests
:target: https://pypi.org/project/requests/
.. image:: https://travis-ci.org/kennethreitz/requests.svg?branch=master
:target: https://travis-ci.org/kennethreitz/requests
.. image:: https://codecov.io/github/kennethreitz/requests/coverage.svg?branch=master
:target: https://codecov.io/github/kennethreitz/requests
.. image:: https://codecov.io/github/requests/requests/coverage.svg?branch=master
:target: https://codecov.io/github/requests/requests
:alt: codecov.io
.. image:: https://img.shields.io/badge/Say%20Thanks!-🦉-1EAEDB.svg
@@ -31,9 +28,12 @@ Release v\ |version|. (:ref:`Installation <install>`)
**Requests** is the only *Non-GMO* HTTP library for Python, safe for human
consumption.
*Warning: Recreational use of the Python standard library for HTTP may result in dangerous side-effects,
including: security vulnerabilities, verbose code, reinventing the wheel,
constantly reading documentation, depression, headaches, or even death.*
.. note:: The use of **Python 3** is *highly* preferred over Python 2. Consider upgrading your applications and infrastructure if you find yourself *still* using Python 2 in production today. If you are using Python 3, congratulations — you are indeed a person of excellent taste.
*Kenneth Reitz*
If you're interested in financially supporting Kenneth Reitz open source, consider visiting `this link <https://cash.me/kennethreitz>`_. Your support helps tremendously with sustainability of motivation, as Open Source is no longer part of my day job.
-------------------
@@ -62,12 +62,12 @@ are 100% automatic, thanks to `urllib3 <https://github.com/shazow/urllib3>`_.
User Testimonials
-----------------
Twitter, Spotify, Microsoft, Amazon, Lyft, BuzzFeed, Reddit, The NSA, Her Majesty's Government, Google, Twilio, Runscope, Mozilla, Heroku,
Nike, Twitter, Spotify, Microsoft, Amazon, Lyft, BuzzFeed, Reddit, The NSA, Her Majesty's Government, Google, Twilio, Runscope, Mozilla, Heroku,
PayPal, NPR, Obama for America, Transifex, Native Instruments, The Washington
Post, SoundCloud, Kippt, Sony, and Federal U.S.
Institutions that prefer to be unnamed claim to use Requests internally.
**Armin Ronacher**
**Armin Ronacher**, creator of Flask
*Requests is the perfect example how beautiful an API can be with the
right level of abstraction.*
@@ -77,14 +77,18 @@ Institutions that prefer to be unnamed claim to use Requests internally.
**Daniel Greenfeld**
*Nuked a 1200 LOC spaghetti code library with 10 lines of code thanks to
Kenneth Reitz's request library. Today has been AWESOME.*
Kenneth Reitz's Requests library. Today has been AWESOME.*
**Kenny Meyers**
*Python HTTP: When in doubt, or when not in doubt, use Requests. Beautiful,
simple, Pythonic.*
Requests is one of the most downloaded Python packages of all time, pulling in
over 11,000,000 downloads every month. All the cool kids are doing it!
over 400,000 downloads **each day**. Join the party!
If your organization uses Requests internally, consider `supporting the development of 3.0 <https://www.kennethreitz.org/requests3>`_. Your
generosity will be greatly appreciated, and help drive the project forward
into the future.
Beloved Features
----------------
@@ -107,7 +111,7 @@ Requests is ready for today's web.
- Chunked Requests
- ``.netrc`` Support
Requests officially supports Python 2.62.7 & 3.33.7, and runs great on PyPy.
Requests officially supports Python 2.7 & 3.43.7, and runs great on PyPy.
The User Guide
@@ -134,10 +138,11 @@ This part of the documentation, which is mostly prose, details the
Requests ecosystem and community.
.. toctree::
:maxdepth: 1
:maxdepth: 2
community/faq
community/sponsors
community/recommended
community/faq
community/out-there
community/support
community/vulnerabilities

View File

@@ -3,6 +3,8 @@
Advanced Usage
==============
.. image:: https://farm5.staticflickr.com/4263/35163665790_d182d84f5e_k_d.jpg
This document covers some of Requests more advanced features.
.. _session-objects:
@@ -23,8 +25,8 @@ Let's persist some cookies across requests::
s = requests.Session()
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('http://httpbin.org/cookies')
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
r = s.get('https://httpbin.org/cookies')
print(r.text)
# '{"cookies": {"sessioncookie": "123456789"}}'
@@ -38,7 +40,7 @@ is done by providing data to the properties on a Session object::
s.headers.update({'x-test': 'true'})
# both 'x-test' and 'x-test2' are sent
s.get('http://httpbin.org/headers', headers={'x-test2': 'true'})
s.get('https://httpbin.org/headers', headers={'x-test2': 'true'})
Any dictionaries that you pass to a request method will be merged with the
@@ -51,11 +53,11 @@ with the first request, but not the second::
s = requests.Session()
r = s.get('http://httpbin.org/cookies', cookies={'from-my': 'browser'})
r = s.get('https://httpbin.org/cookies', cookies={'from-my': 'browser'})
print(r.text)
# '{"cookies": {"from-my": "browser"}}'
r = s.get('http://httpbin.org/cookies')
r = s.get('https://httpbin.org/cookies')
print(r.text)
# '{"cookies": {}}'
@@ -67,7 +69,7 @@ If you want to manually add cookies to your session, use the
Sessions can also be used as context managers::
with requests.Session() as s:
s.get('http://httpbin.org/cookies/set/sessioncookie/123456789')
s.get('https://httpbin.org/cookies/set/sessioncookie/123456789')
This will make sure the session is closed as soon as the ``with`` block is
exited, even if unhandled exceptions occurred.
@@ -95,7 +97,7 @@ The ``Response`` object contains all of the information returned by the server a
also contains the ``Request`` object you created originally. Here is a simple
request to get some very important information from Wikipedia's servers::
>>> r = requests.get('http://en.wikipedia.org/wiki/Monty_Python')
>>> r = requests.get('https://en.wikipedia.org/wiki/Monty_Python')
If we want to access the headers the server sent back to us, we do this::
@@ -187,6 +189,25 @@ applied, replace the call to :meth:`Request.prepare()
print(resp.status_code)
When you are using the prepared request flow, keep in mind that it does not take into account the environment.
This can cause problems if you are using environment variables to change the behaviour of requests.
For example: Self-signed SSL certificates specified in ``REQUESTS_CA_BUNDLE`` will not be taken into account.
As a result an ``SSL: CERTIFICATE_VERIFY_FAILED`` is thrown.
You can get around this behaviour by explicity merging the environment settings into your session::
from requests import Request, Session
s = Session()
req = Request('GET', url)
prepped = s.prepare_request(req)
# Merge environment settings into session
settings = s.merge_environment_settings(prepped.url, None, None, None, None)
resp = s.send(prepped, **settings)
print(resp.status_code)
.. _verification:
SSL Cert Verification
@@ -253,21 +274,20 @@ If you specify a wrong path or an invalid cert, you'll get a SSLError::
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.
Requests uses certificates from the package `certifi`_. This allows for users
to update their trusted certificates without changing the version of Requests.
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.
Before version 2.16, Requests bundled a set of root CAs that it trusted,
sourced from the `Mozilla trust store`_. The certificates were only updated
once for each Requests version. When ``certifi`` was not installed, this led to
extremely out-of-date certificate bundles when using significantly older
versions of Requests.
For the sake of security we recommend upgrading certifi frequently!
.. _HTTP persistent connection: https://en.wikipedia.org/wiki/HTTP_persistent_connection
.. _connection pooling: http://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.connectionpool
.. _certifi: http://certifi.io/
.. _connection pooling: https://urllib3.readthedocs.io/en/latest/reference/index.html#module-urllib3.connectionpool
.. _certifi: https://certifiio.readthedocs.io/
.. _Mozilla trust store: https://hg.mozilla.org/mozilla-central/raw-file/tip/security/nss/lib/ckfw/builtins/certdata.txt
.. _body-content-workflow:
@@ -280,7 +300,7 @@ immediately. You can override this behaviour and defer downloading the response
body until you access the :attr:`Response.content <requests.Response.content>`
attribute with the ``stream`` parameter::
tarball_url = 'https://github.com/kennethreitz/requests/tarball/master'
tarball_url = 'https://github.com/requests/requests/tarball/master'
r = requests.get(tarball_url, stream=True)
At this point only the response headers have been downloaded and the connection
@@ -301,15 +321,11 @@ release the connection back to the pool unless you consume all the data or call
:meth:`Response.close <requests.Response.close>`. This can lead to
inefficiency with connections. If you find yourself partially reading request
bodies (or not reading them at all) while using ``stream=True``, you should
consider using ``contextlib.closing`` (`documented here`_), like this::
make the request within a ``with`` statement to ensure it's always closed::
from contextlib import closing
with closing(requests.get('http://httpbin.org/get', stream=True)) as r:
with requests.get('https://httpbin.org/get', stream=True) as r:
# Do things with the response here.
.. _`documented here`: http://docs.python.org/2/library/contextlib.html#contextlib.closing
.. _keep-alive:
Keep-Alive
@@ -335,13 +351,11 @@ file-like object for your body::
with open('massive-body', 'rb') as f:
requests.post('http://some.url/streamed', data=f)
.. warning:: It is strongly recommended that you open files in `binary mode`_.
This is because Requests may attempt to provide the
``Content-Length`` header for you, and if it does this value will
be set to the number of *bytes* in the file. Errors may occur if
you open the file in *text mode*.
.. _binary mode: https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files
.. warning:: It is strongly recommended that you open files in :ref:`binary
mode <tut-files>`. This is because Requests may attempt to provide
the ``Content-Length`` header for you, and if it does this value
will be set to the number of *bytes* in the file. Errors may occur
if you open the file in *text mode*.
.. _chunk-encoding:
@@ -379,7 +393,7 @@ upload image files to an HTML form with a multiple file field 'images'::
To do that, just set files to a list of tuples of ``(form_field_name, file_info)``::
>>> url = 'http://httpbin.org/post'
>>> url = 'https://httpbin.org/post'
>>> multiple_files = [
('images', ('foo.png', open('foo.png', 'rb'), 'image/png')),
('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))]
@@ -392,13 +406,11 @@ To do that, just set files to a list of tuples of ``(form_field_name, file_info)
...
}
.. warning:: It is strongly recommended that you open files in `binary mode`_.
This is because Requests may attempt to provide the
``Content-Length`` header for you, and if it does this value will
be set to the number of *bytes* in the file. Errors may occur if
you open the file in *text mode*.
.. _binary mode: https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files
.. warning:: It is strongly recommended that you open files in :ref:`binary
mode <tut-files>`. This is because Requests may attempt to provide
the ``Content-Length`` header for you, and if it does this value
will be set to the number of *bytes* in the file. Errors may occur
if you open the file in *text mode*.
.. _event-hooks:
@@ -419,7 +431,7 @@ You can assign a hook function on a per-request basis by passing a
``{hook_name: callback_function}`` dictionary to the ``hooks`` request
parameter::
hooks=dict(response=print_url)
hooks={'response': print_url}
That ``callback_function`` will receive a chunk of data as its first
argument.
@@ -433,14 +445,38 @@ If an error occurs while executing your callback, a warning is given.
If the callback function returns a value, it is assumed that it is to
replace the data that was passed in. If the function doesn't return
anything, nothing else is effected.
anything, nothing else is affected.
::
def record_hook(r, *args, **kwargs):
r.hook_called = True
return r
Let's print some request method arguments at runtime::
>>> requests.get('http://httpbin.org', hooks=dict(response=print_url))
http://httpbin.org
>>> requests.get('https://httpbin.org/', hooks={'response': print_url})
https://httpbin.org/
<Response [200]>
You can add multiple hooks to a single request. Let's call two hooks at once::
>>> r = requests.get('https://httpbin.org/', hooks={'response': [print_url, record_hook]})
>>> r.hook_called
True
You can also add hooks to a ``Session`` instance. Any hooks you add will then
be called on every request made to the session. For example::
>>> s = requests.Session()
>>> s.hooks['response'].append(print_url)
>>> s.get('https://httpbin.org/')
https://httpbin.org/
<Response [200]>
A ``Session`` can have multiple hooks, which will be called in the order
they are added.
.. _custom-auth:
Custom Authentication
@@ -493,7 +529,7 @@ set ``stream`` to ``True`` and iterate over the response with
import json
import requests
r = requests.get('http://httpbin.org/stream/20', stream=True)
r = requests.get('https://httpbin.org/stream/20', stream=True)
for line in r.iter_lines():
@@ -507,7 +543,7 @@ When using `decode_unicode=True` with
:meth:`Response.iter_content() <requests.Response.iter_content>`, you'll want
to provide a fallback encoding in the event the server doesn't provide one::
r = requests.get('http://httpbin.org/stream/20', stream=True)
r = requests.get('https://httpbin.org/stream/20', stream=True)
if r.encoding is None:
r.encoding = 'utf-8'
@@ -597,6 +633,8 @@ as using a HTTP one::
'https': 'socks5://user:pass@host:port'
}
Using the scheme ``socks5`` causes the DNS resolution to happen on the client, rather than on the proxy server. This is in line with curl, which uses the scheme to decide whether to do the DNS resolution on the client or proxy. If you want to resolve the domains on the proxy server, use ``socks5h`` as the scheme.
.. _compliance:
Compliance
@@ -614,12 +652,12 @@ When you receive a response, Requests makes a guess at the encoding to
use for decoding the response when you access the :attr:`Response.text
<requests.Response.text>` attribute. Requests will first check for an
encoding in the HTTP header, and if none is present, will use `chardet
<http://pypi.python.org/pypi/chardet>`_ to attempt to guess the encoding.
<https://pypi.org/project/chardet/>`_ to attempt to guess the encoding.
The only time Requests will not do this is if no explicit charset
is present in the HTTP headers **and** the ``Content-Type``
header contains ``text``. In this situation, `RFC 2616
<http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1>`_ specifies
<https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1>`_ specifies
that the default charset must be ``ISO-8859-1``. Requests follows the
specification in this case. If you require a different encoding, you can
manually set the :attr:`Response.encoding <requests.Response.encoding>`
@@ -642,7 +680,7 @@ from GitHub. Suppose we wanted commit ``a050faf`` on Requests. We would get it
like so::
>>> import requests
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')
>>> r = requests.get('https://api.github.com/repos/requests/requests/git/commits/a050faf084662f3a352dd1a941f2c7c9f886d4ad')
We should confirm that GitHub responded correctly. If it has, we want to work
out what type of content it is. Do this like so::
@@ -697,12 +735,12 @@ we should probably avoid making ham-handed POSTS to it. Instead, let's play
with the Issues feature of GitHub.
This documentation was added in response to
`Issue #482 <https://github.com/kennethreitz/requests/issues/482>`_. Given that
`Issue #482 <https://github.com/requests/requests/issues/482>`_. Given that
this issue already exists, we will use it as an example. Let's start by getting it.
::
>>> r = requests.get('https://api.github.com/repos/kennethreitz/requests/issues/482')
>>> r = requests.get('https://api.github.com/repos/requests/requests/issues/482')
>>> r.status_code
200
@@ -745,7 +783,7 @@ is to POST to the thread. Let's do it.
::
>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it!"})
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/482/comments"
>>> url = u"https://api.github.com/repos/requests/requests/issues/482/comments"
>>> r = requests.post(url=url, data=body)
>>> r.status_code
@@ -779,7 +817,7 @@ that.
5804413
>>> body = json.dumps({u"body": u"Sounds great! I'll get right on it once I feed my cat."})
>>> url = u"https://api.github.com/repos/kennethreitz/requests/issues/comments/5804413"
>>> url = u"https://api.github.com/repos/requests/requests/issues/comments/5804413"
>>> r = requests.patch(url=url, data=body, auth=auth)
>>> r.status_code
@@ -841,7 +879,7 @@ Link Headers
Many HTTP APIs feature Link headers. They make APIs more self describing and
discoverable.
GitHub uses these for `pagination <http://developer.github.com/v3/#pagination>`_
GitHub uses these for `pagination <https://developer.github.com/v3/#pagination>`_
in their API, for example::
>>> url = 'https://api.github.com/users/kennethreitz/repos?page=1&per_page=10'
@@ -883,7 +921,7 @@ it should apply to.
::
>>> s = requests.Session()
>>> s.mount('http://www.github.com', MyAdapter())
>>> s.mount('https://github.com/', MyAdapter())
The mount call registers a specific instance of a Transport Adapter to a
prefix. Once mounted, any HTTP request made using that session whose URL starts
@@ -908,9 +946,9 @@ passed-through to `urllib3`. We'll make a Transport Adapter that instructs the
library to use SSLv3::
import ssl
from urllib3.poolmanager import PoolManager
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.poolmanager import PoolManager
class Ssl3HttpAdapter(HTTPAdapter):
@@ -921,7 +959,7 @@ library to use SSLv3::
num_pools=connections, maxsize=maxsize,
block=block, ssl_version=ssl.PROTOCOL_SSLv3)
.. _`described here`: http://www.kennethreitz.org/essays/the-future-of-python-http
.. _`described here`: https://www.kennethreitz.org/essays/the-future-of-python-http
.. _`urllib3`: https://github.com/shazow/urllib3
.. _blocking-or-nonblocking:
@@ -938,8 +976,9 @@ response at a time. However, these calls will still block.
If you are concerned about the use of blocking IO, there are lots of projects
out there that combine Requests with one of Python's asynchronicity frameworks.
Two excellent examples are `grequests`_ and `requests-futures`_.
Some excellent examples are `requests-threads`_, `grequests`_, and `requests-futures`_.
.. _`requests-threads`: https://github.com/requests/requests-threads
.. _`grequests`: https://github.com/kennethreitz/grequests
.. _`requests-futures`: https://github.com/ross/requests-futures
@@ -964,7 +1003,7 @@ The **connect** timeout is the number of seconds Requests will wait for your
client to establish a connection to a remote machine (corresponding to the
`connect()`_) call on the socket. It's a good practice to set connect timeouts
to slightly larger than a multiple of 3, which is the default `TCP packet
retransmission window <http://www.hjp.at/doc/rfc/rfc2988.txt>`_.
retransmission window <https://www.hjp.at/doc/rfc/rfc2988.txt>`_.
Once your client has connected to the server and sent the HTTP request, the
**read** timeout is the number of seconds the client will wait for the server
@@ -989,4 +1028,4 @@ coffee.
r = requests.get('https://github.com', timeout=None)
.. _`connect()`: http://linux.die.net/man/2/connect
.. _`connect()`: https://linux.die.net/man/2/connect

View File

@@ -3,6 +3,8 @@
Authentication
==============
.. image:: https://farm5.staticflickr.com/4258/35550409215_3b08d49d22_k_d.jpg
This document discusses using various kinds of authentication with Requests.
Many web services require authentication, and there are many different types.
@@ -51,7 +53,7 @@ Another very popular form of HTTP Authentication is Digest Authentication,
and Requests supports this out of the box as well::
>>> from requests.auth import HTTPDigestAuth
>>> url = 'http://httpbin.org/digest-auth/auth/user/pass'
>>> url = 'https://httpbin.org/digest-auth/auth/user/pass'
>>> requests.get(url, auth=HTTPDigestAuth('user', 'pass'))
<Response [200]>
@@ -120,7 +122,7 @@ To do so, subclass :class:`AuthBase <requests.auth.AuthBase>` and implement the
... # Implement my authentication
... return r
...
>>> url = 'http://httpbin.org/get'
>>> url = 'https://httpbin.org/get'
>>> requests.get(url, auth=MyAuth())
<Response [200]>
@@ -132,13 +134,13 @@ authentication will additionally add hooks to provide further functionality.
Further examples can be found under the `Requests organization`_ and in the
``auth.py`` file.
.. _OAuth: http://oauth.net/
.. _OAuth: https://oauth.net/
.. _requests_oauthlib: https://github.com/requests/requests-oauthlib
.. _requests-oauthlib OAuth2 documentation: http://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html
.. _Web Application Flow: http://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#web-application-flow
.. _Mobile Application Flow: http://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#mobile-application-flow
.. _Legacy Application Flow: http://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#legacy-application-flow
.. _Backend Application Flow: http://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#backend-application-flow
.. _requests-oauthlib OAuth2 documentation: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html
.. _Web Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#web-application-flow
.. _Mobile Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#mobile-application-flow
.. _Legacy Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#legacy-application-flow
.. _Backend Application Flow: https://requests-oauthlib.readthedocs.io/en/latest/oauth2_workflow.html#backend-application-flow
.. _Kerberos: https://github.com/requests/requests-kerberos
.. _NTLM: https://github.com/requests/requests-ntlm
.. _Requests organization: https://github.com/requests

View File

@@ -1,39 +1,43 @@
.. _install:
Installation
============
Installation of Requests
========================
.. image:: https://farm5.staticflickr.com/4230/35550376215_da1bf77a8c_k_d.jpg
This part of the documentation covers the installation of Requests.
The first step to using any software package is getting it properly installed.
Pip Install Requests
--------------------
$ pipenv install requests
-------------------------
To install Requests, simply run this simple command in your terminal of choice::
$ pip install requests
$ pipenv install requests
If you don't have `pip <https://pip.pypa.io>`_ installed (tisk tisk!),
`this Python installation guide <http://docs.python-guide.org/en/latest/starting/installation/>`_
If you don't have `pipenv <http://pipenv.org/>`_ installed (tisk tisk!), head over to the Pipenv website for installation instructions. Or, if you prefer to just use pip and don't have it installed,
`this Python installation guide <https://docs.python-guide.org/starting/installation/>`_
can guide you through the process.
Get the Source Code
-------------------
Requests is actively developed on GitHub, where the code is
`always available <https://github.com/kennethreitz/requests>`_.
`always available <https://github.com/requests/requests>`_.
You can either clone the public repository::
$ git clone git://github.com/kennethreitz/requests.git
$ git clone git://github.com/requests/requests.git
Or, download the `tarball <https://github.com/kennethreitz/requests/tarball/master>`_::
Or, download the `tarball <https://github.com/requests/requests/tarball/master>`_::
$ curl -OL https://github.com/kennethreitz/requests/tarball/master
# optionally, zipball is also available (for Windows users).
$ curl -OL https://github.com/requests/requests/tarball/master
# optionally, zipball is also available (for Windows users).
Once you have a copy of the source, you can embed it in your own Python
package, or install it into your site-packages easily::
$ python setup.py install
$ cd requests
$ pip install .

View File

@@ -3,6 +3,8 @@
Introduction
============
.. image:: https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg
Philosophy
----------
@@ -35,8 +37,8 @@ closed-source software.
Requests is released under terms of `Apache2 License`_.
.. _`GPL Licensed`: http://www.opensource.org/licenses/gpl-license.php
.. _`Apache2 License`: http://opensource.org/licenses/Apache-2.0
.. _`GPL Licensed`: https://opensource.org/licenses/gpl-license.php
.. _`Apache2 License`: https://opensource.org/licenses/Apache-2.0
Requests License

View File

@@ -3,6 +3,8 @@
Quickstart
==========
.. image:: https://farm5.staticflickr.com/4259/35163667010_8bfcaef274_k_d.jpg
.. module:: requests.models
Eager to get started? This page gives a good introduction in how to get started
@@ -37,15 +39,15 @@ get all the information we need from this object.
Requests' simple API means that all forms of HTTP request are as obvious. For
example, this is how you make an HTTP POST request::
>>> r = requests.post('http://httpbin.org/post', data = {'key':'value'})
>>> r = requests.post('https://httpbin.org/post', data = {'key':'value'})
Nice, right? What about the other HTTP request types: PUT, DELETE, HEAD and
OPTIONS? These are all just as simple::
>>> r = requests.put('http://httpbin.org/put', data = {'key':'value'})
>>> r = requests.delete('http://httpbin.org/delete')
>>> r = requests.head('http://httpbin.org/get')
>>> r = requests.options('http://httpbin.org/get')
>>> r = requests.put('https://httpbin.org/put', data = {'key':'value'})
>>> r = requests.delete('https://httpbin.org/delete')
>>> r = requests.head('https://httpbin.org/get')
>>> r = requests.options('https://httpbin.org/get')
That's all well and good, but it's also only the start of what Requests can
do.
@@ -63,12 +65,12 @@ using the ``params`` keyword argument. As an example, if you wanted to pass
following code::
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.get('http://httpbin.org/get', params=payload)
>>> r = requests.get('https://httpbin.org/get', params=payload)
You can see that the URL has been correctly encoded by printing the URL::
>>> print(r.url)
http://httpbin.org/get?key2=value2&key1=value1
https://httpbin.org/get?key2=value2&key1=value1
Note that any dictionary key whose value is ``None`` will not be added to the
URL's query string.
@@ -77,9 +79,9 @@ You can also pass a list of items as a value::
>>> payload = {'key1': 'value1', 'key2': ['value2', 'value3']}
>>> r = requests.get('http://httpbin.org/get', params=payload)
>>> r = requests.get('https://httpbin.org/get', params=payload)
>>> print(r.url)
http://httpbin.org/get?key1=value1&key2=value2&key2=value3
https://httpbin.org/get?key1=value1&key2=value2&key2=value3
Response Content
----------------
@@ -108,7 +110,7 @@ using, and change it, using the ``r.encoding`` property::
If you change the encoding, Requests will use the new value of ``r.encoding``
whenever you call ``r.text``. You might want to do this in any situation where
you can apply special logic to work out what the encoding of the content will
be. For example, HTTP and XML have the ability to specify their encoding in
be. For example, HTML and XML have the ability to specify their encoding in
their body. In situations like this, you should use ``r.content`` to find the
encoding, and then set ``r.encoding``. This will let you use ``r.text`` with
the correct encoding.
@@ -169,7 +171,7 @@ server, you can access ``r.raw``. If you want to do this, make sure you set
>>> r = requests.get('https://api.github.com/events', stream=True)
>>> r.raw
<requests.packages.urllib3.response.HTTPResponse object at 0x101194810>
<urllib3.response.HTTPResponse object at 0x101194810>
>>> r.raw.read(10)
'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03'
@@ -187,6 +189,14 @@ download, the above is the preferred and recommended way to retrieve the
content. Note that ``chunk_size`` can be freely adjusted to a number that
may better fit your use cases.
.. note::
An important note about using ``Response.iter_content`` versus ``Response.raw``.
``Response.iter_content`` will automatically decode the ``gzip`` and ``deflate``
transfer-encodings. ``Response.raw`` is a raw stream of bytes -- it does not
transform the response content. If you really need access to the bytes as they
were returned, use ``Response.raw``.
Custom Headers
--------------
@@ -223,7 +233,7 @@ dictionary of data will automatically be form-encoded when the request is made::
>>> payload = {'key1': 'value1', 'key2': 'value2'}
>>> r = requests.post("http://httpbin.org/post", data=payload)
>>> r = requests.post("https://httpbin.org/post", data=payload)
>>> print(r.text)
{
...
@@ -234,7 +244,30 @@ dictionary of data will automatically be form-encoded when the request is made::
...
}
There are many times that you want to send data that is not form-encoded. If
The ``data`` argument can also have multiple values for each key. This can be
done by making ``data`` either a list of tuples or a dictionary with lists
as values. This is particularly useful when the form has multiple elements that
use the same key::
>>> payload_tuples = [('key1', 'value1'), ('key1', 'value2')]
>>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples)
>>> payload_dict = {'key1': ['value1', 'value2']}
>>> r2 = requests.post('https://httpbin.org/post', data=payload_dict)
>>> print(r1.text)
{
...
"form": {
"key1": [
"value1",
"value2"
]
},
...
}
>>> r1.text == r2.text
True
There are times that you may 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.
For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data::
@@ -254,13 +287,16 @@ the ``json`` parameter (added in version 2.4.2) and it will be encoded automatic
>>> r = requests.post(url, json=payload)
Note, the ``json`` parameter is ignored if either ``data`` or ``files`` is passed.
Using the ``json`` parameter in the request will change the ``Content-Type`` in the header to ``application/json``.
POST a Multipart-Encoded File
-----------------------------
Requests makes it simple to upload Multipart-encoded files::
>>> url = 'http://httpbin.org/post'
>>> url = 'https://httpbin.org/post'
>>> files = {'file': open('report.xls', 'rb')}
>>> r = requests.post(url, files=files)
@@ -275,7 +311,7 @@ Requests makes it simple to upload Multipart-encoded files::
You can set the filename, content_type and headers explicitly::
>>> url = 'http://httpbin.org/post'
>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.xls', open('report.xls', 'rb'), 'application/vnd.ms-excel', {'Expires': '0'})}
>>> r = requests.post(url, files=files)
@@ -290,7 +326,7 @@ You can set the filename, content_type and headers explicitly::
If you want, you can send strings to be received as files::
>>> url = 'http://httpbin.org/post'
>>> url = 'https://httpbin.org/post'
>>> files = {'file': ('report.csv', 'some,data,to,send\nanother,row,to,send\n')}
>>> r = requests.post(url, files=files)
@@ -312,13 +348,11 @@ support this, but there is a separate package which does -
For sending multiple files in one request refer to the :ref:`advanced <advanced>`
section.
.. warning:: It is strongly recommended that you open files in `binary mode`_.
This is because Requests may attempt to provide the
``Content-Length`` header for you, and if it does this value will
be set to the number of *bytes* in the file. Errors may occur if
you open the file in *text mode*.
.. _binary mode: https://docs.python.org/2/tutorial/inputoutput.html#reading-and-writing-files
.. warning:: It is strongly recommended that you open files in :ref:`binary
mode <tut-files>`. This is because Requests may attempt to provide
the ``Content-Length`` header for you, and if it does this value
will be set to the number of *bytes* in the file. Errors may occur
if you open the file in *text mode*.
Response Status Codes
@@ -326,7 +360,7 @@ Response Status Codes
We can check the response status code::
>>> r = requests.get('http://httpbin.org/get')
>>> r = requests.get('https://httpbin.org/get')
>>> r.status_code
200
@@ -340,7 +374,7 @@ If we made a bad request (a 4XX client error or 5XX server error response), we
can raise it with
:meth:`Response.raise_for_status() <requests.Response.raise_for_status>`::
>>> bad_r = requests.get('http://httpbin.org/status/404')
>>> bad_r = requests.get('https://httpbin.org/status/404')
>>> bad_r.status_code
404
@@ -376,7 +410,7 @@ We can view the server's response headers using a Python dictionary::
}
The dictionary is special, though: it's made just for HTTP headers. According to
`RFC 7230 <http://tools.ietf.org/html/rfc7230#section-3.2>`_, HTTP Header names
`RFC 7230 <https://tools.ietf.org/html/rfc7230#section-3.2>`_, HTTP Header names
are case-insensitive.
So, we can access the headers using any capitalization we want::
@@ -390,7 +424,7 @@ So, we can access the headers using any capitalization we want::
It is also special in that the server could have sent the same header multiple
times with different values, but requests combines them so they can be
represented in the dictionary within a single mapping, as per
`RFC 7230 <http://tools.ietf.org/html/rfc7230#section-3.2>`_:
`RFC 7230 <https://tools.ietf.org/html/rfc7230#section-3.2>`_:
A recipient MAY combine multiple header fields with the same field name
into one "field-name: field-value" pair, without changing the semantics
@@ -411,7 +445,7 @@ If a response contains some Cookies, you can quickly access them::
To send your own cookies to the server, you can use the ``cookies``
parameter::
>>> url = 'http://httpbin.org/cookies'
>>> url = 'https://httpbin.org/cookies'
>>> cookies = dict(cookies_are='working')
>>> r = requests.get(url, cookies=cookies)
@@ -426,7 +460,7 @@ also be passed in to requests::
>>> jar = requests.cookies.RequestsCookieJar()
>>> 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'
>>> url = 'https://httpbin.org/cookies'
>>> r = requests.get(url, cookies=jar)
>>> r.text
'{"cookies": {"tasty_cookie": "yum"}}'
@@ -447,7 +481,7 @@ response.
For example, GitHub redirects all HTTP requests to HTTPS::
>>> r = requests.get('http://github.com')
>>> r = requests.get('https://github.com/')
>>> r.url
'https://github.com/'
@@ -462,7 +496,7 @@ For example, GitHub redirects all HTTP requests to HTTPS::
If you're using GET, OPTIONS, POST, PUT, PATCH or DELETE, you can disable
redirection handling with the ``allow_redirects`` parameter::
>>> r = requests.get('http://github.com', allow_redirects=False)
>>> r = requests.get('https://github.com/', allow_redirects=False)
>>> r.status_code
301
@@ -472,7 +506,7 @@ redirection handling with the ``allow_redirects`` parameter::
If you're using HEAD, you can enable redirection as well::
>>> r = requests.head('http://github.com', allow_redirects=True)
>>> r = requests.head('https://github.com/', allow_redirects=True)
>>> r.url
'https://github.com/'
@@ -485,11 +519,11 @@ Timeouts
--------
You can tell Requests to stop waiting for a response after a given number of
seconds with the ``timeout`` parameter. Nearly all production code should use
seconds with the ``timeout`` parameter. Nearly all production code should use
this parameter in nearly all requests. Failure to do so can cause your program
to hang indefinitely::
>>> requests.get('http://github.com', timeout=0.001)
>>> requests.get('https://github.com/', timeout=0.001)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
requests.exceptions.Timeout: HTTPConnectionPool(host='github.com', port=80): Request timed out. (timeout=0.001)

View File

@@ -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('https://httpbin.org/post', data=payload)
>>> print(r.text)
{
...
@@ -40,52 +40,75 @@ is at <http://python-requests.org>.
:license: Apache 2.0, see LICENSE for more details.
"""
from .__version__ import __title__, __description__, __url__, __version__
from .__version__ import __build__, __author__, __author_email__, __license__
from .__version__ import __copyright__, __cake__
# Check urllib3 for compatibility.
import urllib3
urllib3_version = urllib3.__version__.split('.')
# Sometimes, urllib3 only reports its version as 16.1.
if len(urllib3_version) == 2:
urllib3_version.append('0')
major, minor, patch = urllib3_version
major, minor, patch = int(major), int(minor), int(patch)
# urllib3 >= 1.21.1, < 1.22
try:
import chardet
import warnings
from .exceptions import RequestsDependencyWarning
def check_compatibility(urllib3_version, chardet_version):
urllib3_version = urllib3_version.split('.')
assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git.
# Sometimes, urllib3 only reports its version as 16.1.
if len(urllib3_version) == 2:
urllib3_version.append('0')
# Check urllib3 for compatibility.
major, minor, patch = urllib3_version # noqa: F811
major, minor, patch = int(major), int(minor), int(patch)
# urllib3 >= 1.21.1, <= 1.24
assert major == 1
assert minor >= 21
assert minor <= 22
except AssertionError:
raise RuntimeError('Requests dependency \'urllib3\' must be version >= 1.21.1, < 1.22!')
assert minor <= 24
# Check chardet for compatibility.
import chardet
major, minor, patch = chardet.__version__.split('.')[:3]
major, minor, patch = int(major), int(minor), int(patch)
# chardet >= 3.0.2, < 3.1.0
try:
# Check chardet for compatibility.
major, minor, patch = chardet_version.split('.')[:3]
major, minor, patch = int(major), int(minor), int(patch)
# chardet >= 3.0.2, < 3.1.0
assert major == 3
assert minor < 1
assert patch >= 2
except AssertionError:
raise RuntimeError('Requests dependency \'chardet\' must be version >= 3.0.2, < 3.1.0!')
def _check_cryptography(cryptography_version):
# cryptography < 1.3.4
try:
cryptography_version = list(map(int, cryptography_version.split('.')))
except ValueError:
return
if cryptography_version < [1, 3, 4]:
warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version)
warnings.warn(warning, RequestsDependencyWarning)
# Check imported dependencies for compatibility.
try:
check_compatibility(urllib3.__version__, chardet.__version__)
except (AssertionError, ValueError):
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
"version!".format(urllib3.__version__, chardet.__version__),
RequestsDependencyWarning)
# Attempt to enable urllib3's SNI support, if possible
try:
from urllib3.contrib import pyopenssl
pyopenssl.inject_into_urllib3()
# Check cryptography version
from cryptography import __version__ as cryptography_version
_check_cryptography(cryptography_version)
except ImportError:
pass
import warnings
# urllib3's DependencyWarnings should be silenced.
from urllib3.exceptions import DependencyWarning
warnings.simplefilter('ignore', DependencyWarning)
from .__version__ import __title__, __description__, __url__, __version__
from .__version__ import __build__, __author__, __author_email__, __license__
from .__version__ import __copyright__, __cake__
from . import utils
from . import packages
from .models import Request, Response, PreparedRequest
@@ -100,12 +123,7 @@ from .exceptions import (
# Set default logging handler to avoid "No handler found" warnings.
import logging
try: # Python 2.7+
from logging import NullHandler
except ImportError:
class NullHandler(logging.Handler):
def emit(self, record):
pass
from logging import NullHandler
logging.getLogger(__name__).addHandler(NullHandler())

View File

@@ -5,12 +5,10 @@
__title__ = 'requests'
__description__ = 'Python HTTP for Humans.'
__url__ = 'http://python-requests.org'
__version__ = '2.16.4'
__build__ = 0x021604
__version__ = '2.20.0'
__build__ = 0x022000
__author__ = 'Kenneth Reitz'
__author_email__ = 'me@kennethreitz.org'
__license__ = 'Apache 2.0'
__copyright__ = 'Copyright 2017 Kenneth Reitz'
__copyright__ = 'Copyright 2018 Kenneth Reitz'
__cake__ = u'\u2728 \U0001f370 \u2728'

View File

@@ -13,6 +13,7 @@ import socket
from urllib3.poolmanager import PoolManager, proxy_from_url
from urllib3.response import HTTPResponse
from urllib3.util import parse_url
from urllib3.util import Timeout as TimeoutSauce
from urllib3.util.retry import Retry
from urllib3.exceptions import ClosedPoolError
@@ -25,16 +26,18 @@ from urllib3.exceptions import ProtocolError
from urllib3.exceptions import ReadTimeoutError
from urllib3.exceptions import SSLError as _SSLError
from urllib3.exceptions import ResponseError
from urllib3.exceptions import LocationValueError
from .models import Response
from .compat import urlparse, basestring
from .utils import (DEFAULT_CA_BUNDLE_PATH, get_encoding_from_headers,
prepend_scheme_if_needed, get_auth_from_url, urldefragauth,
select_proxy)
from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths,
get_encoding_from_headers, prepend_scheme_if_needed,
get_auth_from_url, urldefragauth, select_proxy)
from .structures import CaseInsensitiveDict
from .cookies import extract_cookies_to_jar
from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError,
ProxyError, RetryError, InvalidSchema)
ProxyError, RetryError, InvalidSchema, InvalidProxyURL,
InvalidURL)
from .auth import _basic_auth_str
try:
@@ -126,8 +129,7 @@ class HTTPAdapter(BaseAdapter):
self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
def __getstate__(self):
return dict((attr, getattr(self, attr, None)) for attr in
self.__attrs__)
return {attr: getattr(self, attr, None) for attr in self.__attrs__}
def __setstate__(self, state):
# Can't handle by adding 'proxy_manager' to self.__attrs__ because
@@ -219,11 +221,11 @@ class HTTPAdapter(BaseAdapter):
cert_loc = verify
if not cert_loc:
cert_loc = DEFAULT_CA_BUNDLE_PATH
cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
if not cert_loc or not os.path.exists(cert_loc):
raise IOError("Could not find a suitable TLS CA certificate bundle, "
"invalid path: {0}".format(cert_loc))
"invalid path: {}".format(cert_loc))
conn.cert_reqs = 'CERT_REQUIRED'
@@ -245,10 +247,10 @@ class HTTPAdapter(BaseAdapter):
conn.key_file = None
if conn.cert_file and not os.path.exists(conn.cert_file):
raise IOError("Could not find the TLS certificate file, "
"invalid path: {0}".format(conn.cert_file))
"invalid path: {}".format(conn.cert_file))
if conn.key_file and not os.path.exists(conn.key_file):
raise IOError("Could not find the TLS key file, "
"invalid path: {0}".format(conn.key_file))
"invalid path: {}".format(conn.key_file))
def build_response(self, req, resp):
"""Builds a :class:`Response <requests.Response>` object from a urllib3
@@ -300,6 +302,10 @@ class HTTPAdapter(BaseAdapter):
if proxy:
proxy = prepend_scheme_if_needed(proxy, 'http')
proxy_url = parse_url(proxy)
if not proxy_url.host:
raise InvalidProxyURL("Please check proxy URL. It is malformed"
" and could be missing the host.")
proxy_manager = self.proxy_manager_for(proxy)
conn = proxy_manager.connection_from_url(url)
else:
@@ -373,7 +379,7 @@ class HTTPAdapter(BaseAdapter):
when subclassing the
:class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
:param proxies: The url of the proxy being used for this request.
:param proxy: The url of the proxy being used for this request.
:rtype: dict
"""
headers = {}
@@ -402,11 +408,14 @@ class HTTPAdapter(BaseAdapter):
:rtype: requests.Response
"""
conn = self.get_connection(request.url, proxies)
try:
conn = self.get_connection(request.url, proxies)
except LocationValueError as e:
raise InvalidURL(e, request=request)
self.cert_verify(conn, request.url, verify, cert)
url = self.request_url(request, proxies)
self.add_headers(request)
self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
chunked = not (request.body is None or 'Content-Length' in request.headers)
@@ -416,7 +425,7 @@ class HTTPAdapter(BaseAdapter):
timeout = TimeoutSauce(connect=connect, read=read)
except ValueError as e:
# this may raise a string formatting error.
err = ("Invalid timeout {0}. Pass a (connect, read) "
err = ("Invalid timeout {}. Pass a (connect, read) "
"timeout tuple, or a single float to set "
"both timeouts to the same value".format(timeout))
raise ValueError(err)
@@ -466,11 +475,10 @@ class HTTPAdapter(BaseAdapter):
# Receive the response from the server
try:
# For Python 2.7+ versions, use buffering of HTTP
# responses
# For Python 2.7, use buffering of HTTP responses
r = low_conn.getresponse(buffering=True)
except TypeError:
# For compatibility with Python 2.6 versions and back
# For compatibility with Python 3.3+
r = low_conn.getresponse()
resp = HTTPResponse.from_httplib(
@@ -501,6 +509,10 @@ class HTTPAdapter(BaseAdapter):
if isinstance(e.reason, _ProxyError):
raise ProxyError(e, request=request)
if isinstance(e.reason, _SSLError):
# This branch is for urllib3 v1.22 and later.
raise SSLError(e, request=request)
raise ConnectionError(e, request=request)
except ClosedPoolError as e:
@@ -511,6 +523,7 @@ class HTTPAdapter(BaseAdapter):
except (_SSLError, _HTTPError) as e:
if isinstance(e, _SSLError):
# This branch is for urllib3 versions earlier than v1.22
raise SSLError(e, request=request)
elif isinstance(e, ReadTimeoutError):
raise ReadTimeout(e, request=request)

View File

@@ -18,9 +18,11 @@ 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 list of tuples ``[(key, value)]`` (will be form-encoded), 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 params: (optional) Dictionary, list of tuples or bytes to send
in the body of the :class:`Request`.
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
:param json: (optional) A JSON serializable Python 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': file-tuple}``) for multipart encoding upload.
@@ -47,7 +49,7 @@ def request(method, url, **kwargs):
Usage::
>>> import requests
>>> req = requests.request('GET', 'http://httpbin.org/get')
>>> req = requests.request('GET', 'https://httpbin.org/get')
<Response [200]>
"""
@@ -62,7 +64,8 @@ def get(url, params=None, **kwargs):
r"""Sends a GET request.
: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 params: (optional) Dictionary, list of tuples or bytes to send
in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
@@ -73,7 +76,7 @@ def get(url, params=None, **kwargs):
def options(url, **kwargs):
r"""Sends a OPTIONS request.
r"""Sends an OPTIONS request.
:param url: URL for the new :class:`Request` object.
:param \*\*kwargs: Optional arguments that ``request`` takes.
@@ -102,7 +105,8 @@ def post(url, data=None, json=None, **kwargs):
r"""Sends a POST request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.
:param data: (optional) Dictionary, list of tuples, 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: :class:`Response <Response>` object
@@ -116,7 +120,8 @@ def put(url, data=None, **kwargs):
r"""Sends a PUT request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.
:param data: (optional) Dictionary, list of tuples, 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: :class:`Response <Response>` object
@@ -130,14 +135,15 @@ def patch(url, data=None, **kwargs):
r"""Sends a PATCH request.
:param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.
:param data: (optional) Dictionary, list of tuples, 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: :class:`Response <Response>` object
:rtype: requests.Response
"""
return request('patch', url, data=data, **kwargs)
return request('patch', url, data=data, **kwargs)
def delete(url, **kwargs):

View File

@@ -38,7 +38,7 @@ def _basic_auth_str(username, password):
if not isinstance(username, basestring):
warnings.warn(
"Non-string usernames will no longer be supported in Requests "
"3.0.0. Please convert the object you've passed in ({0!r}) to "
"3.0.0. Please convert the object you've passed in ({!r}) to "
"a string or bytes object in the near future to avoid "
"problems.".format(username),
category=DeprecationWarning,
@@ -48,7 +48,7 @@ def _basic_auth_str(username, password):
if not isinstance(password, basestring):
warnings.warn(
"Non-string passwords will no longer be supported in Requests "
"3.0.0. Please convert the object you've passed in ({0!r}) to "
"3.0.0. Please convert the object you've passed in ({!r}) to "
"a string or bytes object in the near future to avoid "
"problems.".format(password),
category=DeprecationWarning,
@@ -153,6 +153,18 @@ class HTTPDigestAuth(AuthBase):
x = x.encode('utf-8')
return hashlib.sha1(x).hexdigest()
hash_utf8 = sha_utf8
elif _algorithm == 'SHA-256':
def sha256_utf8(x):
if isinstance(x, str):
x = x.encode('utf-8')
return hashlib.sha256(x).hexdigest()
hash_utf8 = sha256_utf8
elif _algorithm == 'SHA-512':
def sha512_utf8(x):
if isinstance(x, str):
x = x.encode('utf-8')
return hashlib.sha512(x).hexdigest()
hash_utf8 = sha512_utf8
KD = lambda s, d: hash_utf8("%s:%s" % (s, d))
@@ -192,7 +204,7 @@ class HTTPDigestAuth(AuthBase):
elif qop == 'auth' or 'auth' in qop.split(','):
noncebit = "%s:%s:%s:%s:%s" % (
nonce, ncvalue, cnonce, 'auth', HA2
)
)
respdig = KD(HA1, noncebit)
else:
# XXX handle auth-int.
@@ -227,7 +239,7 @@ class HTTPDigestAuth(AuthBase):
"""
# If response is not 4xx, do not auth
# See https://github.com/kennethreitz/requests/issues/3772
# See https://github.com/requests/requests/issues/3772
if not 400 <= r.status_code < 500:
self._thread_local.num_401_calls = 1
return r

View File

@@ -27,9 +27,7 @@ is_py3 = (_ver[0] == 3)
try:
import simplejson as json
except (ImportError, SyntaxError):
# simplejson does not support Python 3.2, it throws a SyntaxError
# because of u'...' Unicode literals.
except ImportError:
import json
# ---------
@@ -45,8 +43,8 @@ if is_py2:
import cookielib
from Cookie import Morsel
from StringIO import StringIO
from collections import Callable, Mapping, MutableMapping, OrderedDict
from urllib3.packages.ordered_dict import OrderedDict
builtin_str = str
bytes = str
@@ -62,6 +60,7 @@ elif is_py3:
from http.cookies import Morsel
from io import StringIO
from collections import OrderedDict
from collections.abc import Callable, Mapping, MutableMapping
builtin_str = str
str = str

View File

@@ -12,10 +12,9 @@ requests.utils imports from here, so be careful with imports.
import copy
import time
import calendar
import collections
from ._internal_utils import to_native_string
from .compat import cookielib, urlparse, urlunparse, Morsel
from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping
try:
import threading
@@ -169,7 +168,7 @@ class CookieConflictError(RuntimeError):
"""
class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
"""Compatibility class; is a cookielib.CookieJar, but exposes a dict
interface.
@@ -306,8 +305,10 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
"""
dictionary = {}
for cookie in iter(self):
if (domain is None or cookie.domain == domain) and (path is None
or cookie.path == path):
if (
(domain is None or cookie.domain == domain) and
(path is None or cookie.path == path)
):
dictionary[cookie.name] = cookie.value
return dictionary
@@ -413,9 +414,14 @@ class RequestsCookieJar(cookielib.CookieJar, collections.MutableMapping):
def copy(self):
"""Return a copy of this RequestsCookieJar."""
new_cj = RequestsCookieJar()
new_cj.set_policy(self.get_policy())
new_cj.update(self)
return new_cj
def get_policy(self):
"""Return the CookiePolicy instance used."""
return self._policy
def _copy_cookie_jar(jar):
if jar is None:
@@ -438,20 +444,21 @@ def create_cookie(name, value, **kwargs):
By default, the pair of `name` and `value` will be set for the domain ''
and sent on every request (this is sometimes called a "supercookie").
"""
result = dict(
version=0,
name=name,
value=value,
port=None,
domain='',
path='/',
secure=False,
expires=None,
discard=True,
comment=None,
comment_url=None,
rest={'HttpOnly': None},
rfc2109=False,)
result = {
'version': 0,
'name': name,
'value': value,
'port': None,
'domain': '',
'path': '/',
'secure': False,
'expires': None,
'discard': True,
'comment': None,
'comment_url': None,
'rest': {'HttpOnly': None},
'rfc2109': False,
}
badargs = set(kwargs) - set(result)
if badargs:
@@ -505,6 +512,7 @@ def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
:param cookiejar: (optional) A cookiejar to add the cookies to.
:param overwrite: (optional) If False, will not replace cookies
already in the jar with new ones.
:rtype: CookieJar
"""
if cookiejar is None:
cookiejar = RequestsCookieJar()
@@ -523,6 +531,7 @@ def merge_cookies(cookiejar, cookies):
:param cookiejar: CookieJar object to add the cookies to.
:param cookies: Dictionary or CookieJar object to be added.
:rtype: CookieJar
"""
if not isinstance(cookiejar, cookielib.CookieJar):
raise ValueError('You can only merge into CookieJar')

View File

@@ -85,6 +85,10 @@ class InvalidHeader(RequestException, ValueError):
"""The header value provided was somehow invalid."""
class InvalidProxyURL(InvalidURL):
"""The proxy URL provided is invalid."""
class ChunkedEncodingError(RequestException):
"""The server declared chunked encoding but sent an invalid chunk."""
@@ -100,6 +104,7 @@ class StreamConsumedError(RequestException, TypeError):
class RetryError(RequestException):
"""Custom retries logic failed"""
class UnrewindableBodyError(RequestException):
"""Requests encountered an error when trying to rewind a body"""
@@ -114,3 +119,8 @@ class RequestsWarning(Warning):
class FileModeWarning(RequestsWarning, DeprecationWarning):
"""A file was opened in text mode, but Requests determined its binary length."""
pass
class RequestsDependencyWarning(RequestsWarning):
"""An imported dependency doesn't match the expected version range."""
pass

View File

@@ -6,13 +6,14 @@ import platform
import sys
import ssl
import idna
import urllib3
import chardet
from . import __version__ as requests_version
try:
from .packages.urllib3.contrib import pyopenssl
from urllib3.contrib import pyopenssl
except ImportError:
pyopenssl = None
OpenSSL = None
@@ -23,7 +24,7 @@ else:
def _implementation():
"""Return a dict with the Python implementation and verison.
"""Return a dict with the Python implementation and version.
Provide both the name and the version of the Python implementation
currently running. For example, on CPython 2.7.5 it will return
@@ -44,7 +45,7 @@ def _implementation():
if sys.pypy_version_info.releaselevel != 'final':
implementation_version = ''.join([
implementation_version, sys.pypy_version_info.releaselevel
])
])
elif implementation == 'Jython':
implementation_version = platform.python_version() # Complete Guess
elif implementation == 'IronPython':
@@ -69,8 +70,8 @@ def info():
}
implementation_info = _implementation()
urllib3_info = urllib3.__version__
chardet_info = chardet.__version__
urllib3_info = {'version': urllib3.__version__}
chardet_info = {'version': chardet.__version__}
pyopenssl_info = {
'version': None,
@@ -84,27 +85,35 @@ def info():
cryptography_info = {
'version': getattr(cryptography, '__version__', ''),
}
idna_info = {
'version': getattr(idna, '__version__', ''),
}
system_ssl = ssl.OPENSSL_VERSION_NUMBER
system_ssl_info = {
'version': '%x' % system_ssl if system_ssl is not None else ''
}
return {
'platform': platform_info,
'implementation': implementation_info,
'system_ssl': {
'version': '%x' % ssl.OPENSSL_VERSION_NUMBER,
},
'system_ssl': system_ssl_info,
'using_pyopenssl': pyopenssl is not None,
'pyOpenSSL': pyopenssl_info,
'urllib3': urllib3_info,
'chardet': chardet_info,
'cryptography': cryptography_info,
'idna': idna_info,
'requests': {
'version': requests_version,
},
}
def main():
"""Pretty-print the bug information as JSON."""
print(json.dumps(info(), sort_keys=True, indent=2))
if __name__ == '__main__':
main()

View File

@@ -15,14 +15,14 @@ HOOKS = ['response']
def default_hooks():
return dict((event, []) for event in HOOKS)
return {event: [] for event in HOOKS}
# TODO: response is the only one
def dispatch_hook(key, hooks, hook_data, **kwargs):
"""Dispatches a hook dictionary on a given piece of data."""
hooks = hooks or dict()
hooks = hooks or {}
hooks = hooks.get(key)
if hooks:
if hasattr(hooks, '__call__'):

View File

@@ -7,13 +7,12 @@ requests.models
This module contains the primary objects that power Requests.
"""
import collections
import datetime
import sys
# Import encoding now, to avoid implicit import later.
# Implicit import within threads may cause LookupError when standard library is in a ZIP,
# such as in Embedded Python. See https://github.com/kennethreitz/requests/issues/3578.
# such as in Embedded Python. See https://github.com/requests/requests/issues/3578.
import encodings.idna
from urllib3.fields import RequestField
@@ -37,6 +36,7 @@ from .utils import (
stream_decode_response_unicode, to_key_val_list, parse_header_links,
iter_slices, guess_json_utf, super_len, check_header_validity)
from .compat import (
Callable, Mapping,
cookielib, urlunparse, urlsplit, urlencode, str, bytes,
is_py2, chardet, builtin_str, basestring)
from .compat import json as complexjson
@@ -155,8 +155,12 @@ class RequestEncodingMixin(object):
if isinstance(fp, (str, bytes, bytearray)):
fdata = fp
else:
elif hasattr(fp, 'read'):
fdata = fp.read()
elif fp is None:
continue
else:
fdata = fp
rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
rf.make_multipart(content_type=ft)
@@ -174,10 +178,10 @@ class RequestHooksMixin(object):
if event not in self.hooks:
raise ValueError('Unsupported event specified, with event name "%s"' % (event))
if isinstance(hook, collections.Callable):
if isinstance(hook, Callable):
self.hooks[event].append(hook)
elif hasattr(hook, '__iter__'):
self.hooks[event].extend(h for h in hook if isinstance(h, collections.Callable))
self.hooks[event].extend(h for h in hook if isinstance(h, Callable))
def deregister_hook(self, event, hook):
"""Deregister a previously registered hook.
@@ -200,9 +204,13 @@ 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 to the request. If a dictionary is provided, form-encoding will take place.
:param data: the body to attach to the request. If a dictionary or
list of tuples ``[(key, value)]`` is provided, form-encoding will
take place.
:param json: json for the body to attach to the request (if files or data is not specified).
:param params: dictionary of URL parameters to append to the URL.
:param params: URL parameters to append to the URL. If a dictionary or
list of tuples ``[(key, value)]`` is provided, form-encoding will
take place.
: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.
@@ -210,13 +218,14 @@ class Request(RequestHooksMixin):
Usage::
>>> import requests
>>> req = requests.Request('GET', 'http://httpbin.org/get')
>>> req = requests.Request('GET', 'https://httpbin.org/get')
>>> req.prepare()
<PreparedRequest [GET]>
"""
def __init__(self, method=None, url=None, headers=None, files=None,
data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
def __init__(self,
method=None, url=None, headers=None, files=None, data=None,
params=None, auth=None, cookies=None, hooks=None, json=None):
# Default empty dicts for dict params.
data = [] if data is None else data
@@ -269,7 +278,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
Usage::
>>> import requests
>>> req = requests.Request('GET', 'http://httpbin.org/get')
>>> req = requests.Request('GET', 'https://httpbin.org/get')
>>> r = req.prepare()
<PreparedRequest [GET]>
@@ -295,8 +304,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
#: integer denoting starting position of a readable file-like body.
self._body_position = None
def prepare(self, method=None, url=None, headers=None, files=None,
data=None, params=None, auth=None, cookies=None, hooks=None, json=None):
def prepare(self,
method=None, url=None, headers=None, files=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)
@@ -348,7 +358,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
#: We're unable to blindly call unicode/str functions
#: as this will include the bytestring indicator (b'')
#: on python 3.x.
#: https://github.com/kennethreitz/requests/pull/2238
#: https://github.com/requests/requests/pull/2238
if isinstance(url, bytes):
url = url.decode('utf8')
else:
@@ -459,7 +469,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
is_stream = all([
hasattr(data, '__iter__'),
not isinstance(data, (basestring, list, tuple, collections.Mapping))
not isinstance(data, (basestring, list, tuple, Mapping))
])
try:
@@ -584,8 +594,6 @@ class Response(object):
]
def __init__(self):
super(Response, self).__init__()
self._content = False
self._content_consumed = False
self._next = None
@@ -632,16 +640,19 @@ class Response(object):
#: is a response.
self.request = None
def __enter__(self):
return self
def __exit__(self, *args):
self.close()
def __getstate__(self):
# Consume everything; accessing the content attribute makes
# sure the content has been fully read.
if not self._content_consumed:
self.content
return dict(
(attr, getattr(self, attr, None))
for attr in self.__attrs__
)
return {attr: getattr(self, attr, None) for attr in self.__attrs__}
def __setstate__(self, state):
for name, value in state.items():
@@ -680,11 +691,11 @@ class Response(object):
@property
def ok(self):
"""Returns True if :attr:`status_code` is less than 400.
"""Returns True if :attr:`status_code` is less than 400, False if not.
This attribute checks if the status code of the response is between
400 and 600 to see if there was a client error or a server error. If
the status code, is between 200 and 400, this will return True. This
the status code is between 200 and 400, this will return True. This
is **not** a check to see if the response code is ``200 OK``.
"""
try:
@@ -814,7 +825,7 @@ class Response(object):
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()
self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b''
self._content_consumed = True
# don't need to release the connection; that's been handled by urllib3

View File

@@ -3,13 +3,12 @@ import sys
# This code exists for backwards compatibility reasons.
# I don't like it either. Just look the other way. :)
import urllib3
sys.modules['requests.packages.urllib3'] = urllib3
for package in ('urllib3', 'idna', 'chardet'):
locals()[package] = __import__(package)
# This traversal is apparently necessary such that the identities are
# preserved (requests.packages.urllib3.* is urllib3.*)
for mod in list(sys.modules):
if mod == package or mod.startswith(package + '.'):
sys.modules['requests.packages.' + mod] = sys.modules[mod]
import idna
sys.modules['requests.packages.idna'] = idna
import chardet
sys.modules['requests.packages.chardet'] = chardet
# Kinda cool, though, right?
# Kinda cool, though, right?

149
requests/sessions.py Executable file → Normal file
View File

@@ -8,15 +8,12 @@ This module provides a Session object to manage and persist settings across
requests (cookies, auth, proxies).
"""
import os
import platform
import sys
import time
from collections import Mapping
from datetime import timedelta
from urllib3._collections import RecentlyUsedContainer
from .auth import _basic_auth_str
from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse
from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse, Mapping
from .cookies import (
cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
@@ -39,11 +36,9 @@ from .status_codes import codes
# formerly defined here, reexposed here for backward compatibility
from .models import REDIRECT_STATI
REDIRECT_CACHE_SIZE = 1000
# Preferred clock, based on which one is more accurate on a given system.
if platform.system() == 'Windows':
try: # Python 3.3+
if sys.platform == 'win32':
try: # Python 3.4+
preferred_clock = time.perf_counter
except AttributeError: # Earlier than Python 3.
preferred_clock = time.clock
@@ -101,6 +96,12 @@ class SessionRedirectMixin(object):
def get_redirect_target(self, resp):
"""Receives a Response. Returns a redirect URI or ``None``"""
# Due to the nature of how requests processes redirects this method will
# be called at least once upon the original response and at least twice
# on each subsequent redirect response (if any).
# If a custom mixin is used to handle this logic, it may be advantageous
# to cache the redirect location onto the response object as a private
# attribute.
if resp.is_redirect:
location = resp.headers['location']
# Currently the underlying http module on py3 decode headers
@@ -114,13 +115,30 @@ class SessionRedirectMixin(object):
return to_native_string(location, 'utf8')
return None
def should_strip_auth(self, old_url, new_url):
"""Decide whether Authorization header should be removed when redirecting"""
old_parsed = urlparse(old_url)
new_parsed = urlparse(new_url)
if old_parsed.hostname != new_parsed.hostname:
return True
# Special case: allow http -> https redirect when using the standard
# ports. This isn't specified by RFC 7235, but is kept to avoid
# breaking backwards compatibility with older versions of requests
# that allowed any redirects on the same host.
if (old_parsed.scheme == 'http' and old_parsed.port in (80, None)
and new_parsed.scheme == 'https' and new_parsed.port in (443, None)):
return False
# Standard case: root URI must match
return old_parsed.port != new_parsed.port or old_parsed.scheme != new_parsed.scheme
def resolve_redirects(self, resp, req, stream=False, timeout=None,
verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs):
"""Receives a Response. Returns a generator of Responses or Requests."""
hist = [] # keep track of history
hist = [] # keep track of history
url = self.get_redirect_target(resp)
previous_fragment = urlparse(req.url).fragment
while url:
prepared_request = req.copy()
@@ -145,8 +163,12 @@ class SessionRedirectMixin(object):
parsed_rurl = urlparse(resp.url)
url = '%s:%s' % (to_native_string(parsed_rurl.scheme), url)
# The scheme should be lower case...
# Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2)
parsed = urlparse(url)
if parsed.fragment == '' and previous_fragment:
parsed = parsed._replace(fragment=previous_fragment)
elif parsed.fragment:
previous_fragment = parsed.fragment
url = parsed.geturl()
# Facilitate relative 'location' headers, as allowed by RFC 7231.
@@ -158,15 +180,12 @@ class SessionRedirectMixin(object):
url = requote_uri(url)
prepared_request.url = to_native_string(url)
# 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
self.rebuild_method(prepared_request, resp)
# https://github.com/kennethreitz/requests/issues/1084
# https://github.com/requests/requests/issues/1084
if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect):
# https://github.com/kennethreitz/requests/issues/3490
# https://github.com/requests/requests/issues/3490
purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding')
for header in purged_headers:
prepared_request.headers.pop(header, None)
@@ -233,14 +252,10 @@ class SessionRedirectMixin(object):
headers = prepared_request.headers
url = prepared_request.url
if 'Authorization' in headers:
if 'Authorization' in headers and self.should_strip_auth(response.request.url, url):
# If we get redirected to a new host, we should strip out any
# authentication headers.
original_parsed = urlparse(response.request.url)
redirect_parsed = urlparse(url)
if (original_parsed.hostname != redirect_parsed.hostname):
del headers['Authorization']
del headers['Authorization']
# .netrc might have more auth for us on our new host.
new_auth = get_netrc_auth(url) if self.trust_env else None
@@ -296,7 +311,7 @@ class SessionRedirectMixin(object):
"""
method = prepared_request.method
# http://tools.ietf.org/html/rfc7231#section-6.4.4
# https://tools.ietf.org/html/rfc7231#section-6.4.4
if response.status_code == codes.see_other and method != 'HEAD':
method = 'GET'
@@ -322,13 +337,13 @@ class Session(SessionRedirectMixin):
>>> import requests
>>> s = requests.Session()
>>> s.get('http://httpbin.org/get')
>>> s.get('https://httpbin.org/get')
<Response [200]>
Or as a context manager::
>>> with requests.Session() as s:
>>> s.get('http://httpbin.org/get')
>>> s.get('https://httpbin.org/get')
<Response [200]>
"""
@@ -393,9 +408,6 @@ class Session(SessionRedirectMixin):
self.mount('https://', HTTPAdapter())
self.mount('http://', HTTPAdapter())
# Only store 1000 redirects to prevent using infinite memory
self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE)
def __enter__(self):
return self
@@ -443,20 +455,9 @@ class Session(SessionRedirectMixin):
return p
def request(self, method, url,
params=None,
data=None,
headers=None,
cookies=None,
files=None,
auth=None,
timeout=None,
allow_redirects=True,
proxies=None,
hooks=None,
stream=None,
verify=None,
cert=None,
json=None):
params=None, data=None, headers=None, cookies=None, files=None,
auth=None, timeout=None, allow_redirects=True, proxies=None,
hooks=None, stream=None, verify=None, cert=None, json=None):
"""Constructs a :class:`Request <Request>`, prepares it and sends it.
Returns :class:`Response <Response>` object.
@@ -464,8 +465,8 @@ class Session(SessionRedirectMixin):
: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 data: (optional) Dictionary, list of tuples, 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 headers: (optional) Dictionary of HTTP Headers to send with the
@@ -495,16 +496,16 @@ class Session(SessionRedirectMixin):
"""
# Create the Request.
req = Request(
method = method.upper(),
url = url,
headers = headers,
files = files,
data = data or {},
json = json,
params = params or {},
auth = auth,
cookies = cookies,
hooks = hooks,
method=method.upper(),
url=url,
headers=headers,
files=files,
data=data or {},
json=json,
params=params or {},
auth=auth,
cookies=cookies,
hooks=hooks,
)
prep = self.prepare_request(req)
@@ -561,7 +562,8 @@ class Session(SessionRedirectMixin):
r"""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 data: (optional) Dictionary, list of tuples, 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.
:rtype: requests.Response
@@ -573,7 +575,8 @@ class Session(SessionRedirectMixin):
r"""Sends a PUT 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 data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
@@ -584,12 +587,13 @@ class Session(SessionRedirectMixin):
r"""Sends a PATCH 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 data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:rtype: requests.Response
"""
return self.request('PATCH', url, data=data, **kwargs)
return self.request('PATCH', url, data=data, **kwargs)
def delete(self, url, **kwargs):
r"""Sends a DELETE request. Returns :class:`Response` object.
@@ -623,16 +627,6 @@ class Session(SessionRedirectMixin):
stream = kwargs.get('stream')
hooks = request.hooks
# Resolve URL in redirect cache, if available.
if allow_redirects:
checked_urls = set()
while request.url in self.redirect_cache:
checked_urls.add(request.url)
new_url = self.redirect_cache.get(request.url)
if new_url in checked_urls:
break
request.url = new_url
# Get the appropriate adapter to use
adapter = self.get_adapter(url=request.url)
@@ -721,7 +715,7 @@ class Session(SessionRedirectMixin):
"""
for (prefix, adapter) in self.adapters.items():
if url.lower().startswith(prefix):
if url.lower().startswith(prefix.lower()):
return adapter
# Nothing matches :-/
@@ -735,7 +729,7 @@ class Session(SessionRedirectMixin):
def mount(self, prefix, adapter):
"""Registers a connection adapter to a prefix.
Adapters are sorted in descending order by key length.
Adapters are sorted in descending order by prefix length.
"""
self.adapters[prefix] = adapter
keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
@@ -744,25 +738,24 @@ class Session(SessionRedirectMixin):
self.adapters[key] = self.adapters.pop(key)
def __getstate__(self):
state = dict((attr, getattr(self, attr, None)) for attr in self.__attrs__)
state['redirect_cache'] = dict(self.redirect_cache)
state = {attr: getattr(self, attr, None) for attr in self.__attrs__}
return state
def __setstate__(self, state):
redirect_cache = state.pop('redirect_cache', {})
for attr, value in state.items():
setattr(self, attr, value)
self.redirect_cache = RecentlyUsedContainer(REDIRECT_CACHE_SIZE)
for redirect, to in redirect_cache.items():
self.redirect_cache[redirect] = to
def session():
"""
Returns a :class:`Session` for context-management.
.. deprecated:: 1.0.0
This method has been deprecated since version 1.0.0 and is only kept for
backwards compatibility. New code should use :class:`~requests.sessions.Session`
to create a session. This may be removed at a future date.
:rtype: Session
"""
return Session()

View File

@@ -1,5 +1,22 @@
# -*- coding: utf-8 -*-
r"""
The ``codes`` object defines a mapping from common names for HTTP statuses
to their numerical codes, accessible either as attributes or as dictionary
items.
>>> requests.codes['temporary_redirect']
307
>>> requests.codes.teapot
418
>>> requests.codes['\o/']
200
Some codes have multiple names, and both upper- and lower-case versions of
the names are allowed. For example, ``codes.ok``, ``codes.OK``, and
``codes.okay`` all correspond to the HTTP status code 200.
"""
from .structures import LookupDict
_codes = {
@@ -84,8 +101,20 @@ _codes = {
codes = LookupDict(name='status_codes')
for code, titles in _codes.items():
for title in titles:
setattr(codes, title, code)
if not title.startswith(('\\', '/')):
setattr(codes, title.upper(), code)
def _init():
for code, titles in _codes.items():
for title in titles:
setattr(codes, title, code)
if not title.startswith(('\\', '/')):
setattr(codes, title.upper(), code)
def doc(code):
names = ', '.join('``%s``' % n for n in _codes[code])
return '* %d: %s' % (code, names)
global __doc__
__doc__ = (__doc__ + '\n' +
'\n'.join(doc(code) for code in sorted(_codes))
if __doc__ is not None else None)
_init()

View File

@@ -7,16 +7,14 @@ requests.structures
Data structures that power Requests.
"""
import collections
from .compat import OrderedDict
from .compat import OrderedDict, Mapping, MutableMapping
class CaseInsensitiveDict(collections.MutableMapping):
class CaseInsensitiveDict(MutableMapping):
"""A case-insensitive ``dict``-like object.
Implements all methods and operations of
``collections.MutableMapping`` as well as dict's ``copy``. Also
``MutableMapping`` as well as dict's ``copy``. Also
provides ``lower_items``.
All keys are expected to be strings. The structure remembers the
@@ -71,7 +69,7 @@ class CaseInsensitiveDict(collections.MutableMapping):
)
def __eq__(self, other):
if isinstance(other, collections.Mapping):
if isinstance(other, Mapping):
other = CaseInsensitiveDict(other)
else:
return NotImplemented

View File

@@ -8,17 +8,17 @@ This module provides utility functions that are used within Requests
that are also useful for external consumption.
"""
import cgi
import codecs
import collections
import contextlib
import io
import os
import platform
import re
import socket
import struct
import sys
import tempfile
import warnings
import zipfile
from .__version__ import __version__
from . import certs
@@ -28,7 +28,7 @@ from .compat import parse_http_list as _parse_list_header
from .compat import (
quote, urlparse, bytes, str, OrderedDict, unquote, getproxies,
proxy_bypass, urlunparse, basestring, integer_types, is_py3,
proxy_bypass_environment, getproxies_environment)
proxy_bypass_environment, getproxies_environment, Mapping)
from .cookies import cookiejar_from_dict
from .structures import CaseInsensitiveDict
from .exceptions import (
@@ -39,19 +39,25 @@ NETRC_FILES = ('.netrc', '_netrc')
DEFAULT_CA_BUNDLE_PATH = certs.where()
if platform.system() == 'Windows':
if sys.platform == 'win32':
# provide a proxy_bypass version on Windows without DNS lookups
def proxy_bypass_registry(host):
if is_py3:
import winreg
else:
import _winreg as winreg
try:
if is_py3:
import winreg
else:
import _winreg as winreg
except ImportError:
return False
try:
internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER,
r'Software\Microsoft\Windows\CurrentVersion\Internet Settings')
proxyEnable = winreg.QueryValueEx(internetSettings,
'ProxyEnable')[0]
# ProxyEnable could be REG_SZ or REG_DWORD, normalizing it
proxyEnable = int(winreg.QueryValueEx(internetSettings,
'ProxyEnable')[0])
# ProxyOverride is almost always a string
proxyOverride = winreg.QueryValueEx(internetSettings,
'ProxyOverride')[0]
except OSError:
@@ -167,11 +173,11 @@ def get_netrc_auth(url, raise_errors=False):
for f in NETRC_FILES:
try:
loc = os.path.expanduser('~/{0}'.format(f))
loc = os.path.expanduser('~/{}'.format(f))
except KeyError:
# os.path.expanduser can fail when $HOME is undefined and
# getpwuid fails. See http://bugs.python.org/issue20164 &
# https://github.com/kennethreitz/requests/issues/1846
# getpwuid fails. See https://bugs.python.org/issue20164 &
# https://github.com/requests/requests/issues/1846
return
if os.path.exists(loc):
@@ -216,6 +222,38 @@ def guess_filename(obj):
return os.path.basename(name)
def extract_zipped_paths(path):
"""Replace nonexistent paths that look like they refer to a member of a zip
archive with the location of an extracted copy of the target, or else
just return the provided path unchanged.
"""
if os.path.exists(path):
# this is already a valid path, no need to do anything further
return path
# find the first valid part of the provided path and treat that as a zip archive
# assume the rest of the path is the name of a member in the archive
archive, member = os.path.split(path)
while archive and not os.path.exists(archive):
archive, prefix = os.path.split(archive)
member = '/'.join([prefix, member])
if not zipfile.is_zipfile(archive):
return path
zip_file = zipfile.ZipFile(archive)
if member not in zip_file.namelist():
return path
# we have a valid zip archive and a valid member of that archive
tmp = tempfile.gettempdir()
extracted_path = os.path.join(tmp, *member.split('/'))
if not os.path.exists(extracted_path):
extracted_path = zip_file.extract(member, path=tmp)
return extracted_path
def from_key_val_list(value):
"""Take an object and test to see if it can be represented as a
dictionary. Unless it can not be represented as such, return an
@@ -262,7 +300,7 @@ def to_key_val_list(value):
if isinstance(value, (str, bytes, bool, int)):
raise ValueError('cannot encode objects that are not 2-tuples')
if isinstance(value, collections.Mapping):
if isinstance(value, Mapping):
value = value.items()
return list(value)
@@ -407,6 +445,31 @@ def get_encodings_from_content(content):
xml_re.findall(content))
def _parse_content_type_header(header):
"""Returns content type and parameters from given header
:param header: string
:return: tuple containing content type and dictionary of
parameters
"""
tokens = header.split(';')
content_type, params = tokens[0].strip(), tokens[1:]
params_dict = {}
items_to_strip = "\"' "
for param in params:
param = param.strip()
if param:
key, value = param, True
index_of_equals = param.find("=")
if index_of_equals != -1:
key = param[:index_of_equals].strip(items_to_strip)
value = param[index_of_equals + 1:].strip(items_to_strip)
params_dict[key.lower()] = value
return content_type, params_dict
def get_encoding_from_headers(headers):
"""Returns encodings from given HTTP Header Dict.
@@ -419,7 +482,7 @@ def get_encoding_from_headers(headers):
if not content_type:
return None
content_type, params = cgi.parse_header(content_type)
content_type, params = _parse_content_type_header(content_type)
if 'charset' in params:
return params['charset'].strip("'\"")
@@ -494,8 +557,7 @@ def get_unicode_from_response(r):
# The unreserved URI characters (RFC 3986)
UNRESERVED_SET = frozenset(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789-._~")
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~")
def unquote_unreserved(uri):
@@ -613,18 +675,18 @@ def set_environ(env_name, value):
the environment variable 'env_name'.
If 'value' is None, do nothing"""
if value is not None:
value_changed = value is not None
if value_changed:
old_value = os.environ.get(env_name)
os.environ[env_name] = value
try:
yield
finally:
if value is None:
return
if old_value is None:
del os.environ[env_name]
else:
os.environ[env_name] = old_value
if value_changed:
if old_value is None:
del os.environ[env_name]
else:
os.environ[env_name] = old_value
def should_bypass_proxies(url, no_proxy):
@@ -633,6 +695,8 @@ def should_bypass_proxies(url, no_proxy):
:rtype: bool
"""
# Prioritize lowercase environment variables over uppercase
# to keep a consistent behaviour with other http projects (curl, wget).
get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper())
# First check whether no_proxy is defined. If it is, check that the URL
@@ -640,41 +704,43 @@ def should_bypass_proxies(url, no_proxy):
no_proxy_arg = no_proxy
if no_proxy is None:
no_proxy = get_proxy('no_proxy')
netloc = urlparse(url).netloc
parsed = urlparse(url)
if parsed.hostname is None:
# URLs don't always have hostnames, e.g. file:/// urls.
return True
if no_proxy:
# We need to check whether we match here. We need to see if we match
# the end of the netloc, both with and without the port.
# the end of the hostname, both with and without the port.
no_proxy = (
host for host in no_proxy.replace(' ', '').split(',') if host
)
ip = netloc.split(':')[0]
if is_ipv4_address(ip):
if is_ipv4_address(parsed.hostname):
for proxy_ip in no_proxy:
if is_valid_cidr(proxy_ip):
if address_in_network(ip, proxy_ip):
if address_in_network(parsed.hostname, proxy_ip):
return True
elif ip == proxy_ip:
elif parsed.hostname == proxy_ip:
# If no_proxy ip was defined in plain IP notation instead of cidr notation &
# matches the IP of the index
return True
else:
host_with_port = parsed.hostname
if parsed.port:
host_with_port += ':{}'.format(parsed.port)
for host in no_proxy:
if netloc.endswith(host) or netloc.split(':')[0].endswith(host):
if parsed.hostname.endswith(host) or host_with_port.endswith(host):
# The URL does match something in no_proxy, so we don't want
# to apply the proxies on this URL.
return True
# If the system proxy settings indicate that this URL should be bypassed,
# don't proxy.
# The proxy_bypass function is incredibly buggy on OS X in early versions
# of Python 2.6, so allow this call to fail. Only catch the specific
# exceptions we've seen, though: this call failing in other ways can reveal
# legitimate problems.
with set_environ('no_proxy', no_proxy_arg):
# parsed.hostname can be `None` in cases such as a file URI.
try:
bypass = proxy_bypass(netloc)
bypass = proxy_bypass(parsed.hostname)
except (TypeError, socket.gaierror):
bypass = False
@@ -744,7 +810,7 @@ def default_headers():
def parse_header_links(value):
"""Return a dict of parsed link headers proxies.
"""Return a list of parsed link headers proxies.
i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg"
@@ -755,6 +821,10 @@ def parse_header_links(value):
replace_chars = ' \'"'
value = value.strip(replace_chars)
if not value:
return links
for val in re.split(', *<', value):
try:
url, params = val.split(';', 1)
@@ -851,6 +921,7 @@ def get_auth_from_url(url):
_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$')
_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$')
def check_header_validity(header):
"""Verifies that header value is a string which doesn't contain
leading whitespace or return characters. This prevents unintended
@@ -868,8 +939,8 @@ def check_header_validity(header):
if not pat.match(value):
raise InvalidHeader("Invalid return character or leading space in header: %s" % name)
except TypeError:
raise InvalidHeader("Header value %s must be of type str or bytes, "
"not %s" % (value, type(value)))
raise InvalidHeader("Value for header {%s: %s} must be of type str or "
"bytes, not %s" % (name, value, type(value)))
def urldefragauth(url):
@@ -888,6 +959,7 @@ def urldefragauth(url):
return urlunparse((scheme, netloc, path, params, query, ''))
def rewind_body(prepared_request):
"""Move file pointer back to its recorded starting position
so it can be read again on redirect.

View File

@@ -1 +0,0 @@
-e .

View File

@@ -1,2 +1,5 @@
[bdist_wheel]
universal = 1
[metadata]
license_file = LICENSE

View File

@@ -1,5 +1,5 @@
#!/usr/bin/env python
# Learn more: https://github.com/kennethreitz/setup.py
import os
import re
import sys
@@ -16,7 +16,11 @@ class PyTest(TestCommand):
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = []
try:
from multiprocessing import cpu_count
self.pytest_args = ['-n', str(cpu_count()), '--boxed']
except (ImportError, NotImplementedError):
self.pytest_args = ['-n', '1', '--boxed']
def finalize_options(self):
TestCommand.finalize_options(self)
@@ -39,27 +43,35 @@ packages = ['requests']
requires = [
'chardet>=3.0.2,<3.1.0',
'idna>=2.5,<2.6',
'urllib3>=1.21.1,<1.22',
'idna>=2.5,<2.8',
'urllib3>=1.21.1,<1.25',
'certifi>=2017.4.17'
]
test_requirements = ['pytest>=2.8.0', 'pytest-httpbin==0.0.7', 'pytest-cov', 'pytest-mock']
test_requirements = [
'pytest-httpbin==0.0.7',
'pytest-cov',
'pytest-mock',
'pytest-xdist',
'PySocks>=1.5.6, !=1.5.7',
'pytest>=2.8.0'
]
about = {}
with open(os.path.join(here, 'requests', '__version__.py'), 'r', 'utf-8') as f:
exec(f.read(), about)
with open('README.rst', 'r', 'utf-8') as f:
with open('README.md', 'r', 'utf-8') as f:
readme = f.read()
with open('HISTORY.rst', 'r', 'utf-8') as f:
with open('HISTORY.md', 'r', 'utf-8') as f:
history = f.read()
setup(
name=about['__title__'],
version=about['__version__'],
description=about['__description__'],
long_description=readme + '\n\n' + history,
long_description=readme,
long_description_content_type='text/markdown',
author=about['__author__'],
author_email=about['__author_email__'],
url=about['__url__'],
@@ -67,31 +79,31 @@ setup(
package_data={'': ['LICENSE', 'NOTICE'], 'requests': ['*.pem']},
package_dir={'requests': 'requests'},
include_package_data=True,
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
install_requires=requires,
license=about['__license__'],
zip_safe=False,
classifiers=(
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'Natural Language :: English',
'License :: OSI Approved :: Apache Software License',
'Programming Language :: Python',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: Implementation :: CPython',
'Programming Language :: Python :: Implementation :: PyPy'
),
],
cmdclass={'test': PyTest},
tests_require=test_requirements,
extras_require={
'security': ['pyOpenSSL>=0.14', 'cryptography>=1.3.4', 'idna>=2.0.0'],
'security': ['pyOpenSSL >= 0.14', 'cryptography>=1.3.4', 'idna>=2.0.0'],
'socks': ['PySocks>=1.5.6, !=1.5.7'],
'socks:sys_platform == "win32" and (python_version == "2.7" or python_version == "2.6")': ['win_inet_pton'],
'socks:sys_platform == "win32" and python_version == "2.7"': ['win_inet_pton'],
},
)

31
tests/test_help.py Normal file
View File

@@ -0,0 +1,31 @@
# -*- encoding: utf-8
import sys
import pytest
from requests.help import info
def test_system_ssl():
"""Verify we're actually setting system_ssl when it should be available."""
assert info()['system_ssl']['version'] != ''
class VersionedPackage(object):
def __init__(self, version):
self.__version__ = version
def test_idna_without_version_attribute(mocker):
"""Older versions of IDNA don't provide a __version__ attribute, verify
that if we have such a package, we don't blow up.
"""
mocker.patch('requests.help.idna', new=None)
assert info()['idna'] == {'version': ''}
def test_idna_with_version_attribute(mocker):
"""Verify we're actually setting idna version when it should be available."""
mocker.patch('requests.help.idna', new=VersionedPackage('2.6'))
assert info()['idna'] == {'version': '2.6'}

96
tests/test_lowlevel.py Executable file → Normal file
View File

@@ -16,7 +16,7 @@ def test_chunked_upload():
data = iter([b'a', b'b', b'c'])
with server as (host, port):
url = 'http://{0}:{1}/'.format(host, port)
url = 'http://{}:{}/'.format(host, port)
r = requests.post(url, data=data, stream=True)
close_server.set() # release server block
@@ -28,7 +28,7 @@ def test_digestauth_401_count_reset_on_redirect():
"""Ensure we correctly reset num_401_calls after a successful digest auth,
followed by a 302 redirect to another digest auth prompt.
See https://github.com/kennethreitz/requests/issues/1979.
See https://github.com/requests/requests/issues/1979.
"""
text_401 = (b'HTTP/1.1 401 UNAUTHORIZED\r\n'
b'Content-Length: 0\r\n'
@@ -77,7 +77,7 @@ def test_digestauth_401_count_reset_on_redirect():
server = Server(digest_response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{0}:{1}/'.format(host, port)
url = 'http://{}:{}/'.format(host, port)
r = requests.get(url, auth=auth)
# Verify server succeeded in authenticating.
assert r.status_code == 200
@@ -127,7 +127,7 @@ def test_digestauth_401_only_sent_once():
server = Server(digest_failed_response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{0}:{1}/'.format(host, port)
url = 'http://{}:{}/'.format(host, port)
r = requests.get(url, auth=auth)
# Verify server didn't authenticate us.
assert r.status_code == 401
@@ -138,7 +138,7 @@ def test_digestauth_401_only_sent_once():
def test_digestauth_only_on_4xx():
"""Ensure we only send digestauth on 4xx challenges.
See https://github.com/kennethreitz/requests/issues/3772.
See https://github.com/requests/requests/issues/3772.
"""
text_200_chal = (b'HTTP/1.1 200 OK\r\n'
b'Content-Length: 0\r\n'
@@ -164,7 +164,7 @@ def test_digestauth_only_on_4xx():
server = Server(digest_response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{0}:{1}/'.format(host, port)
url = 'http://{}:{}/'.format(host, port)
r = requests.get(url, auth=auth)
# Verify server didn't receive auth from us.
assert r.status_code == 200
@@ -181,17 +181,17 @@ _schemes_by_var_prefix = [
_proxy_combos = []
for prefix, schemes in _schemes_by_var_prefix:
for scheme in schemes:
_proxy_combos.append(("{0}_proxy".format(prefix), scheme))
_proxy_combos.append(("{}_proxy".format(prefix), scheme))
_proxy_combos += [(var.upper(), scheme) for var, scheme in _proxy_combos]
@pytest.mark.parametrize("var,scheme", _proxy_combos)
def test_use_proxy_from_environment(httpbin, var, scheme):
url = "{0}://httpbin.org".format(scheme)
url = "{}://httpbin.org".format(scheme)
fake_proxy = Server() # do nothing with the requests; just close the socket
with fake_proxy as (host, port):
proxy_url = "socks5://{0}:{1}".format(host, port)
proxy_url = "socks5://{}:{}".format(host, port)
kwargs = {var: proxy_url}
with override_environ(**kwargs):
# fake proxy's lack of response will cause a ConnectionError
@@ -212,7 +212,7 @@ def test_redirect_rfc1808_to_non_ascii_location():
def redirect_resp_handler(sock):
consume_socket_content(sock, timeout=0.5)
location = u'//{0}:{1}/{2}'.format(host, port, path)
location = u'//{}:{}/{}'.format(host, port, path)
sock.send(
b'HTTP/1.1 301 Moved Permanently\r\n'
b'Content-Length: 0\r\n'
@@ -226,12 +226,84 @@ def test_redirect_rfc1808_to_non_ascii_location():
server = Server(redirect_resp_handler, wait_to_close_event=close_server)
with server as (host, port):
url = u'http://{0}:{1}'.format(host, port)
url = u'http://{}:{}'.format(host, port)
r = requests.get(url=url, allow_redirects=True)
assert r.status_code == 200
assert len(r.history) == 1
assert r.history[0].status_code == 301
assert redirect_request[0].startswith(b'GET /' + expected_path + b' HTTP/1.1')
assert r.url == u'{0}/{1}'.format(url, expected_path.decode('ascii'))
assert r.url == u'{}/{}'.format(url, expected_path.decode('ascii'))
close_server.set()
def test_fragment_not_sent_with_request():
"""Verify that the fragment portion of a URI isn't sent to the server."""
def response_handler(sock):
req = consume_socket_content(sock, timeout=0.5)
sock.send(
b'HTTP/1.1 200 OK\r\n'
b'Content-Length: '+bytes(len(req))+b'\r\n'
b'\r\n'+req
)
close_server = threading.Event()
server = Server(response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{}:{}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
r = requests.get(url)
raw_request = r.content
assert r.status_code == 200
headers, body = raw_request.split(b'\r\n\r\n', 1)
status_line, headers = headers.split(b'\r\n', 1)
assert status_line == b'GET /path/to/thing/ HTTP/1.1'
for frag in (b'view', b'edit', b'token', b'hunter2'):
assert frag not in headers
assert frag not in body
close_server.set()
def test_fragment_update_on_redirect():
"""Verify we only append previous fragment if one doesn't exist on new
location. If a new fragment is encountered in a Location header, it should
be added to all subsequent requests.
"""
def response_handler(sock):
consume_socket_content(sock, timeout=0.5)
sock.send(
b'HTTP/1.1 302 FOUND\r\n'
b'Content-Length: 0\r\n'
b'Location: /get#relevant-section\r\n\r\n'
)
consume_socket_content(sock, timeout=0.5)
sock.send(
b'HTTP/1.1 302 FOUND\r\n'
b'Content-Length: 0\r\n'
b'Location: /final-url/\r\n\r\n'
)
consume_socket_content(sock, timeout=0.5)
sock.send(
b'HTTP/1.1 200 OK\r\n\r\n'
)
close_server = threading.Event()
server = Server(response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{}:{}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
r = requests.get(url)
raw_request = r.content
assert r.status_code == 200
assert len(r.history) == 2
assert r.history[0].request.url == url
# Verify we haven't overwritten the location with our previous fragment.
assert r.history[1].request.url == 'http://{}:{}/get#relevant-section'.format(host, port)
# Verify previous fragment is used and not the original.
assert r.url == 'http://{}:{}/final-url/#relevant-section'.format(host, port)
close_server.set()

13
tests/test_packages.py Normal file
View File

@@ -0,0 +1,13 @@
import requests
def test_can_access_urllib3_attribute():
requests.packages.urllib3
def test_can_access_idna_attribute():
requests.packages.idna
def test_can_access_chardet_attribute():
requests.packages.chardet

273
tests/test_requests.py Executable file → Normal file
View File

@@ -1,4 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""Tests for Requests."""
@@ -24,12 +23,13 @@ from requests.cookies import (
from requests.exceptions import (
ConnectionError, ConnectTimeout, InvalidSchema, InvalidURL,
MissingSchema, ReadTimeout, Timeout, RetryError, TooManyRedirects,
ProxyError, InvalidHeader, UnrewindableBodyError)
ProxyError, InvalidHeader, UnrewindableBodyError, SSLError, InvalidProxyURL)
from requests.models import PreparedRequest
from requests.structures import CaseInsensitiveDict
from requests.sessions import SessionRedirectMixin
from requests.models import urlencode
from requests.hooks import default_hooks
from requests.compat import MutableMapping
from .compat import StringIO, u
from .utils import override_environ
@@ -55,6 +55,8 @@ except AttributeError:
class TestRequests:
digest_auth_algo = ('MD5', 'SHA-256', 'SHA-512')
def test_entry_points(self):
requests.session
@@ -156,7 +158,7 @@ class TestRequests:
url = scheme + parts.netloc + parts.path
r = requests.Request('GET', url)
r = s.send(r.prepare())
assert r.status_code == 200, 'failed for scheme {0}'.format(scheme)
assert r.status_code == 200, 'failed for scheme {}'.format(scheme)
def test_HTTP_200_OK_GET_ALTERNATIVE(self, httpbin):
r = requests.Request('GET', httpbin('get'))
@@ -295,6 +297,14 @@ class TestRequests:
for header in purged_headers:
assert header not in next_resp.request.headers
def test_fragment_maintained_on_redirect(self, httpbin):
fragment = "#view=edit&token=hunter2"
r = requests.get(httpbin('redirect-to?url=get')+fragment)
assert len(r.history) > 0
assert r.history[0].request.url == httpbin('redirect-to?url=get')+fragment
assert r.url == httpbin('get')+fragment
def test_HTTP_200_OK_GET_WITH_PARAMS(self, httpbin):
heads = {'User-agent': 'Mozilla/5.0'}
@@ -455,7 +465,7 @@ class TestRequests:
@pytest.mark.parametrize('key', ('User-agent', 'user-agent'))
def test_user_agent_transfers(self, httpbin, key):
heads = {key: 'Mozilla/5.0 (github.com/kennethreitz/requests)'}
heads = {key: 'Mozilla/5.0 (github.com/requests/requests)'}
r = requests.get(httpbin('user-agent'), headers=heads)
assert heads[key] in r.text
@@ -527,6 +537,19 @@ class TestRequests:
with pytest.raises(ProxyError):
requests.get('http://localhost:1', proxies={'http': 'non-resolvable-address'})
def test_proxy_error_on_bad_url(self, httpbin, httpbin_secure):
with pytest.raises(InvalidProxyURL):
requests.get(httpbin_secure(), proxies={'https': 'http:/badproxyurl:3128'})
with pytest.raises(InvalidProxyURL):
requests.get(httpbin(), proxies={'http': 'http://:8080'})
with pytest.raises(InvalidProxyURL):
requests.get(httpbin_secure(), proxies={'https': 'https://'})
with pytest.raises(InvalidProxyURL):
requests.get(httpbin(), proxies={'http': 'http:///example.com:8080'})
def test_basicauth_with_netrc(self, httpbin):
auth = ('user', 'pass')
wrong_auth = ('wronguser', 'wrongpass')
@@ -562,70 +585,79 @@ class TestRequests:
def test_DIGEST_HTTP_200_OK_GET(self, httpbin):
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass')
for authtype in self.digest_auth_algo:
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype, 'never')
r = requests.get(url, auth=auth)
assert r.status_code == 200
r = requests.get(url, auth=auth)
assert r.status_code == 200
r = requests.get(url)
assert r.status_code == 401
r = requests.get(url)
assert r.status_code == 401
print(r.headers['WWW-Authenticate'])
s = requests.session()
s.auth = HTTPDigestAuth('user', 'pass')
r = s.get(url)
assert r.status_code == 200
s = requests.session()
s.auth = HTTPDigestAuth('user', 'pass')
r = s.get(url)
assert r.status_code == 200
def test_DIGEST_AUTH_RETURNS_COOKIE(self, httpbin):
url = httpbin('digest-auth', 'auth', 'user', 'pass')
auth = HTTPDigestAuth('user', 'pass')
r = requests.get(url)
assert r.cookies['fake'] == 'fake_value'
r = requests.get(url, auth=auth)
assert r.status_code == 200
for authtype in self.digest_auth_algo:
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype)
auth = HTTPDigestAuth('user', 'pass')
r = requests.get(url)
assert r.cookies['fake'] == 'fake_value'
r = requests.get(url, auth=auth)
assert r.status_code == 200
def test_DIGEST_AUTH_SETS_SESSION_COOKIES(self, httpbin):
url = httpbin('digest-auth', 'auth', 'user', 'pass')
auth = HTTPDigestAuth('user', 'pass')
s = requests.Session()
s.get(url, auth=auth)
assert s.cookies['fake'] == 'fake_value'
for authtype in self.digest_auth_algo:
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype)
auth = HTTPDigestAuth('user', 'pass')
s = requests.Session()
s.get(url, auth=auth)
assert s.cookies['fake'] == 'fake_value'
def test_DIGEST_STREAM(self, httpbin):
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass')
for authtype in self.digest_auth_algo:
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype)
r = requests.get(url, auth=auth, stream=True)
assert r.raw.read() != b''
r = requests.get(url, auth=auth, stream=True)
assert r.raw.read() != b''
r = requests.get(url, auth=auth, stream=False)
assert r.raw.read() == b''
r = requests.get(url, auth=auth, stream=False)
assert r.raw.read() == b''
def test_DIGESTAUTH_WRONG_HTTP_401_GET(self, httpbin):
auth = HTTPDigestAuth('user', 'wrongpass')
url = httpbin('digest-auth', 'auth', 'user', 'pass')
for authtype in self.digest_auth_algo:
auth = HTTPDigestAuth('user', 'wrongpass')
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype)
r = requests.get(url, auth=auth)
assert r.status_code == 401
r = requests.get(url, auth=auth)
assert r.status_code == 401
r = requests.get(url)
assert r.status_code == 401
r = requests.get(url)
assert r.status_code == 401
s = requests.session()
s.auth = auth
r = s.get(url)
assert r.status_code == 401
s = requests.session()
s.auth = auth
r = s.get(url)
assert r.status_code == 401
def test_DIGESTAUTH_QUOTES_QOP_VALUE(self, httpbin):
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass')
for authtype in self.digest_auth_algo:
auth = HTTPDigestAuth('user', 'pass')
url = httpbin('digest-auth', 'auth', 'user', 'pass', authtype)
r = requests.get(url, auth=auth)
assert '"auth"' in r.request.headers['Authorization']
r = requests.get(url, auth=auth)
assert '"auth"' in r.request.headers['Authorization']
def test_POSTBIN_GET_POST_FILES(self, httpbin):
@@ -645,6 +677,14 @@ class TestRequests:
with pytest.raises(ValueError):
requests.post(url, files=['bad file data'])
def test_invalid_files_input(self, httpbin):
url = httpbin('post')
post = requests.post(url,
files={"random-file-1": None, "random-file-2": 1})
assert b'name="random-file-1"' not in post.request.body
assert b'name="random-file-2"' in post.request.body
def test_POSTBIN_SEEKED_OBJECT_WITH_NO_ITER(self, httpbin):
class TestStream(object):
@@ -706,7 +746,7 @@ class TestRequests:
requests.post(url, files=['bad file data'])
def test_post_with_custom_mapping(self, httpbin):
class CustomMapping(collections.MutableMapping):
class CustomMapping(MutableMapping):
def __init__(self, *args, **kwargs):
self.data = dict(*args, **kwargs)
@@ -776,17 +816,17 @@ class TestRequests:
INVALID_PATH = '/garbage'
with pytest.raises(IOError) as e:
requests.get(httpbin_secure(), verify=INVALID_PATH)
assert str(e.value) == 'Could not find a suitable TLS CA certificate bundle, invalid path: {0}'.format(INVALID_PATH)
assert str(e.value) == 'Could not find a suitable TLS CA certificate bundle, invalid path: {}'.format(INVALID_PATH)
def test_invalid_ssl_certificate_files(self, httpbin_secure):
INVALID_PATH = '/garbage'
with pytest.raises(IOError) as e:
requests.get(httpbin_secure(), cert=INVALID_PATH)
assert str(e.value) == 'Could not find the TLS certificate file, invalid path: {0}'.format(INVALID_PATH)
assert str(e.value) == 'Could not find the TLS certificate file, invalid path: {}'.format(INVALID_PATH)
with pytest.raises(IOError) as e:
requests.get(httpbin_secure(), cert=('.', INVALID_PATH))
assert str(e.value) == 'Could not find the TLS key file, invalid path: {0}'.format(INVALID_PATH)
assert str(e.value) == 'Could not find the TLS key file, invalid path: {}'.format(INVALID_PATH)
def test_http_with_certificate(self, httpbin):
r = requests.get(httpbin(), cert='.')
@@ -813,12 +853,27 @@ class TestRequests:
item.category.__name__ for item in warning_records)
assert warnings_category == warnings_expected
def test_certificate_failure(self, httpbin_secure):
"""
When underlying SSL problems occur, an SSLError is raised.
"""
with pytest.raises(SSLError):
# Our local httpbin does not have a trusted CA, so this call will
# fail if we use our default trust bundle.
requests.get(httpbin_secure('status', '200'))
def test_urlencoded_get_query_multivalued_param(self, httpbin):
r = requests.get(httpbin('get'), params=dict(test=['foo', 'baz']))
r = requests.get(httpbin('get'), params={'test': ['foo', 'baz']})
assert r.status_code == 200
assert r.url == httpbin('get?test=foo&test=baz')
def test_form_encoded_post_query_multivalued_element(self, httpbin):
r = requests.Request(method='POST', url=httpbin('post'),
data=dict(test=['foo', 'baz']))
prep = r.prepare()
assert prep.body == 'test=foo&test=baz'
def test_different_encodings_dont_break_post(self, httpbin):
r = requests.post(httpbin('post'),
data={'stuff': json.dumps({'a': 123})},
@@ -1123,6 +1178,14 @@ class TestRequests:
with pytest.raises(requests.cookies.CookieConflictError):
jar.get(key)
def test_cookie_policy_copy(self):
class MyCookiePolicy(cookielib.DefaultCookiePolicy):
pass
jar = requests.cookies.RequestsCookieJar()
jar.set_policy(MyCookiePolicy())
assert isinstance(jar.copy().get_policy(), MyCookiePolicy)
def test_time_elapsed_blank(self, httpbin):
r = requests.get(httpbin('get'))
td = r.elapsed
@@ -1343,6 +1406,44 @@ class TestRequests:
assert 'http://' in s2.adapters
assert 'https://' in s2.adapters
def test_session_get_adapter_prefix_matching(self):
prefix = 'https://example.com'
more_specific_prefix = prefix + '/some/path'
url_matching_only_prefix = prefix + '/another/path'
url_matching_more_specific_prefix = more_specific_prefix + '/longer/path'
url_not_matching_prefix = 'https://another.example.com/'
s = requests.Session()
prefix_adapter = HTTPAdapter()
more_specific_prefix_adapter = HTTPAdapter()
s.mount(prefix, prefix_adapter)
s.mount(more_specific_prefix, more_specific_prefix_adapter)
assert s.get_adapter(url_matching_only_prefix) is prefix_adapter
assert s.get_adapter(url_matching_more_specific_prefix) is more_specific_prefix_adapter
assert s.get_adapter(url_not_matching_prefix) not in (prefix_adapter, more_specific_prefix_adapter)
def test_session_get_adapter_prefix_matching_mixed_case(self):
mixed_case_prefix = 'hTtPs://eXamPle.CoM/MixEd_CAse_PREfix'
url_matching_prefix = mixed_case_prefix + '/full_url'
s = requests.Session()
my_adapter = HTTPAdapter()
s.mount(mixed_case_prefix, my_adapter)
assert s.get_adapter(url_matching_prefix) is my_adapter
def test_session_get_adapter_prefix_matching_is_case_insensitive(self):
mixed_case_prefix = 'hTtPs://eXamPle.CoM/MixEd_CAse_PREfix'
url_matching_prefix_with_different_case = 'HtTpS://exaMPLe.cOm/MiXeD_caSE_preFIX/another_url'
s = requests.Session()
my_adapter = HTTPAdapter()
s.mount(mixed_case_prefix, my_adapter)
assert s.get_adapter(url_matching_prefix_with_different_case) is my_adapter
def test_header_remove_is_case_insensitive(self, httpbin):
# From issue #1321
s = requests.Session()
@@ -1357,7 +1458,7 @@ class TestRequests:
assert r.json()['args'] == {'foo': 'bar', 'FOO': 'bar'}
def test_long_authinfo_in_url(self):
url = 'http://{0}:{1}@{2}:9000/path?query#frag'.format(
url = 'http://{}:{}@{}:9000/path?query#frag'.format(
'E8A3BE87-9E3F-4620-8858-95478E385B5B',
'EA770032-DA4D-4D84-8CE9-29C6D910BF1E',
'exactly-------------sixty-----------three------------characters',
@@ -1393,14 +1494,17 @@ class TestRequests:
headers_list = {'baz': ['foo', 'bar']}
# Test for int
with pytest.raises(InvalidHeader):
with pytest.raises(InvalidHeader) as excinfo:
r = requests.get(httpbin('get'), headers=headers_int)
assert 'foo' in str(excinfo.value)
# Test for dict
with pytest.raises(InvalidHeader):
with pytest.raises(InvalidHeader) as excinfo:
r = requests.get(httpbin('get'), headers=headers_dict)
assert 'bar' in str(excinfo.value)
# Test for list
with pytest.raises(InvalidHeader):
with pytest.raises(InvalidHeader) as excinfo:
r = requests.get(httpbin('get'), headers=headers_list)
assert 'baz' in str(excinfo.value)
def test_header_no_return_chars(self, httpbin):
"""Ensure that a header containing return character sequences raise an
@@ -1469,15 +1573,15 @@ class TestRequests:
preq = req.prepare()
assert test_url == preq.url
@pytest.mark.xfail(raises=ConnectionError)
def test_auth_is_stripped_on_redirect_off_host(self, httpbin):
def test_auth_is_stripped_on_http_downgrade(self, httpbin, httpbin_secure, httpbin_ca_bundle):
r = requests.get(
httpbin('redirect-to'),
params={'url': 'http://www.google.co.uk'},
httpbin_secure('redirect-to'),
params={'url': httpbin('get')},
auth=('user', 'pass'),
verify=httpbin_ca_bundle
)
assert r.history[0].request.headers['Authorization']
assert not r.request.headers.get('Authorization', '')
assert 'Authorization' not in r.request.headers
def test_auth_is_retained_for_redirect_on_host(self, httpbin):
r = requests.get(httpbin('redirect/1'), auth=('user', 'pass'))
@@ -1486,6 +1590,27 @@ class TestRequests:
assert h1 == h2
def test_should_strip_auth_host_change(self):
s = requests.Session()
assert s.should_strip_auth('http://example.com/foo', 'http://another.example.com/')
def test_should_strip_auth_http_downgrade(self):
s = requests.Session()
assert s.should_strip_auth('https://example.com/foo', 'http://example.com/bar')
def test_should_strip_auth_https_upgrade(self):
s = requests.Session()
assert not s.should_strip_auth('http://example.com/foo', 'https://example.com/bar')
assert not s.should_strip_auth('http://example.com:80/foo', 'https://example.com/bar')
assert not s.should_strip_auth('http://example.com/foo', 'https://example.com:443/bar')
# Non-standard ports should trigger stripping
assert s.should_strip_auth('http://example.com:8080/foo', 'https://example.com/bar')
assert s.should_strip_auth('http://example.com/foo', 'https://example.com:8443/bar')
def test_should_strip_auth_port_change(self):
s = requests.Session()
assert s.should_strip_auth('http://example.com:1234/foo', 'https://example.com:4321/bar')
def test_manual_redirect_with_partial_body_read(self, httpbin):
s = requests.Session()
r1 = s.get(httpbin('redirect/2'), allow_redirects=False, stream=True)
@@ -1507,13 +1632,11 @@ class TestRequests:
def test_prepare_body_position_non_stream(self):
data = b'the data'
s = requests.Session()
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position is None
def test_rewind_body(self):
data = io.BytesIO(b'the data')
s = requests.Session()
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position == 0
assert prep.body.read() == b'the data'
@@ -1527,7 +1650,6 @@ class TestRequests:
def test_rewind_partially_read_body(self):
data = io.BytesIO(b'the data')
s = requests.Session()
data.read(4) # read some data
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position == 4
@@ -1552,7 +1674,6 @@ class TestRequests:
return
data = BadFileObj('the data')
s = requests.Session()
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position == 0
@@ -1576,7 +1697,6 @@ class TestRequests:
return
data = BadFileObj('the data')
s = requests.Session()
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position == 0
@@ -1597,7 +1717,6 @@ class TestRequests:
return
data = BadFileObj('the data')
s = requests.Session()
prep = requests.Request('GET', 'http://example.com', data=data).prepare()
assert prep._body_position is not None
@@ -1668,6 +1787,12 @@ class TestRequests:
next(it)
assert len(list(it)) == 3
def test_response_context_manager(self, httpbin):
with requests.get(httpbin('stream/4'), stream=True) as response:
assert isinstance(response, requests.Response)
assert response.raw.closed
def test_unconsumed_session_response_closes_connection(self, httpbin):
s = requests.session()
@@ -1697,12 +1822,12 @@ class TestRequests:
proxies['one'].clear.assert_called_once_with()
proxies['two'].clear.assert_called_once_with()
def test_proxy_auth(self, httpbin):
def test_proxy_auth(self):
adapter = HTTPAdapter()
headers = adapter.proxy_headers("http://user:pass@httpbin.org")
assert headers == {'Proxy-Authorization': 'Basic dXNlcjpwYXNz'}
def test_proxy_auth_empty_pass(self, httpbin):
def test_proxy_auth_empty_pass(self):
adapter = HTTPAdapter()
headers = adapter.proxy_headers("http://user:@httpbin.org")
assert headers == {'Proxy-Authorization': 'Basic dXNlcjo='}
@@ -2075,7 +2200,7 @@ class TestTimeout:
pass
def test_encoded_methods(self, httpbin):
"""See: https://github.com/kennethreitz/requests/issues/2316"""
"""See: https://github.com/requests/requests/issues/2316"""
r = requests.request(b'GET', httpbin('get'))
assert r.ok
@@ -2301,6 +2426,16 @@ class TestPreparingURLs(object):
with pytest.raises(requests.exceptions.InvalidURL):
r.prepare()
@pytest.mark.parametrize(
'url, exception',
(
('http://localhost:-1', InvalidURL),
)
)
def test_redirecting_to_bad_url(self, httpbin, url, exception):
with pytest.raises(exception):
r = requests.get(httpbin('redirect-to'), params={'url': url})
@pytest.mark.parametrize(
'input, expected',
(
@@ -2364,7 +2499,7 @@ class TestPreparingURLs(object):
)
def test_parameters_for_nonstandard_schemes(self, input, params, expected):
"""
Setting paramters for nonstandard schemes is allowed if those schemes
Setting parameters for nonstandard schemes is allowed if those schemes
begin with "http", and is forbidden otherwise.
"""
r = requests.Request('GET', url=input, params=params)

View File

@@ -50,7 +50,7 @@ class TestTestServer:
)
with server as (host, port):
r = requests.get('http://{0}:{1}'.format(host, port))
r = requests.get('http://{}:{}'.format(host, port))
assert r.status_code == 200
assert r.text == u'roflol'
@@ -59,7 +59,7 @@ class TestTestServer:
def test_basic_response(self):
"""the basic response server returns an empty http response"""
with Server.basic_response_server() as (host, port):
r = requests.get('http://{0}:{1}'.format(host, port))
r = requests.get('http://{}:{}'.format(host, port))
assert r.status_code == 200
assert r.text == u''
assert r.headers['Content-Length'] == '0'
@@ -83,7 +83,7 @@ class TestTestServer:
server = Server.basic_response_server(requests_to_handle=requests_to_handle)
with server as (host, port):
server_url = 'http://{0}:{1}'.format(host, port)
server_url = 'http://{}:{}'.format(host, port)
for _ in range(requests_to_handle):
r = requests.get(server_url)
assert r.status_code == 200
@@ -92,8 +92,10 @@ class TestTestServer:
with pytest.raises(requests.exceptions.ConnectionError):
r = requests.get(server_url)
@pytest.mark.skip(reason="this fails non-deterministically under pytest-xdist")
def test_request_recovery(self):
"""can check the requests content"""
# TODO: figure out why this sometimes fails when using pytest-xdist.
server = Server.basic_response_server(requests_to_handle=2)
first_request = b'put your hands up in the air'
second_request = b'put your hand down in the floor'

View File

@@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
import os
import copy
import filecmp
from io import BytesIO
import zipfile
from collections import deque
import pytest
from requests import compat
from requests.cookies import RequestsCookieJar
from requests.structures import CaseInsensitiveDict
from requests.utils import (
address_in_network, dotted_netmask,
get_auth_from_url, get_encoding_from_headers,
address_in_network, dotted_netmask, extract_zipped_paths,
get_auth_from_url, _parse_content_type_header, get_encoding_from_headers,
get_encodings_from_content, get_environ_proxies,
guess_filename, guess_json_utf, is_ipv4_address,
is_valid_cidr, iter_slices, parse_dict_header,
@@ -17,7 +21,7 @@ from requests.utils import (
requote_uri, select_proxy, should_bypass_proxies, super_len,
to_key_val_list, to_native_string,
unquote_header_value, unquote_unreserved,
urldefragauth, add_dict_to_cookiejar)
urldefragauth, add_dict_to_cookiejar, set_environ)
from requests._internal_utils import unicode_is_ascii
from .compat import StringIO, cStringIO
@@ -255,6 +259,32 @@ class TestGuessFilename:
assert isinstance(result, expected_type)
class TestExtractZippedPaths:
@pytest.mark.parametrize(
'path', (
'/',
__file__,
pytest.__file__,
'/etc/invalid/location',
))
def test_unzipped_paths_unchanged(self, path):
assert path == extract_zipped_paths(path)
def test_zipped_paths_extracted(self, tmpdir):
zipped_py = tmpdir.join('test.zip')
with zipfile.ZipFile(zipped_py.strpath, 'w') as f:
f.write(__file__)
_, name = os.path.splitdrive(__file__)
zipped_path = os.path.join(zipped_py.strpath, name.lstrip(r'\/'))
extracted_path = extract_zipped_paths(zipped_path)
assert extracted_path != zipped_path
assert os.path.exists(extracted_path)
assert filecmp.cmp(extracted_path, __file__)
class TestContentEncodingDetection:
def test_none(self):
@@ -367,7 +397,7 @@ def test_get_auth_from_url(url, auth):
),
))
def test_requote_uri_with_unquoted_percents(uri, expected):
"""See: https://github.com/kennethreitz/requests/issues/2356"""
"""See: https://github.com/requests/requests/issues/2356"""
assert requote_uri(uri) == expected
@@ -440,6 +470,49 @@ def test_parse_dict_header(value, expected):
assert parse_dict_header(value) == expected
@pytest.mark.parametrize(
'value, expected', (
(
'application/xml',
('application/xml', {})
),
(
'application/json ; charset=utf-8',
('application/json', {'charset': 'utf-8'})
),
(
'application/json ; Charset=utf-8',
('application/json', {'charset': 'utf-8'})
),
(
'text/plain',
('text/plain', {})
),
(
'multipart/form-data; boundary = something ; boundary2=\'something_else\' ; no_equals ',
('multipart/form-data', {'boundary': 'something', 'boundary2': 'something_else', 'no_equals': True})
),
(
'multipart/form-data; boundary = something ; boundary2="something_else" ; no_equals ',
('multipart/form-data', {'boundary': 'something', 'boundary2': 'something_else', 'no_equals': True})
),
(
'multipart/form-data; boundary = something ; \'boundary2=something_else\' ; no_equals ',
('multipart/form-data', {'boundary': 'something', 'boundary2': 'something_else', 'no_equals': True})
),
(
'multipart/form-data; boundary = something ; "boundary2=something_else" ; no_equals ',
('multipart/form-data', {'boundary': 'something', 'boundary2': 'something_else', 'no_equals': True})
),
(
'application/json ; ; ',
('application/json', {})
)
))
def test__parse_content_type_header(value, expected):
assert _parse_content_type_header(value) == expected
@pytest.mark.parametrize(
'value, expected', (
(
@@ -497,6 +570,10 @@ def test_iter_slices(value, length):
{'url': 'http://.../back.jpeg'}
]
),
(
'',
[]
),
))
def test_parse_header_links(value, expected):
assert parse_header_links(value) == expected
@@ -541,19 +618,41 @@ def test_urldefragauth(url, expected):
('http://172.16.1.1/', True),
('http://172.16.1.1:5000/', True),
('http://localhost.localdomain:5000/v1.0/', True),
('http://google.com:6000/', True),
('http://172.16.1.12/', False),
('http://172.16.1.12:5000/', False),
('http://google.com:5000/v1.0/', False),
('file:///some/path/on/disk', True),
))
def test_should_bypass_proxies(url, expected, monkeypatch):
"""Tests for function should_bypass_proxies to check if proxy
can be bypassed or not
"""
monkeypatch.setenv('no_proxy', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1')
monkeypatch.setenv('NO_PROXY', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1')
monkeypatch.setenv('no_proxy', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1, google.com:6000')
monkeypatch.setenv('NO_PROXY', '192.168.0.0/24,127.0.0.1,localhost.localdomain,172.16.1.1, google.com:6000')
assert should_bypass_proxies(url, no_proxy=None) == expected
@pytest.mark.parametrize(
'url, expected', (
('http://172.16.1.1/', '172.16.1.1'),
('http://172.16.1.1:5000/', '172.16.1.1'),
('http://user:pass@172.16.1.1', '172.16.1.1'),
('http://user:pass@172.16.1.1:5000', '172.16.1.1'),
('http://hostname/', 'hostname'),
('http://hostname:5000/', 'hostname'),
('http://user:pass@hostname', 'hostname'),
('http://user:pass@hostname:5000', 'hostname'),
))
def test_should_bypass_proxies_pass_only_hostname(url, expected, mocker):
"""The proxy_bypass function should be called with a hostname or IP without
a port number or auth credentials.
"""
proxy_bypass = mocker.patch('requests.utils.proxy_bypass')
should_bypass_proxies(url, no_proxy=None)
proxy_bypass.assert_called_once_with(expected)
@pytest.mark.parametrize(
'cookiejar', (
compat.cookielib.CookieJar(),
@@ -566,7 +665,7 @@ def test_add_dict_to_cookiejar(cookiejar):
cookiedict = {'test': 'cookies',
'good': 'cookies'}
cj = add_dict_to_cookiejar(cookiejar, cookiedict)
cookies = dict((cookie.name, cookie.value) for cookie in cj)
cookies = {cookie.name: cookie.value for cookie in cj}
assert cookiedict == cookies
@@ -633,6 +732,7 @@ def test_should_bypass_proxies_win_registry(url, expected, override,
pass
ie_settings = RegHandle()
proxyEnableValues = deque([1, "1"])
def OpenKey(key, subkey):
return ie_settings
@@ -640,7 +740,9 @@ def test_should_bypass_proxies_win_registry(url, expected, override,
def QueryValueEx(key, value_name):
if key is ie_settings:
if value_name == 'ProxyEnable':
return [1]
# this could be a string (REG_SZ) or a 32-bit number (REG_DWORD)
proxyEnableValues.rotate()
return [proxyEnableValues[0]]
elif value_name == 'ProxyOverride':
return [override]
@@ -651,4 +753,30 @@ def test_should_bypass_proxies_win_registry(url, expected, override,
monkeypatch.setenv('NO_PROXY', '')
monkeypatch.setattr(winreg, 'OpenKey', OpenKey)
monkeypatch.setattr(winreg, 'QueryValueEx', QueryValueEx)
assert should_bypass_proxies(url, no_proxy=None) == expected
assert should_bypass_proxies(url, None) == expected
@pytest.mark.parametrize(
'env_name, value', (
('no_proxy', '192.168.0.0/24,127.0.0.1,localhost.localdomain'),
('no_proxy', None),
('a_new_key', '192.168.0.0/24,127.0.0.1,localhost.localdomain'),
('a_new_key', None),
))
def test_set_environ(env_name, value):
"""Tests set_environ will set environ values and will restore the environ."""
environ_copy = copy.deepcopy(os.environ)
with set_environ(env_name, value):
assert os.environ.get(env_name) == value
assert os.environ == environ_copy
def test_set_environ_raises_exception():
"""Tests set_environ will raise exceptions in context when the
value parameter is None."""
with pytest.raises(Exception) as exception:
with set_environ('test1', None):
raise Exception('Expected exception')
assert 'Expected exception' in str(exception.value)

8
tox.ini Normal file
View File

@@ -0,0 +1,8 @@
[tox]
envlist = py27,py34,py35,py36
[testenv]
commands =
pip install -e .[socks]
python setup.py test