Compare commits

...

93 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
51 changed files with 2456 additions and 1997 deletions

View File

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

View File

@@ -1,14 +1,5 @@
sudo: false
language: python
python:
# - "2.6"
- "2.7"
- "3.4"
- "3.5"
- "3.6"
- "3.7-dev"
# - "pypy" -- appears to hang
# - "pypy3"
# command to install dependencies
install: "make"
# command to run tests
@@ -21,9 +12,31 @@ jobs:
include:
- stage: test
script:
- |
if [[ "$TRAVIS_PYTHON_VERSION" != "2.6" ]] ; then make test-readme; fi
- 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

View File

@@ -125,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>`_)
@@ -188,3 +188,4 @@ Patches and Suggestions
- 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

@@ -4,7 +4,7 @@ Copyright 2018 Kenneth Reitz
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 requirements.txt
include README.md LICENSE NOTICE HISTORY.md pytest.ini requirements.txt Pipfile Pipfile.lock
recursive-include tests *.py

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,110 +0,0 @@
Requests: HTTP for Humans
=========================
.. image:: https://img.shields.io/pypi/v/requests.svg
:target: https://pypi.org/project/requests/
.. image:: https://img.shields.io/pypi/l/requests.svg
:target: https://pypi.org/project/requests/
.. image:: https://img.shields.io/pypi/pyversions/requests.svg
:target: https://pypi.org/project/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/github/contributors/requests/requests.svg
:target: https://github.com/requests/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.
.. image:: https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg
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/requests/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.7 & 3.43.6, and runs great on PyPy.
Installation
------------
To install Requests, simply use `pipenv <http://pipenv.org/>`_ (or pip, of course):
.. code-block:: 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
-----------------
#. 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`: https://github.com/requests/requests
.. _AUTHORS: https://github.com/requests/requests/blob/master/AUTHORS.rst
.. _Contributor Friendly: https://github.com/requests/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
@@ -25,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 }

View File

@@ -6,15 +6,16 @@ body > div.document > div.sphinxsidebar > div > form > table > tbody > tr:nth-ch
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;
border: solid 1px #cccccc;
margin: 1.5em 0 2em;
border-radius: 2px;
line-height: 1.5;
}
@@ -42,6 +43,140 @@ body > div.document > div.sphinxsidebar > div > form > table > tbody > tr:nth-ch
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

@@ -1,33 +1,4 @@
<!-- Alabaster (krTheme++) Hacks -->
<aside id="python27">
<a href="https://www.kennethreitz.org/requests3"><strong>Requests 3.0</strong> development is underway, and your financial help is appreciated!</a>
</aside>
<!-- Python 2 Death Clock™ -->
<style type="text/css">
body { margin-top: 4em; }
#python27 {
position: fixed;
top: 0;
left: 0; right: 0;
height: auto;
text-align: center;
color: white;
background-color: black;
font-size: larger;
line-height: 3;
}
</style>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script>
var death = new Date('2020-04-12');
var diff = moment.duration(death - moment());
document.querySelector('#python27 time').innerText = (diff.years() * 12) + diff.months();
</script> -->
<!-- CSS Adjustments (I'm very picky.) -->
<style type="text/css">
@@ -82,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

@@ -16,9 +16,8 @@
<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>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=pythonrequestsorg" id="_carbonads_js"></script>
<script async type="text/javascript" src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=CKYI5K3E&placement=pythonrequestsorg" id="_carbonads_js"></script>
<p><a href="http://www.unixstickers.com/stickers/coding_stickers/requests-shaped-sticker">Requests Stickers!</a></p>
<h3>Stay Informed</h3>
<p>Receive updates on new releases and upcoming projects.</p>
@@ -26,17 +25,17 @@
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="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://html.python-requests.org/">Requests-HTML</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>
@@ -69,3 +68,42 @@
<li><a href="http://it.python-requests.org/">Italian</a></li>
<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

@@ -20,9 +20,7 @@
<h3>Stay Informed</h3>
<p>Receive updates on new releases and upcoming projects.</p>
<p><a href="http://www.unixstickers.com/stickers/coding_stickers/requests-shaped-sticker">Requests Stickers!</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>
<hr/>
@@ -36,14 +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://html.python-requests.org/">Requests-HTML</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>

View File

@@ -139,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'.
@@ -185,7 +185,7 @@ API Changes
requests_log.setLevel(logging.DEBUG)
requests_log.propagate = True
requests.get('http://httpbin.org/headers')
requests.get('https://httpbin.org/headers')
@@ -197,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
@@ -213,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

@@ -60,6 +60,7 @@ supported:
* Python 3.4
* Python 3.5
* Python 3.6
* Python 3.7
* PyPy
What are "hostname doesn't match" errors?

View File

@@ -15,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>`_ )
- `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 <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/>`_
- `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

@@ -7,18 +7,18 @@ Support
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>`_.

View File

@@ -97,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

@@ -376,4 +376,7 @@ epub_exclude_files = ['search.html']
# If false, no index is generated.
#epub_use_index = True
intersphinx_mapping = {'urllib3': ('https://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

@@ -41,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:
@@ -157,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

View File

@@ -9,7 +9,7 @@ Requests is an open but opinionated library, created by an open but opinionated
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, 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.
`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. Their word is, in some ways, more final than Kenneth's.
@@ -26,7 +26,7 @@ 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?
~~~~~~~~~~~~~~~~~

View File

@@ -55,6 +55,7 @@ Requests currently supports the following versions of Python:
- Python 3.4
- Python 3.5
- Python 3.6
- Python 3.7
- PyPy
Google AppEngine is not officially supported although support is available

View File

@@ -3,8 +3,8 @@
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>`)
@@ -30,6 +30,9 @@ consumption.
.. 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.
-------------------

View File

@@ -25,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"}}'
@@ -40,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
@@ -53,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": {}}'
@@ -69,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.
@@ -97,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::
@@ -323,7 +323,7 @@ inefficiency with connections. If you find yourself partially reading request
bodies (or not reading them at all) while using ``stream=True``, you should
make the request within a ``with`` statement to ensure it's always closed::
with 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.
.. _keep-alive:
@@ -351,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/3/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:
@@ -395,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'))]
@@ -408,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/3/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:
@@ -459,13 +455,13 @@ anything, nothing else is affected.
Let's print some request method arguments at runtime::
>>> requests.get('http://httpbin.org', hooks={'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('http://httpbin.org', hooks={'response': [print_url, record_hook]})
>>> r = requests.get('https://httpbin.org/', hooks={'response': [print_url, record_hook]})
>>> r.hook_called
True
@@ -474,8 +470,8 @@ be called on every request made to the session. For example::
>>> s = requests.Session()
>>> s.hooks['response'].append(print_url)
>>> s.get('http://httpbin.org')
http://httpbin.org
>>> s.get('https://httpbin.org/')
https://httpbin.org/
<Response [200]>
A ``Session`` can have multiple hooks, which will be called in the order
@@ -533,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():
@@ -547,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'
@@ -661,7 +657,7 @@ encoding in the HTTP header, and if none is present, will use `chardet
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>`
@@ -925,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
@@ -963,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:
@@ -1007,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
@@ -1032,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

@@ -53,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]>
@@ -122,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]>
@@ -134,7 +134,7 @@ 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: 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

View File

@@ -18,7 +18,7 @@ To install Requests, simply run this simple command in your terminal of choice::
$ pipenv install requests
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 <http://docs.python-guide.org/en/latest/starting/installation/>`_
`this Python installation guide <https://docs.python-guide.org/starting/installation/>`_
can guide you through the process.
Get the Source Code

View File

@@ -37,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

@@ -39,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.
@@ -65,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.
@@ -79,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
----------------
@@ -233,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)
{
...
@@ -244,12 +244,16 @@ dictionary of data will automatically be form-encoded when the request is made::
...
}
You can also pass a list of tuples to the ``data`` argument. This is particularly
useful when the form has multiple elements that use the same key::
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 = (('key1', 'value1'), ('key1', 'value2'))
>>> r = requests.post('http://httpbin.org/post', data=payload)
>>> print(r.text)
>>> 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": {
@@ -260,6 +264,8 @@ useful when the form has multiple elements that use the same key::
},
...
}
>>> 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.
@@ -290,7 +296,7 @@ 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)
@@ -305,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)
@@ -320,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)
@@ -342,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/3/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
@@ -356,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
@@ -370,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
@@ -406,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::
@@ -420,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
@@ -441,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)
@@ -456,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"}}'
@@ -477,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/'
@@ -492,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
@@ -502,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/'
@@ -519,7 +523,7 @@ 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)
{
...
@@ -57,10 +57,10 @@ def check_compatibility(urllib3_version, chardet_version):
# 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.23
# urllib3 >= 1.21.1, <= 1.24
assert major == 1
assert minor >= 21
assert minor <= 23
assert minor <= 24
# Check chardet for compatibility.
major, minor, patch = chardet_version.split('.')[:3]
@@ -79,14 +79,14 @@ def _check_cryptography(cryptography_version):
return
if cryptography_version < [1, 3, 4]:
warning = 'Old version of cryptography ({0}) may cause slowdown.'.format(cryptography_version)
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 ({0}) or chardet ({1}) doesn't match a supported "
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
"version!".format(urllib3.__version__, chardet.__version__),
RequestsDependencyWarning)
@@ -123,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,8 +5,8 @@
__title__ = 'requests'
__description__ = 'Python HTTP for Humans.'
__url__ = 'http://python-requests.org'
__version__ = '2.19.0'
__build__ = 0x021900
__version__ = '2.20.0'
__build__ = 0x022000
__author__ = 'Kenneth Reitz'
__author_email__ = 'me@kennethreitz.org'
__license__ = 'Apache 2.0'

View File

@@ -26,6 +26,7 @@ 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
@@ -35,7 +36,8 @@ from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths,
from .structures import CaseInsensitiveDict
from .cookies import extract_cookies_to_jar
from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError,
ProxyError, RetryError, InvalidSchema, InvalidProxyURL)
ProxyError, RetryError, InvalidSchema, InvalidProxyURL,
InvalidURL)
from .auth import _basic_auth_str
try:
@@ -127,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
@@ -224,7 +225,7 @@ class HTTPAdapter(BaseAdapter):
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'
@@ -246,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
@@ -378,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 = {}
@@ -407,7 +408,10 @@ 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)
@@ -421,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)
@@ -471,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(

View File

@@ -18,8 +18,10 @@ 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 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`.
@@ -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
@@ -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,7 +135,8 @@ 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

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,

View File

@@ -43,9 +43,8 @@ if is_py2:
import cookielib
from Cookie import Morsel
from StringIO import StringIO
from collections import Callable, Mapping, MutableMapping
from collections import Callable, Mapping, MutableMapping, OrderedDict
from urllib3.packages.ordered_dict import OrderedDict
builtin_str = str
bytes = str

View File

@@ -444,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:
@@ -511,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()
@@ -529,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

@@ -89,8 +89,7 @@ def info():
'version': getattr(idna, '__version__', ''),
}
# OPENSSL_VERSION_NUMBER doesn't exist in the Python 2.6 ssl module.
system_ssl = getattr(ssl, 'OPENSSL_VERSION_NUMBER', None)
system_ssl = ssl.OPENSSL_VERSION_NUMBER
system_ssl_info = {
'version': '%x' % system_ssl if system_ssl is not None else ''
}

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

@@ -204,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.
@@ -214,7 +218,7 @@ 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]>
"""
@@ -274,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]>
@@ -648,10 +652,7 @@ class Response(object):
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():

View File

@@ -115,6 +115,22 @@ 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."""
@@ -236,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
@@ -299,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'
@@ -325,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]>
"""
@@ -453,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
@@ -550,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
@@ -562,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
"""
@@ -573,7 +587,8 @@ 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
"""
@@ -723,7 +738,7 @@ 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 = {attr: getattr(self, attr, None) for attr in self.__attrs__}
return state
def __setstate__(self, state):
@@ -735,7 +750,12 @@ 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,6 +1,6 @@
# -*- 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.
@@ -114,6 +114,7 @@ def _init():
global __doc__
__doc__ = (__doc__ + '\n' +
'\n'.join(doc(code) for code in sorted(_codes)))
'\n'.join(doc(code) for code in sorted(_codes))
if __doc__ is not None else None)
_init()

View File

@@ -173,10 +173,10 @@ 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 &
# getpwuid fails. See https://bugs.python.org/issue20164 &
# https://github.com/requests/requests/issues/1846
return
@@ -466,7 +466,7 @@ def _parse_content_type_header(header):
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] = value
params_dict[key.lower()] = value
return content_type, params_dict
@@ -706,6 +706,10 @@ def should_bypass_proxies(url, no_proxy):
no_proxy = get_proxy('no_proxy')
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 hostname, both with and without the port.
@@ -725,7 +729,7 @@ def should_bypass_proxies(url, no_proxy):
else:
host_with_port = parsed.hostname
if parsed.port:
host_with_port += ':{0}'.format(parsed.port)
host_with_port += ':{}'.format(parsed.port)
for host in no_proxy:
if parsed.hostname.endswith(host) or host_with_port.endswith(host):
@@ -733,13 +737,8 @@ def should_bypass_proxies(url, no_proxy):
# 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(parsed.hostname)
except (TypeError, socket.gaierror):

View File

@@ -1,6 +1,5 @@
#!/usr/bin/env python
# Learn more: https://github.com/kennethreitz/setup.py
import os
import re
import sys
@@ -40,38 +39,39 @@ if sys.argv[-1] == 'publish':
os.system('twine upload dist/*')
sys.exit()
# pyOpenSSL version 18.0.0 dropped support for Python 2.6
if sys.version_info < (2, 7):
PYOPENSSL_VERSION = 'pyOpenSSL >= 0.14, < 18.0.0'
else:
PYOPENSSL_VERSION = 'pyOpenSSL >= 0.14'
packages = ['requests']
requires = [
'chardet>=3.0.2,<3.1.0',
'idna>=2.5,<2.8',
'urllib3>=1.21.1,<1.24',
'urllib3>=1.21.1,<1.25',
'certifi>=2017.4.17'
]
test_requirements = ['pytest-httpbin==0.0.7', 'pytest-cov', 'pytest-mock', 'pytest-xdist', 'PySocks>=1.5.6, !=1.5.7', 'pytest>=2.8.0']
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_content_type='text/x-rst',
long_description=readme,
long_description_content_type='text/markdown',
author=about['__author__'],
author_email=about['__author_email__'],
url=about['__url__'],
@@ -79,11 +79,11 @@ setup(
package_data={'': ['LICENSE', 'NOTICE'], 'requests': ['*.pem']},
package_dir={'requests': 'requests'},
include_package_data=True,
python_requires=">=2.6, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*",
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',
@@ -95,14 +95,15 @@ setup(
'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_VERSION, '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'],
},
)

View File

@@ -7,15 +7,6 @@ import pytest
from requests.help import info
@pytest.mark.skipif(sys.version_info[:2] != (2,6), reason="Only run on Python 2.6")
def test_system_ssl_py26():
"""OPENSSL_VERSION_NUMBER isn't provided in Python 2.6, verify we don't
blow up in this case.
"""
assert info()['system_ssl'] == {'version': ''}
@pytest.mark.skipif(sys.version_info < (2,7), reason="Only run on Python 2.7+")
def test_system_ssl():
"""Verify we're actually setting system_ssl when it should be available."""
assert info()['system_ssl']['version'] != ''

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
@@ -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
@@ -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,13 +226,13 @@ 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()
@@ -250,7 +250,7 @@ def test_fragment_not_sent_with_request():
server = Server(response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{0}:{1}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
url = 'http://{}:{}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
r = requests.get(url)
raw_request = r.content
@@ -267,7 +267,7 @@ def test_fragment_not_sent_with_request():
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 encounterd in a Location header, it should
location. If a new fragment is encountered in a Location header, it should
be added to all subsequent requests.
"""
@@ -293,7 +293,7 @@ def test_fragment_update_on_redirect():
server = Server(response_handler, wait_to_close_event=close_server)
with server as (host, port):
url = 'http://{0}:{1}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
url = 'http://{}:{}/path/to/thing/#view=edit&token=hunter2'.format(host, port)
r = requests.get(url)
raw_request = r.content
@@ -302,8 +302,8 @@ def test_fragment_update_on_redirect():
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://{0}:{1}/get#relevant-section'.format(host, port)
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://{0}:{1}/final-url/#relevant-section'.format(host, port)
assert r.url == 'http://{}:{}/final-url/#relevant-section'.format(host, port)
close_server.set()

View File

@@ -158,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'))
@@ -816,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='.')
@@ -864,10 +864,16 @@ class TestRequests:
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})},
@@ -1400,7 +1406,7 @@ class TestRequests:
assert 'http://' in s2.adapters
assert 'https://' in s2.adapters
def test_session_get_adapter_prefix_matching(self, httpbin):
def test_session_get_adapter_prefix_matching(self):
prefix = 'https://example.com'
more_specific_prefix = prefix + '/some/path'
@@ -1418,7 +1424,7 @@ class TestRequests:
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, httpbin):
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'
@@ -1428,7 +1434,7 @@ class TestRequests:
assert s.get_adapter(url_matching_prefix) is my_adapter
def test_session_get_adapter_prefix_matching_is_case_insensitive(self, httpbin):
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'
@@ -1452,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',
@@ -1567,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'))
@@ -1584,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)
@@ -1605,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'
@@ -1625,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
@@ -1650,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
@@ -1674,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
@@ -1695,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
@@ -1801,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='}
@@ -2405,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',
(

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

View File

@@ -480,6 +480,10 @@ def test_parse_dict_header(value, expected):
'application/json ; charset=utf-8',
('application/json', {'charset': 'utf-8'})
),
(
'application/json ; Charset=utf-8',
('application/json', {'charset': 'utf-8'})
),
(
'text/plain',
('text/plain', {})
@@ -618,6 +622,7 @@ def test_urldefragauth(url, expected):
('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
@@ -660,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

View File

@@ -1,5 +1,5 @@
[tox]
envlist = py26,py27,py34,py35,py36
envlist = py27,py34,py35,py36
[testenv]