Compare commits
144 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0192aac241 | ||
|
|
e50dc12b0f | ||
|
|
17e6e27a93 | ||
|
|
ab38e2c726 | ||
|
|
77d1e9aa3e | ||
|
|
b0829a8690 | ||
|
|
28d537dde3 | ||
|
|
86bbee71b2 | ||
|
|
0d5347e628 | ||
|
|
ef59aa0227 | ||
|
|
d09659997c | ||
|
|
2b06a952a9 | ||
|
|
e2064a2c05 | ||
|
|
401e17bbdc | ||
|
|
4246792b81 | ||
|
|
658c10e84a | ||
|
|
39d0fdd909 | ||
|
|
c193d9742e | ||
|
|
8e764f355d | ||
|
|
7556ea4213 | ||
|
|
2d2447e210 | ||
|
|
e77dd8de6e | ||
|
|
55da533a87 | ||
|
|
99b3b49241 | ||
|
|
590350f8d0 | ||
|
|
9dd6e47b5b | ||
|
|
94f9f7357e | ||
|
|
fc106ab586 | ||
|
|
1e5fad7433 | ||
|
|
248122a697 | ||
|
|
9572d6a299 | ||
|
|
4ab2550d66 | ||
|
|
6fbfca90b6 | ||
|
|
aae78010e9 | ||
|
|
10968357a1 | ||
|
|
b351e906b6 | ||
|
|
70a13e2a26 | ||
|
|
8ea90a5ce7 | ||
|
|
7adb8686ac | ||
|
|
827b87b9be | ||
|
|
2d30aeb7c6 | ||
|
|
b0e025ade7 | ||
|
|
d8829f9f24 | ||
|
|
b227e3cb82 | ||
|
|
db575eeedc | ||
|
|
941a77f2b8 | ||
|
|
a3d54b83f7 | ||
|
|
a5b45edf2f | ||
|
|
a1a6a549a0 | ||
|
|
e253eba5ed | ||
|
|
f6c0619d89 | ||
|
|
33cf965f72 | ||
|
|
5351469472 | ||
|
|
24630743ce | ||
|
|
2ed84f55b2 | ||
|
|
33d448eb21 | ||
|
|
1466ad713c | ||
|
|
f6d43b03fb | ||
|
|
05a1a21593 | ||
|
|
c45a4dfe6b | ||
|
|
2c2138e811 | ||
|
|
c267415882 | ||
|
|
5433656878 | ||
|
|
f79d1ef42f | ||
|
|
4193b95db0 | ||
|
|
06462a6e79 | ||
|
|
913880c45a | ||
|
|
bdc00eb097 | ||
|
|
ef6ceffc1c | ||
|
|
8c211a96cd | ||
|
|
74b7280049 | ||
|
|
083aa67a0d | ||
|
|
f6072f1e14 | ||
|
|
c2b307dbef | ||
|
|
6de4f104cd | ||
|
|
b223291693 | ||
|
|
516f84f490 | ||
|
|
d3e0f73354 | ||
|
|
60ea7f0c2d | ||
|
|
5035827ba4 | ||
|
|
589c454733 | ||
|
|
5855dd711f | ||
|
|
d0359c9460 | ||
|
|
f02a80cbe8 | ||
|
|
d1ca591c0f | ||
|
|
2fddbe3606 | ||
|
|
4b66260cb7 | ||
|
|
9ce669e3ae | ||
|
|
0514dea6fc | ||
|
|
962c8986ca | ||
|
|
28cc1d237b | ||
|
|
78fdf4dd92 | ||
|
|
03957eb1c2 | ||
|
|
320a10d142 | ||
|
|
9cd2d33489 | ||
|
|
2f70990cd3 | ||
|
|
ba543713d3 | ||
|
|
1431502331 | ||
|
|
4840d4a376 | ||
|
|
4f6c018715 | ||
|
|
d09c0e0f24 | ||
|
|
941ac53ba0 | ||
|
|
799a97d360 | ||
|
|
ae6144599a | ||
|
|
333fa8d3f2 | ||
|
|
c3280d7844 | ||
|
|
967a05bfff | ||
|
|
1f7c88880b | ||
|
|
22b5a39098 | ||
|
|
2a7832b5b0 | ||
|
|
48237afd9d | ||
|
|
0b01355870 | ||
|
|
43ed689d97 | ||
|
|
551a0bf0df | ||
|
|
0830062100 | ||
|
|
533c384b87 | ||
|
|
02eb5a2cd3 | ||
|
|
2d39c0db05 | ||
|
|
1b41763472 | ||
|
|
8149e9fe54 | ||
|
|
9cae7be94f | ||
|
|
1ca1c52e69 | ||
|
|
0797c61fd5 | ||
|
|
daa2b297a3 | ||
|
|
7c71982260 | ||
|
|
71a05cf289 | ||
|
|
737dd0c3c6 | ||
|
|
8ac5929ae1 | ||
|
|
2b3436e0e7 | ||
|
|
fa2dbe9a91 | ||
|
|
9ed5db8ed2 | ||
|
|
427e8eb1e7 | ||
|
|
251f73f65d | ||
|
|
db47b9b4a0 | ||
|
|
bfb93d4b7d | ||
|
|
9ea85109a5 | ||
|
|
c577eb8d5f | ||
|
|
bebf5250b0 | ||
|
|
2758124a13 | ||
|
|
4fc7f4a255 | ||
|
|
65989ddfe9 | ||
|
|
0a760ff025 | ||
|
|
ca6f9af5db | ||
|
|
b7c6aba848 |
7
.github/CODE_OF_CONDUCT.md
vendored
7
.github/CODE_OF_CONDUCT.md
vendored
@@ -1,3 +1,6 @@
|
||||
Be cordial or be on your way.
|
||||
# Treat each other well
|
||||
|
||||
https://www.kennethreitz.org/essays/be-cordial-or-be-on-your-way
|
||||
Everyone participating in the _requests_ project, and in particular in the issue tracker,
|
||||
pull requests, and social media activity, is expected to treat other people with respect
|
||||
and more generally to follow the guidelines articulated in the
|
||||
[Python Community Code of Conduct](https://www.python.org/psf/codeofconduct/).
|
||||
|
||||
7
.github/CONTRIBUTING.md
vendored
7
.github/CONTRIBUTING.md
vendored
@@ -1,10 +1,7 @@
|
||||
# Contribution Guidelines
|
||||
|
||||
Before opening any issues or proposing any pull requests, please do the
|
||||
following:
|
||||
|
||||
1. Read our [Contributor's Guide](https://requests.readthedocs.io/en/latest/dev/contributing/).
|
||||
2. Understand our [development philosophy](https://requests.readthedocs.io/en/latest/dev/philosophy/).
|
||||
Before opening any issues or proposing any pull requests, please read
|
||||
our [Contributor's Guide](https://requests.readthedocs.io/en/latest/dev/contributing/).
|
||||
|
||||
To get the greatest chance of helpful responses, please also observe the
|
||||
following additional notes.
|
||||
|
||||
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1 +1 @@
|
||||
custom: ['https://www.python.org/psf/forms/sponsor-application/']
|
||||
custom: ['https://www.python.org/psf/sponsorship/']
|
||||
|
||||
16
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
16
.github/ISSUE_TEMPLATE/Bug_report.md
vendored
@@ -4,15 +4,15 @@ about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
Summary.
|
||||
<!-- Summary. -->
|
||||
|
||||
## Expected Result
|
||||
|
||||
What you expected.
|
||||
<!-- What you expected. -->
|
||||
|
||||
## Actual Result
|
||||
|
||||
What happened instead.
|
||||
<!-- What happened instead. -->
|
||||
|
||||
## Reproduction Steps
|
||||
|
||||
@@ -25,10 +25,12 @@ import requests
|
||||
|
||||
$ python -m requests.help
|
||||
|
||||
```
|
||||
<paste here>
|
||||
```json
|
||||
{
|
||||
"paste": "here"
|
||||
}
|
||||
```
|
||||
|
||||
This command is only available on Requests v2.16.4 and greater. Otherwise,
|
||||
<!-- This command is only available on Requests v2.16.4 and greater. Otherwise,
|
||||
please provide some basic information about your system (Python version,
|
||||
operating system, &c).
|
||||
operating system, &c). -->
|
||||
|
||||
16
.github/SECURITY.md
vendored
16
.github/SECURITY.md
vendored
@@ -1,18 +1,18 @@
|
||||
# Vulnerability Disclosure
|
||||
|
||||

|
||||
|
||||
If you think you have found a potential security vulnerability in
|
||||
requests, please email
|
||||
`sigmavirus24 <mailto:graffatcolmingov@gmail.com>`\_ and
|
||||
`Nate <mailto:nate.prewitt@gmail.com>`\_ directly. **Do not file a
|
||||
public issue.**
|
||||
requests, please email [Nate](mailto:nate.prewitt@gmail.com)
|
||||
and [Seth](mailto:sethmichaellarson@gmail.com) directly.
|
||||
**Do not file a public issue.**
|
||||
|
||||
Our PGP Key fingerprints are:
|
||||
|
||||
- 0161 BB7E B208 B5E0 4FDC 9F81 D9DA 0A04 9113 F853 (@sigmavirus24)
|
||||
- 8722 7E29 AD9C FF5C FAC3 EA6A 44D3 FF97 B80D C864 ([@nateprewitt](https://keybase.io/nateprewitt))
|
||||
|
||||
- 8722 7E29 AD9C FF5C FAC3 EA6A 44D3 FF97 B80D C864 (@nateprewitt)
|
||||
- EDD5 6765 A9D8 4653 CBC8 A134 51B0 6736 1740 F5FC ([@sethmlarson](https://keybase.io/sethmlarson))
|
||||
|
||||
You can also contact us on [Keybase](https://keybase.io) with the
|
||||
profiles above if desired.
|
||||
|
||||
If English is not your first language, please try to describe the
|
||||
problem and its impact to the best of your ability. For greater detail,
|
||||
|
||||
66
.github/workflows/codeql-analysis.yml
vendored
Normal file
66
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 23 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: "python"
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
18
.github/workflows/lock-issues.yml
vendored
Normal file
18
.github/workflows/lock-issues.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: 'Lock Threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 * * * *'
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
action:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v2
|
||||
with:
|
||||
issue-lock-inactive-days: 90
|
||||
pr-lock-inactive-days: 90
|
||||
33
.github/workflows/run-tests.yml
vendored
Normal file
33
.github/workflows/run-tests.yml
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
name: Tests
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
python-version: ["2.7", "3.6", "3.7", "3.8", "3.9", "3.10"]
|
||||
os: [ubuntu-18.04, macOS-latest, windows-latest]
|
||||
include:
|
||||
# pypy3 on Mac OS currently fails trying to compile
|
||||
# brotlipy. Moving pypy3 to only test linux.
|
||||
- python-version: pypy3
|
||||
os: ubuntu-latest
|
||||
- python-version: pypy-3.7
|
||||
os: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
make
|
||||
- name: Run tests
|
||||
run: |
|
||||
make ci
|
||||
6
.gitignore
vendored
6
.gitignore
vendored
@@ -23,6 +23,12 @@ env/
|
||||
|
||||
.workon
|
||||
|
||||
# in case you work with IntelliJ/PyCharm
|
||||
.idea
|
||||
*.iml
|
||||
.python-version
|
||||
|
||||
|
||||
t.py
|
||||
|
||||
t2.py
|
||||
|
||||
26
.travis.yml
26
.travis.yml
@@ -1,26 +0,0 @@
|
||||
language: python
|
||||
# command to install dependencies
|
||||
install: "make"
|
||||
# command to run tests
|
||||
script:
|
||||
- make test-readme
|
||||
- make ci
|
||||
cache: pip
|
||||
jobs:
|
||||
include:
|
||||
- stage: test
|
||||
python: '2.7'
|
||||
- stage: test
|
||||
python: '3.5'
|
||||
- stage: test
|
||||
python: '3.6'
|
||||
- stage: test
|
||||
python: '3.7'
|
||||
- stage: test
|
||||
python: 'pypy3'
|
||||
dist: xenial
|
||||
- stage: test
|
||||
python: '3.8'
|
||||
- stage: coverage
|
||||
python: '3.6'
|
||||
script: codecov
|
||||
@@ -3,13 +3,14 @@ Requests was lovingly created by Kenneth Reitz.
|
||||
Keepers of the Crystals
|
||||
```````````````````````
|
||||
|
||||
- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_.
|
||||
- Nate Prewitt <nate.prewitt@gmail.com> `@nateprewitt <https://github.com/nateprewitt>`_.
|
||||
- Nate Prewitt `@nateprewitt <https://github.com/nateprewitt>`_.
|
||||
- Seth M. Larson `@sethmlarson <https://github.com/sethmlarson>`_.
|
||||
|
||||
Previous Keepers of Crystals
|
||||
````````````````````````````
|
||||
- Kenneth Reitz <me@kennethreitz.org> `@kennethreitz <https://github.com/kennethreitz>`_, reluctant Keeper of the Master Crystal.
|
||||
- Kenneth Reitz <me@kennethreitz.org> `@ken-reitz <https://github.com/ken-reitz>`_, reluctant Keeper of the Master Crystal.
|
||||
- Cory Benfield <cory@lukasa.co.uk> `@lukasa <https://github.com/lukasa>`_
|
||||
- Ian Cordasco <graffatcolmingov@gmail.com> `@sigmavirus24 <https://github.com/sigmavirus24>`_.
|
||||
|
||||
|
||||
Patches and Suggestions
|
||||
@@ -189,3 +190,5 @@ Patches and Suggestions
|
||||
- Antti Kaihola (`@akaihola <https://github.com/akaihola>`_)
|
||||
- "Dull Bananas" <dull.bananas0@gmail.com> (`@dullbananas <https://github.com/dullbananas>`_)
|
||||
- Alessio Izzo (`@aless10 <https://github.com/aless10>`_)
|
||||
- Sylvain Marié (`@smarie <https://github.com/smarie>`_)
|
||||
- Hod Bin Noon (`@hodbn <https://github.com/hodbn>`_)
|
||||
|
||||
147
HISTORY.md
147
HISTORY.md
@@ -4,9 +4,143 @@ Release History
|
||||
dev
|
||||
---
|
||||
|
||||
- \[Short description of non-trivial change.\]
|
||||
|
||||
2.27.0 (2022-01-03)
|
||||
-------------------
|
||||
|
||||
**Improvements**
|
||||
|
||||
- Officially added support for Python 3.10. (#5928)
|
||||
|
||||
- Added a `requests.exceptions.JSONDecodeError` to unify JSON exceptions between
|
||||
Python 2 and 3. This gets raised in the `response.json()` method, and is
|
||||
backwards compatible as it inherits from previously thrown exceptions.
|
||||
Can be caught from `requests.exceptions.RequestException` as well. (#5856)
|
||||
|
||||
- Improved error text for misnamed `InvalidSchema` and `MissingSchema`
|
||||
exceptions. This is a temporary fix until exceptions can be renamed
|
||||
(Schema->Scheme). (#6017)
|
||||
|
||||
- Improved proxy parsing for proxy URLs missing a scheme. This will address
|
||||
recent changes to `urlparse` in Python 3.9+. (#5917)
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- \[Short description of non-trivial change.\]
|
||||
- Fixed defect in `extract_zipped_paths` which could result in an infinite loop
|
||||
for some paths. (#5851)
|
||||
|
||||
- Fixed handling for `AttributeError` when calculating length of files obtained
|
||||
by `Tarfile.extractfile()`. (#5239)
|
||||
|
||||
- Fixed urllib3 exception leak, wrapping `urllib3.exceptions.InvalidHeader` with
|
||||
`requests.exceptions.InvalidHeader`. (#5914)
|
||||
|
||||
- Fixed bug where two Host headers were sent for chunked requests. (#5391)
|
||||
|
||||
- Fixed regression in Requests 2.26.0 where `Proxy-Authorization` was
|
||||
incorrectly stripped from all requests sent with `Session.send`. (#5924)
|
||||
|
||||
- Fixed performance regression in 2.26.0 for hosts with a large number of
|
||||
proxies available in the environment. (#5924)
|
||||
|
||||
- Fixed idna exception leak, wrapping `UnicodeError` with
|
||||
`requests.exceptions.InvalidURL` for URLs with a leading dot (.) in the
|
||||
domain. (#5414)
|
||||
|
||||
**Deprecations**
|
||||
|
||||
- Requests support for Python 2.7 and 3.6 will be ending in 2022. While we
|
||||
don't have exact dates, Requests 2.27.x is likely to be the last release
|
||||
series providing support.
|
||||
|
||||
2.26.0 (2021-07-13)
|
||||
-------------------
|
||||
|
||||
**Improvements**
|
||||
|
||||
- Requests now supports Brotli compression, if either the `brotli` or
|
||||
`brotlicffi` package is installed. (#5783)
|
||||
|
||||
- `Session.send` now correctly resolves proxy configurations from both
|
||||
the Session and Request. Behavior now matches `Session.request`. (#5681)
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Fixed a race condition in zip extraction when using Requests in parallel
|
||||
from zip archive. (#5707)
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- Instead of `chardet`, use the MIT-licensed `charset_normalizer` for Python3
|
||||
to remove license ambiguity for projects bundling requests. If `chardet`
|
||||
is already installed on your machine it will be used instead of `charset_normalizer`
|
||||
to keep backwards compatibility. (#5797)
|
||||
|
||||
You can also install `chardet` while installing requests by
|
||||
specifying `[use_chardet_on_py3]` extra as follows:
|
||||
|
||||
```shell
|
||||
pip install "requests[use_chardet_on_py3]"
|
||||
```
|
||||
|
||||
Python2 still depends upon the `chardet` module.
|
||||
|
||||
- Requests now supports `idna` 3.x on Python 3. `idna` 2.x will continue to
|
||||
be used on Python 2 installations. (#5711)
|
||||
|
||||
**Deprecations**
|
||||
|
||||
- The `requests[security]` extra has been converted to a no-op install.
|
||||
PyOpenSSL is no longer the recommended secure option for Requests. (#5867)
|
||||
|
||||
- Requests has officially dropped support for Python 3.5. (#5867)
|
||||
|
||||
2.25.1 (2020-12-16)
|
||||
-------------------
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
- Requests now treats `application/json` as `utf8` by default. Resolving
|
||||
inconsistencies between `r.text` and `r.json` output. (#5673)
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- Requests now supports chardet v4.x.
|
||||
|
||||
2.25.0 (2020-11-11)
|
||||
-------------------
|
||||
|
||||
**Improvements**
|
||||
|
||||
- Added support for NETRC environment variable. (#5643)
|
||||
|
||||
**Dependencies**
|
||||
|
||||
- Requests now supports urllib3 v1.26.
|
||||
|
||||
**Deprecations**
|
||||
|
||||
- Requests v2.25.x will be the last release series with support for Python 3.5.
|
||||
- The `requests[security]` extra is officially deprecated and will be removed
|
||||
in Requests v2.26.0.
|
||||
|
||||
2.24.0 (2020-06-17)
|
||||
-------------------
|
||||
|
||||
**Improvements**
|
||||
|
||||
- pyOpenSSL TLS implementation is now only used if Python
|
||||
either doesn't have an `ssl` module or doesn't support
|
||||
SNI. Previously pyOpenSSL was unconditionally used if available.
|
||||
This applies even if pyOpenSSL is installed via the
|
||||
`requests[security]` extra (#5443)
|
||||
|
||||
- Redirect resolution should now only occur when
|
||||
`allow_redirects` is True. (#5492)
|
||||
|
||||
- No longer perform unnecessary Content-Length calculation for
|
||||
requests that won't use it. (#5496)
|
||||
|
||||
2.23.0 (2020-02-19)
|
||||
-------------------
|
||||
@@ -22,7 +156,7 @@ dev
|
||||
**Dependencies**
|
||||
|
||||
- Pinning for `chardet` and `idna` now uses major version instead of minor.
|
||||
This hopefully reduces the need for releases everytime a dependency is updated.
|
||||
This hopefully reduces the need for releases every time a dependency is updated.
|
||||
|
||||
2.22.0 (2019-05-15)
|
||||
-------------------
|
||||
@@ -377,7 +511,7 @@ Or, even better:
|
||||
|
||||
- Fixed regression from 2.12.2 where non-string types were rejected in
|
||||
the basic auth parameters. While support for this behaviour has been
|
||||
readded, the behaviour is deprecated and will be removed in the
|
||||
re-added, the behaviour is deprecated and will be removed in the
|
||||
future.
|
||||
|
||||
2.12.3 (2016-12-01)
|
||||
@@ -1611,12 +1745,12 @@ This is not a backwards compatible change.
|
||||
- Automatic Authentication API Change
|
||||
- Smarter Query URL Parameterization
|
||||
- Allow file uploads and POST data together
|
||||
-
|
||||
-
|
||||
|
||||
New Authentication Manager System
|
||||
|
||||
: - Simpler Basic HTTP System
|
||||
- Supports all build-in urllib2 Auths
|
||||
- Supports all built-in urllib2 Auths
|
||||
- Allows for custom Auth Handlers
|
||||
|
||||
0.2.4 (2011-02-19)
|
||||
@@ -1630,7 +1764,7 @@ This is not a backwards compatible change.
|
||||
0.2.3 (2011-02-15)
|
||||
------------------
|
||||
|
||||
-
|
||||
-
|
||||
|
||||
New HTTPHandling Methods
|
||||
|
||||
@@ -1663,4 +1797,3 @@ This is not a backwards compatible change.
|
||||
|
||||
- Frustration
|
||||
- Conception
|
||||
|
||||
|
||||
182
LICENSE
182
LICENSE
@@ -1,13 +1,175 @@
|
||||
Copyright 2019 Kenneth Reitz
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
include README.md LICENSE NOTICE HISTORY.md pytest.ini requirements.txt Pipfile Pipfile.lock
|
||||
include README.md LICENSE NOTICE HISTORY.md pytest.ini requirements-dev.txt
|
||||
recursive-include tests *.py
|
||||
|
||||
16
Makefile
16
Makefile
@@ -1,21 +1,21 @@
|
||||
.PHONY: docs
|
||||
init:
|
||||
pip install pipenv --upgrade
|
||||
pipenv install --dev
|
||||
pip install -e .[socks]
|
||||
pip install -r requirements-dev.txt
|
||||
test:
|
||||
# This runs all of the tests, on both Python 2 and Python 3.
|
||||
detox
|
||||
tox -p
|
||||
ci:
|
||||
pipenv run py.test -n 8 --boxed --junitxml=report.xml
|
||||
pytest tests --junitxml=report.xml
|
||||
|
||||
test-readme:
|
||||
@pipenv run python setup.py check --restructuredtext --strict && ([ $$? -eq 0 ] && echo "README.rst and HISTORY.rst ok") || echo "Invalid markup in README.rst or HISTORY.rst!"
|
||||
python setup.py check --restructuredtext --strict && ([ $$? -eq 0 ] && echo "README.rst and HISTORY.rst ok") || echo "Invalid markup in README.rst or HISTORY.rst!"
|
||||
|
||||
flake8:
|
||||
pipenv run flake8 --ignore=E501,F401,E128,E402,E731,F821 requests
|
||||
flake8 --ignore=E501,F401,E128,E402,E731,F821 requests
|
||||
|
||||
coverage:
|
||||
pipenv run py.test --cov-config .coveragerc --verbose --cov-report term --cov-report xml --cov=requests tests
|
||||
pytest --cov-config .coveragerc --verbose --cov-report term --cov-report xml --cov=requests tests
|
||||
|
||||
publish:
|
||||
pip install 'twine>=1.5.0'
|
||||
@@ -25,4 +25,4 @@ publish:
|
||||
|
||||
docs:
|
||||
cd docs && make html
|
||||
@echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m"
|
||||
@echo "\033[95m\n\nBuild successful! View the docs homepage at docs/_build/html/index.html.\n\033[0m"
|
||||
|
||||
25
Pipfile
25
Pipfile
@@ -1,25 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple/"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[dev-packages]
|
||||
alabaster = "*"
|
||||
codecov = "*"
|
||||
docutils = "*"
|
||||
detox = "*"
|
||||
"flake8" = "*"
|
||||
httpbin = ">=0.7.0"
|
||||
more-itertools = "<6.0"
|
||||
pysocks = "*"
|
||||
pytest = ">=2.8.0,<=3.10.1"
|
||||
pytest-httpbin = ">=0.0.7,<1.0"
|
||||
pytest-mock = "*"
|
||||
pytest-cov = "*"
|
||||
pytest-xdist = "<=1.25"
|
||||
readme-renderer = "*"
|
||||
sphinx = "<=1.5.5"
|
||||
tox = "*"
|
||||
|
||||
[packages]
|
||||
"requests" = {path = ".", editable = true, extras = ["socks"]}
|
||||
739
Pipfile.lock
generated
739
Pipfile.lock
generated
@@ -1,739 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9c8d31d74dee008bc23d846267f23665288b0b1bee2525baca681d1061726701"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple/",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
|
||||
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
|
||||
],
|
||||
"version": "==2019.9.11"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"pysocks": {
|
||||
"hashes": [
|
||||
"sha256:15d38914b60dbcb231d276f64882a20435c049450160e953ca7d313d1405f16f",
|
||||
"sha256:32238918ac0f19e9fd870a8692ac9bd14f5e8752b3c62624cda5851424642210",
|
||||
"sha256:d9031ea45fdfacbe59a99273e9f0448ddb33c1580fe3831c1b09557c5718977c"
|
||||
],
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"requests": {
|
||||
"editable": true,
|
||||
"extras": [
|
||||
"socks"
|
||||
],
|
||||
"path": ".",
|
||||
"version": "==2.22.0"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:319cef72311e511d94be1bb478d202fde499935d0347a9e8f0d232dc3bce47c6",
|
||||
"sha256:8a8090dd02b145256534c205e624eb20161080428ffa14408f6f283c0d0c356e"
|
||||
],
|
||||
"version": "==1.25.4"
|
||||
},
|
||||
"win-inet-pton": {
|
||||
"hashes": [
|
||||
"sha256:dd03d942c0d3e2b1cf8bab511844546dfa5f74cb61b241699fa379ad707dea4f",
|
||||
"sha256:eaf0193cbe7152ac313598a0da7313fb479f769343c0c16c5308f64887dc885b"
|
||||
],
|
||||
"markers": "sys_platform == 'win32' and python_version == '2.7'",
|
||||
"version": "==1.1.0"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"alabaster": {
|
||||
"hashes": [
|
||||
"sha256:446438bdcca0e05bd45ea2de1668c1d9b032e1a9154c2c259092d77031ddd359",
|
||||
"sha256:a661d72d58e6ea8a57f7a86e37d86716863ee5e92788398526d58b26a4e4dc02"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.12"
|
||||
},
|
||||
"apipkg": {
|
||||
"hashes": [
|
||||
"sha256:37228cda29411948b422fae072f57e31d3396d2ee1c9783775980ee9c9990af6",
|
||||
"sha256:58587dd4dc3daefad0487f6d9ae32b4542b185e1c36db6993290e7c41ca2b47c"
|
||||
],
|
||||
"version": "==1.5"
|
||||
},
|
||||
"atomicwrites": {
|
||||
"hashes": [
|
||||
"sha256:03472c30eb2c5d1ba9227e4c2ca66ab8287fbfbbda3888aa93dc2e28fc6811b4",
|
||||
"sha256:75a9445bac02d8d058d5e1fe689654ba5a6556a1dfd8ce6ec55a0ed79866cfa6"
|
||||
],
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
|
||||
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
|
||||
],
|
||||
"version": "==19.1.0"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:af92e6106cb7c55286b25b38ad7695f8b4efb36a90ba483d7f7a6628c46158ab",
|
||||
"sha256:e86135ae101e31e2c8ec20a4e0c5220f4eed12487d5cf3f78be7e98d3a57fc28"
|
||||
],
|
||||
"version": "==2.7.0"
|
||||
},
|
||||
"bleach": {
|
||||
"hashes": [
|
||||
"sha256:213336e49e102af26d9cde77dd2d0397afabc5a6bf2fed985dc35b5d1e285a16",
|
||||
"sha256:3fdf7f77adcf649c9911387df51254b813185e32b2c6619f690b593a617e19fa"
|
||||
],
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"blinker": {
|
||||
"hashes": [
|
||||
"sha256:471aee25f3992bd325afa3772f1063dbdbbca947a041b8b89466dc00d606f8b6"
|
||||
],
|
||||
"version": "==1.4"
|
||||
},
|
||||
"brotlipy": {
|
||||
"hashes": [
|
||||
"sha256:07194f4768eb62a4f4ea76b6d0df6ade185e24ebd85877c351daa0a069f1111a",
|
||||
"sha256:091b299bf36dd6ef7a06570dbc98c0f80a504a56c5b797f31934d2ad01ae7d17",
|
||||
"sha256:09ec3e125d16749b31c74f021aba809541b3564e5359f8c265cbae442810b41a",
|
||||
"sha256:0be698678a114addcf87a4b9496c552c68a2c99bf93cf8e08f5738b392e82057",
|
||||
"sha256:0fa6088a9a87645d43d7e21e32b4a6bf8f7c3939015a50158c10972aa7f425b7",
|
||||
"sha256:1379347337dc3d20b2d61456d44ccce13e0625db2611c368023b4194d5e2477f",
|
||||
"sha256:1ea4e578241504b58f2456a6c69952c88866c794648bdc74baee74839da61d44",
|
||||
"sha256:2699945a0a992c04fc7dc7fa2f1d0575a2c8b4b769f2874a08e8eae46bef36ae",
|
||||
"sha256:2a80319ae13ea8dd60ecdc4f5ccf6da3ae64787765923256b62c598c5bba4121",
|
||||
"sha256:2e5c64522364a9ebcdf47c5744a5ddeb3f934742d31e61ebfbbc095460b47162",
|
||||
"sha256:36def0b859beaf21910157b4c33eb3b06d8ce459c942102f16988cca6ea164df",
|
||||
"sha256:3a3e56ced8b15fbbd363380344f70f3b438e0fd1fcf27b7526b6172ea950e867",
|
||||
"sha256:3c1d5e2cf945a46975bdb11a19257fa057b67591eb232f393d260e7246d9e571",
|
||||
"sha256:4e4638b49835d567d447a2cfacec109f9a777f219f071312268b351b6839436d",
|
||||
"sha256:50ca336374131cfad20612f26cc43c637ac0bfd2be3361495e99270883b52962",
|
||||
"sha256:5de6f7d010b7558f72f4b061a07395c5c3fd57f0285c5af7f126a677b976a868",
|
||||
"sha256:637847560d671657f993313ecc6c6c6666a936b7a925779fd044065c7bc035b9",
|
||||
"sha256:653faef61241bf8bf99d73ca7ec4baa63401ba7b2a2aa88958394869379d67c7",
|
||||
"sha256:786afc8c9bd67de8d31f46e408a3386331e126829114e4db034f91eacb05396d",
|
||||
"sha256:79aaf217072840f3e9a3b641cccc51f7fc23037496bd71e26211856b93f4b4cb",
|
||||
"sha256:7e31f7adcc5851ca06134705fcf3478210da45d35ad75ec181e1ce9ce345bb38",
|
||||
"sha256:8b39abc3256c978f575df5cd7893153277216474f303e26f0e43ba3d3969ef96",
|
||||
"sha256:9448227b0df082e574c45c983fa5cd4bda7bfb11ea6b59def0940c1647be0c3c",
|
||||
"sha256:96bc59ff9b5b5552843dc67999486a220e07a0522dddd3935da05dc194fa485c",
|
||||
"sha256:a07647886e24e2fb2d68ca8bf3ada398eb56fd8eac46c733d4d95c64d17f743b",
|
||||
"sha256:af65d2699cb9f13b26ec3ba09e75e80d31ff422c03675fcb36ee4dabe588fdc2",
|
||||
"sha256:b4c98b0d2c9c7020a524ca5bbff42027db1004c6571f8bc7b747f2b843128e7a",
|
||||
"sha256:c6cc0036b1304dd0073eec416cb2f6b9e37ac8296afd9e481cac3b1f07f9db25",
|
||||
"sha256:d2c1c724c4ac375feb2110f1af98ecdc0e5a8ea79d068efb5891f621a5b235cb",
|
||||
"sha256:dc6c5ee0df9732a44d08edab32f8a616b769cc5a4155a12d2d010d248eb3fb07",
|
||||
"sha256:fd1d1c64214af5d90014d82cee5d8141b13d44c92ada7a0c0ec0679c6f15a471"
|
||||
],
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"certifi": {
|
||||
"hashes": [
|
||||
"sha256:e4f3620cfea4f83eedc95b24abd9cd56f3c4b146dd0177e83a21b4eb49e21e50",
|
||||
"sha256:fd7c7c74727ddcf00e9acd26bba8da604ffec95bf1c2144e67aff7a8b50e6cef"
|
||||
],
|
||||
"version": "==2019.9.11"
|
||||
},
|
||||
"cffi": {
|
||||
"hashes": [
|
||||
"sha256:041c81822e9f84b1d9c401182e174996f0bae9991f33725d059b771744290774",
|
||||
"sha256:046ef9a22f5d3eed06334d01b1e836977eeef500d9b78e9ef693f9380ad0b83d",
|
||||
"sha256:066bc4c7895c91812eff46f4b1c285220947d4aa46fa0a2651ff85f2afae9c90",
|
||||
"sha256:066c7ff148ae33040c01058662d6752fd73fbc8e64787229ea8498c7d7f4041b",
|
||||
"sha256:2444d0c61f03dcd26dbf7600cf64354376ee579acad77aef459e34efcb438c63",
|
||||
"sha256:300832850b8f7967e278870c5d51e3819b9aad8f0a2c8dbe39ab11f119237f45",
|
||||
"sha256:34c77afe85b6b9e967bd8154e3855e847b70ca42043db6ad17f26899a3df1b25",
|
||||
"sha256:46de5fa00f7ac09f020729148ff632819649b3e05a007d286242c4882f7b1dc3",
|
||||
"sha256:4aa8ee7ba27c472d429b980c51e714a24f47ca296d53f4d7868075b175866f4b",
|
||||
"sha256:4d0004eb4351e35ed950c14c11e734182591465a33e960a4ab5e8d4f04d72647",
|
||||
"sha256:4e3d3f31a1e202b0f5a35ba3bc4eb41e2fc2b11c1eff38b362de710bcffb5016",
|
||||
"sha256:50bec6d35e6b1aaeb17f7c4e2b9374ebf95a8975d57863546fa83e8d31bdb8c4",
|
||||
"sha256:55cad9a6df1e2a1d62063f79d0881a414a906a6962bc160ac968cc03ed3efcfb",
|
||||
"sha256:5662ad4e4e84f1eaa8efce5da695c5d2e229c563f9d5ce5b0113f71321bcf753",
|
||||
"sha256:59b4dc008f98fc6ee2bb4fd7fc786a8d70000d058c2bbe2698275bc53a8d3fa7",
|
||||
"sha256:73e1ffefe05e4ccd7bcea61af76f36077b914f92b76f95ccf00b0c1b9186f3f9",
|
||||
"sha256:a1f0fd46eba2d71ce1589f7e50a9e2ffaeb739fb2c11e8192aa2b45d5f6cc41f",
|
||||
"sha256:a2e85dc204556657661051ff4bab75a84e968669765c8a2cd425918699c3d0e8",
|
||||
"sha256:a5457d47dfff24882a21492e5815f891c0ca35fefae8aa742c6c263dac16ef1f",
|
||||
"sha256:a8dccd61d52a8dae4a825cdbb7735da530179fea472903eb871a5513b5abbfdc",
|
||||
"sha256:ae61af521ed676cf16ae94f30fe202781a38d7178b6b4ab622e4eec8cefaff42",
|
||||
"sha256:b012a5edb48288f77a63dba0840c92d0504aa215612da4541b7b42d849bc83a3",
|
||||
"sha256:d2c5cfa536227f57f97c92ac30c8109688ace8fa4ac086d19d0af47d134e2909",
|
||||
"sha256:d42b5796e20aacc9d15e66befb7a345454eef794fdb0737d1af593447c6c8f45",
|
||||
"sha256:dee54f5d30d775f525894d67b1495625dd9322945e7fee00731952e0368ff42d",
|
||||
"sha256:e070535507bd6aa07124258171be2ee8dfc19119c28ca94c9dfb7efd23564512",
|
||||
"sha256:e1ff2748c84d97b065cc95429814cdba39bcbd77c9c85c89344b317dc0d9cbff",
|
||||
"sha256:ed851c75d1e0e043cbf5ca9a8e1b13c4c90f3fbd863dacb01c0808e2b5204201"
|
||||
],
|
||||
"version": "==1.12.3"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"click": {
|
||||
"hashes": [
|
||||
"sha256:2335065e6395b9e67ca716de5f7526736bfa6ceead690adf616d925bdc622b13",
|
||||
"sha256:5b94b49521f6456670fdb30cd82a4eca9412788a93fa6dd6df72c94d5a8ff2d7"
|
||||
],
|
||||
"version": "==7.0"
|
||||
},
|
||||
"codecov": {
|
||||
"hashes": [
|
||||
"sha256:8ed8b7c6791010d359baed66f84f061bba5bd41174bf324c31311e8737602788",
|
||||
"sha256:ae00d68e18d8a20e9c3288ba3875ae03db3a8e892115bf9b83ef20507732bed4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.15"
|
||||
},
|
||||
"configparser": {
|
||||
"hashes": [
|
||||
"sha256:254c1d9c79f60c45dfde850850883d5aaa7f19a23f13561243a050d5a7c3fe4c",
|
||||
"sha256:c7d282687a5308319bf3d2e7706e575c635b0a470342641c93bea0ea3b5331df"
|
||||
],
|
||||
"markers": "python_version == '2.7'",
|
||||
"version": "==4.0.2"
|
||||
},
|
||||
"contextlib2": {
|
||||
"hashes": [
|
||||
"sha256:509f9419ee91cdd00ba34443217d5ca51f5a364a404e1dce9e8979cea969ca48",
|
||||
"sha256:f5260a6e679d2ff42ec91ec5252f4eeffdcf21053db9113bd0a8e4d953769c00"
|
||||
],
|
||||
"markers": "python_version < '3'",
|
||||
"version": "==0.5.5"
|
||||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:08907593569fe59baca0bf152c43f3863201efb6113ecb38ce7e97ce339805a6",
|
||||
"sha256:0be0f1ed45fc0c185cfd4ecc19a1d6532d72f86a2bac9de7e24541febad72650",
|
||||
"sha256:141f08ed3c4b1847015e2cd62ec06d35e67a3ac185c26f7635f4406b90afa9c5",
|
||||
"sha256:19e4df788a0581238e9390c85a7a09af39c7b539b29f25c89209e6c3e371270d",
|
||||
"sha256:23cc09ed395b03424d1ae30dcc292615c1372bfba7141eb85e11e50efaa6b351",
|
||||
"sha256:245388cda02af78276b479f299bbf3783ef0a6a6273037d7c60dc73b8d8d7755",
|
||||
"sha256:331cb5115673a20fb131dadd22f5bcaf7677ef758741312bee4937d71a14b2ef",
|
||||
"sha256:386e2e4090f0bc5df274e720105c342263423e77ee8826002dcffe0c9533dbca",
|
||||
"sha256:3a794ce50daee01c74a494919d5ebdc23d58873747fa0e288318728533a3e1ca",
|
||||
"sha256:60851187677b24c6085248f0a0b9b98d49cba7ecc7ec60ba6b9d2e5574ac1ee9",
|
||||
"sha256:63a9a5fc43b58735f65ed63d2cf43508f462dc49857da70b8980ad78d41d52fc",
|
||||
"sha256:6b62544bb68106e3f00b21c8930e83e584fdca005d4fffd29bb39fb3ffa03cb5",
|
||||
"sha256:6ba744056423ef8d450cf627289166da65903885272055fb4b5e113137cfa14f",
|
||||
"sha256:7494b0b0274c5072bddbfd5b4a6c6f18fbbe1ab1d22a41e99cd2d00c8f96ecfe",
|
||||
"sha256:826f32b9547c8091679ff292a82aca9c7b9650f9fda3e2ca6bf2ac905b7ce888",
|
||||
"sha256:93715dffbcd0678057f947f496484e906bf9509f5c1c38fc9ba3922893cda5f5",
|
||||
"sha256:9a334d6c83dfeadae576b4d633a71620d40d1c379129d587faa42ee3e2a85cce",
|
||||
"sha256:af7ed8a8aa6957aac47b4268631fa1df984643f07ef00acd374e456364b373f5",
|
||||
"sha256:bf0a7aed7f5521c7ca67febd57db473af4762b9622254291fbcbb8cd0ba5e33e",
|
||||
"sha256:bf1ef9eb901113a9805287e090452c05547578eaab1b62e4ad456fcc049a9b7e",
|
||||
"sha256:c0afd27bc0e307a1ffc04ca5ec010a290e49e3afbe841c5cafc5c5a80ecd81c9",
|
||||
"sha256:dd579709a87092c6dbee09d1b7cfa81831040705ffa12a1b248935274aee0437",
|
||||
"sha256:df6712284b2e44a065097846488f66840445eb987eb81b3cc6e4149e7b6982e1",
|
||||
"sha256:e07d9f1a23e9e93ab5c62902833bf3e4b1f65502927379148b6622686223125c",
|
||||
"sha256:e2ede7c1d45e65e209d6093b762e98e8318ddeff95317d07a27a2140b80cfd24",
|
||||
"sha256:e4ef9c164eb55123c62411f5936b5c2e521b12356037b6e1c2617cef45523d47",
|
||||
"sha256:eca2b7343524e7ba246cab8ff00cab47a2d6d54ada3b02772e908a45675722e2",
|
||||
"sha256:eee64c616adeff7db37cc37da4180a3a5b6177f5c46b187894e633f088fb5b28",
|
||||
"sha256:ef824cad1f980d27f26166f86856efe11eff9912c4fed97d3804820d43fa550c",
|
||||
"sha256:efc89291bd5a08855829a3c522df16d856455297cf35ae827a37edac45f466a7",
|
||||
"sha256:fa964bae817babece5aa2e8c1af841bebb6d0b9add8e637548809d040443fee0",
|
||||
"sha256:ff37757e068ae606659c28c3bd0d923f9d29a85de79bf25b2b34b148473b5025"
|
||||
],
|
||||
"version": "==4.5.4"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:86156361c50488b84a3f148056ea716ca587df2f0de1d34750d35c21312725de",
|
||||
"sha256:f069f3a01830ca754ba5258fde2278454a0b5b79e0d7f5c13b3b97e57d4acff6"
|
||||
],
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"detox": {
|
||||
"hashes": [
|
||||
"sha256:e650f95f0c7f5858578014b3b193e5dac76c89285c1bbe4bae598fd641bf9cd3",
|
||||
"sha256:fcad009e2d20ce61176dc826a2c1562bd712fe53953ca603b455171cf819080f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.19"
|
||||
},
|
||||
"dnspython": {
|
||||
"hashes": [
|
||||
"sha256:36c5e8e38d4369a08b6780b7f27d790a292b2b08eea01607865bf0936c558e01",
|
||||
"sha256:f69c21288a962f4da86e56c4905b49d11aba7938d3d740e80d9e366ee4f1632d"
|
||||
],
|
||||
"version": "==1.16.0"
|
||||
},
|
||||
"docutils": {
|
||||
"hashes": [
|
||||
"sha256:6c4f696463b79f1fb8ba0c594b63840ebd41f059e92b31957c46b74a4599b6d0",
|
||||
"sha256:9e4d7ecfc600058e07ba661411a2b7de2fd0fafa17d1a7f7361cd47b1175c827",
|
||||
"sha256:a2aeea129088da402665e92e0b25b04b073c04b2dce4ab65caaa38b7ce2e1a99"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.15.2"
|
||||
},
|
||||
"entrypoints": {
|
||||
"hashes": [
|
||||
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"enum34": {
|
||||
"hashes": [
|
||||
"sha256:2d81cbbe0e73112bdfe6ef8576f2238f2ba27dd0d55752a776c41d38b7da2850",
|
||||
"sha256:644837f692e5f550741432dd3f223bbb9852018674981b1664e5dc339387588a",
|
||||
"sha256:6bd0f6ad48ec2aa117d3d141940d484deccda84d4fcd884f5c3d93c23ecd8c79",
|
||||
"sha256:8ad8c4783bf61ded74527bffb48ed9b54166685e4230386a9ed9b1279e2df5b1"
|
||||
],
|
||||
"markers": "python_version == '2.7' or python_version == '3.3'",
|
||||
"version": "==1.1.6"
|
||||
},
|
||||
"eventlet": {
|
||||
"hashes": [
|
||||
"sha256:658b1cd80937adc1a4860de2841e0528f64e2ca672885c4e00fc0e2217bde6b1",
|
||||
"sha256:6c9c625af48424c4680d89314dbe45a76cc990cf002489f9469ff214b044ffc1"
|
||||
],
|
||||
"version": "==0.25.1"
|
||||
},
|
||||
"execnet": {
|
||||
"hashes": [
|
||||
"sha256:cacb9df31c9680ec5f95553976c4da484d407e85e41c83cb812aa014f0eddc50",
|
||||
"sha256:d4efd397930c46415f62f8a31388d6be4f27a91d7550eb79bc64a756e0056547"
|
||||
],
|
||||
"version": "==1.7.1"
|
||||
},
|
||||
"filelock": {
|
||||
"hashes": [
|
||||
"sha256:18d82244ee114f543149c66a6e0c14e9c4f8a1044b5cdaadd0f82159d6a6ff59",
|
||||
"sha256:929b7d63ec5b7d6b71b0fa5ac14e030b3f70b75747cef1b10da9b879fef15836"
|
||||
],
|
||||
"version": "==3.0.12"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:19241c1cbc971b9962473e4438a2ca19749a7dd002dd1a946eaba171b4114548",
|
||||
"sha256:8e9dfa3cecb2400b3738a42c54c3043e821682b9c840b0448c0503f781130696"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7.8"
|
||||
},
|
||||
"flask": {
|
||||
"hashes": [
|
||||
"sha256:13f9f196f330c7c2c5d7a5cf91af894110ca0215ac051b5844701f2bfd934d52",
|
||||
"sha256:45eb5a6fd193d6cf7e0cf5d8a5b31f83d5faae0293695626f539a823e93b13f6"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"funcsigs": {
|
||||
"hashes": [
|
||||
"sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca",
|
||||
"sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"
|
||||
],
|
||||
"markers": "python_version < '3.0'",
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"functools32": {
|
||||
"hashes": [
|
||||
"sha256:89d824aa6c358c421a234d7f9ee0bd75933a67c29588ce50aaa3acdf4d403fa0",
|
||||
"sha256:f6253dfbe0538ad2e387bd8fdfd9293c925d63553f5813c4e587745416501e6d"
|
||||
],
|
||||
"markers": "python_version < '3.2'",
|
||||
"version": "==3.2.3.post2"
|
||||
},
|
||||
"greenlet": {
|
||||
"hashes": [
|
||||
"sha256:000546ad01e6389e98626c1367be58efa613fa82a1be98b0c6fc24b563acc6d0",
|
||||
"sha256:0d48200bc50cbf498716712129eef819b1729339e34c3ae71656964dac907c28",
|
||||
"sha256:23d12eacffa9d0f290c0fe0c4e81ba6d5f3a5b7ac3c30a5eaf0126bf4deda5c8",
|
||||
"sha256:37c9ba82bd82eb6a23c2e5acc03055c0e45697253b2393c9a50cef76a3985304",
|
||||
"sha256:51503524dd6f152ab4ad1fbd168fc6c30b5795e8c70be4410a64940b3abb55c0",
|
||||
"sha256:8041e2de00e745c0e05a502d6e6db310db7faa7c979b3a5877123548a4c0b214",
|
||||
"sha256:81fcd96a275209ef117e9ec91f75c731fa18dcfd9ffaa1c0adbdaa3616a86043",
|
||||
"sha256:853da4f9563d982e4121fed8c92eea1a4594a2299037b3034c3c898cb8e933d6",
|
||||
"sha256:8b4572c334593d449113f9dc8d19b93b7b271bdbe90ba7509eb178923327b625",
|
||||
"sha256:9416443e219356e3c31f1f918a91badf2e37acf297e2fa13d24d1cc2380f8fbc",
|
||||
"sha256:9854f612e1b59ec66804931df5add3b2d5ef0067748ea29dc60f0efdcda9a638",
|
||||
"sha256:99a26afdb82ea83a265137a398f570402aa1f2b5dfb4ac3300c026931817b163",
|
||||
"sha256:a19bf883b3384957e4a4a13e6bd1ae3d85ae87f4beb5957e35b0be287f12f4e4",
|
||||
"sha256:a9f145660588187ff835c55a7d2ddf6abfc570c2651c276d3d4be8a2766db490",
|
||||
"sha256:ac57fcdcfb0b73bb3203b58a14501abb7e5ff9ea5e2edfa06bb03035f0cff248",
|
||||
"sha256:bcb530089ff24f6458a81ac3fa699e8c00194208a724b644ecc68422e1111939",
|
||||
"sha256:beeabe25c3b704f7d56b573f7d2ff88fc99f0138e43480cecdfcaa3b87fe4f87",
|
||||
"sha256:d634a7ea1fc3380ff96f9e44d8d22f38418c1c381d5fac680b272d7d90883720",
|
||||
"sha256:d97b0661e1aead761f0ded3b769044bb00ed5d33e1ec865e891a8b128bf7c656"
|
||||
],
|
||||
"version": "==0.4.15"
|
||||
},
|
||||
"httpbin": {
|
||||
"hashes": [
|
||||
"sha256:7a04b5904c80b7aa04dd0a6af6520d68ce17a5db175e66a64b971f8e93d73a26",
|
||||
"sha256:cbb37790c91575f4f15757f42ad41d9f729eb227d5edbe89e4ec175486db8dfa"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"imagesize": {
|
||||
"hashes": [
|
||||
"sha256:3f349de3eb99145973fefb7dbe38554414e5c30abd0c8e4b970a7c9d09f3a1d8",
|
||||
"sha256:f3832918bc3c66617f92e35f5d70729187676313caa60c187eb0f28b8fe5e3b5"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"importlib-metadata": {
|
||||
"hashes": [
|
||||
"sha256:aa18d7378b00b40847790e7c27e11673d7fed219354109d0e7b9e5b25dc3ad26",
|
||||
"sha256:d5f18a79777f3aa179c145737780282e27b508fc8fd688cb17c7a813e8bd39af"
|
||||
],
|
||||
"markers": "python_version < '3.8'",
|
||||
"version": "==0.23"
|
||||
},
|
||||
"itsdangerous": {
|
||||
"hashes": [
|
||||
"sha256:321b033d07f2a4136d3ec762eac9f16a10ccd60f53c0c91af90217ace7ba1f19",
|
||||
"sha256:b12271b2047cb23eeb98c8b5622e2e5c5e9abd9784a153e9d8ef9cb4dd09d749"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"jinja2": {
|
||||
"hashes": [
|
||||
"sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013",
|
||||
"sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"
|
||||
],
|
||||
"version": "==2.10.1"
|
||||
},
|
||||
"markupsafe": {
|
||||
"hashes": [
|
||||
"sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473",
|
||||
"sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161",
|
||||
"sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235",
|
||||
"sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5",
|
||||
"sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff",
|
||||
"sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b",
|
||||
"sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1",
|
||||
"sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e",
|
||||
"sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183",
|
||||
"sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66",
|
||||
"sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1",
|
||||
"sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1",
|
||||
"sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e",
|
||||
"sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b",
|
||||
"sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905",
|
||||
"sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735",
|
||||
"sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d",
|
||||
"sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e",
|
||||
"sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d",
|
||||
"sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c",
|
||||
"sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21",
|
||||
"sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2",
|
||||
"sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5",
|
||||
"sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b",
|
||||
"sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6",
|
||||
"sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f",
|
||||
"sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f",
|
||||
"sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"
|
||||
],
|
||||
"version": "==1.1.1"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"mock": {
|
||||
"hashes": [
|
||||
"sha256:83657d894c90d5681d62155c82bda9c1187827525880eda8ff5df4ec813437c3",
|
||||
"sha256:d157e52d4e5b938c550f39eb2fd15610db062441a9c2747d3dbfa9298211d0f8"
|
||||
],
|
||||
"markers": "python_version < '3.0'",
|
||||
"version": "==3.0.5"
|
||||
},
|
||||
"monotonic": {
|
||||
"hashes": [
|
||||
"sha256:23953d55076df038541e648a53676fb24980f7a1be290cdda21300b3bc21dfb0",
|
||||
"sha256:552a91f381532e33cbd07c6a2655a21908088962bb8fa7239ecbcc6ad1140cc7"
|
||||
],
|
||||
"version": "==1.5"
|
||||
},
|
||||
"more-itertools": {
|
||||
"hashes": [
|
||||
"sha256:38a936c0a6d98a38bcc2d03fdaaedaba9f412879461dd2ceff8d37564d6522e4",
|
||||
"sha256:c0a5785b1109a6bd7fac76d6837fd1feca158e54e521ccd2ae8bfe393cc9d4fc",
|
||||
"sha256:fe7a7cae1ccb57d33952113ff4fa1bc5f879963600ed74918f1236e212ee50b9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.0.0"
|
||||
},
|
||||
"pathlib2": {
|
||||
"hashes": [
|
||||
"sha256:2156525d6576d21c4dcaddfa427fae887ef89a7a9de5cbfe0728b3aafa78427e",
|
||||
"sha256:446014523bb9be5c28128c4d2a10ad6bb60769e78bd85658fe44a450674e0ef8"
|
||||
],
|
||||
"markers": "python_version < '3.6'",
|
||||
"version": "==2.3.4"
|
||||
},
|
||||
"pluggy": {
|
||||
"hashes": [
|
||||
"sha256:0db4b7601aae1d35b4a033282da476845aa19185c1e6964b25cf324b5e4ec3e6",
|
||||
"sha256:fa5fa1622fa6dd5c030e9cad086fa19ef6a0cf6d7a2d12318e10cb49d6d68f34"
|
||||
],
|
||||
"version": "==0.13.0"
|
||||
},
|
||||
"py": {
|
||||
"hashes": [
|
||||
"sha256:64f65755aee5b381cea27766a3a147c3f15b9b6b9ac88676de66ba2ae36793fa",
|
||||
"sha256:dc639b046a6e2cff5bbe40194ad65936d6ba360b52b3c3fe1d08a82dd50b5e53"
|
||||
],
|
||||
"version": "==1.8.0"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:95a2219d12372f05704562a14ec30bc76b05a5b297b21a5dfe3f6fac3491ae56",
|
||||
"sha256:e40a936c9a450ad81df37f549d676d127b1b66000a6c500caa2b085bc0ca976c"
|
||||
],
|
||||
"version": "==2.5.0"
|
||||
},
|
||||
"pycparser": {
|
||||
"hashes": [
|
||||
"sha256:a988718abfad80b6b157acce7bf130a30876d27603738ac39f140993246b25b3"
|
||||
],
|
||||
"version": "==2.19"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
},
|
||||
"pygments": {
|
||||
"hashes": [
|
||||
"sha256:71e430bc85c88a430f000ac1d9b331d2407f681d6f6aec95e8bcfbc3df5b0127",
|
||||
"sha256:881c4c157e45f30af185c1ffe8d549d48ac9127433f2c380c24b84572ad66297"
|
||||
],
|
||||
"version": "==2.4.2"
|
||||
},
|
||||
"pysocks": {
|
||||
"hashes": [
|
||||
"sha256:15d38914b60dbcb231d276f64882a20435c049450160e953ca7d313d1405f16f",
|
||||
"sha256:32238918ac0f19e9fd870a8692ac9bd14f5e8752b3c62624cda5851424642210",
|
||||
"sha256:d9031ea45fdfacbe59a99273e9f0448ddb33c1580fe3831c1b09557c5718977c"
|
||||
],
|
||||
"version": "==1.7.0"
|
||||
},
|
||||
"pytest": {
|
||||
"hashes": [
|
||||
"sha256:3f193df1cfe1d1609d4c583838bea3d532b18d6160fd3f55c9447fdca30848ec",
|
||||
"sha256:e246cf173c01169b9617fc07264b7b1316e78d7a650055235d6d897bc80d9660"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.10.1"
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
"sha256:2b097cde81a302e1047331b48cadacf23577e431b61e9c6f49a1170bbe3d3da6",
|
||||
"sha256:e00ea4fdde970725482f1f35630d12f074e121a23801aabf2ae154ec6bdd343a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.7.1"
|
||||
},
|
||||
"pytest-forked": {
|
||||
"hashes": [
|
||||
"sha256:5fe33fbd07d7b1302c95310803a5e5726a4ff7f19d5a542b7ce57c76fed8135f",
|
||||
"sha256:d352aaced2ebd54d42a65825722cb433004b4446ab5d2044851d9cc7a00c9e38"
|
||||
],
|
||||
"version": "==1.0.2"
|
||||
},
|
||||
"pytest-httpbin": {
|
||||
"hashes": [
|
||||
"sha256:8cd57e27418a7d7d205fcc9802eea246ed06170e3065abfa76c6d9b40553592c",
|
||||
"sha256:d3919c5df0b644454129c0066a8ae62db40ac54bacb4cfd89d8cfa58615a4b42"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.3.0"
|
||||
},
|
||||
"pytest-mock": {
|
||||
"hashes": [
|
||||
"sha256:43ce4e9dd5074993e7c021bb1c22cbb5363e612a2b5a76bc6d956775b10758b7",
|
||||
"sha256:5bf5771b1db93beac965a7347dc81c675ec4090cb841e49d9d34637a25c30568"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.10.4"
|
||||
},
|
||||
"pytest-xdist": {
|
||||
"hashes": [
|
||||
"sha256:96f893094c89fddeaff3f4783f4807f7aeb138be1a0d87a8805057b6af1201b5",
|
||||
"sha256:aab1402f2b063df48bf044b042707610f8fcc4c49d0eb9c10e79e30b3f26074f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.25.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:26c0b32e437e54a18161324a2fca3c4b9846b74a8dccddd843113109e1116b32",
|
||||
"sha256:c894d57500a4cd2d5c71114aaab77dbab5eabd9022308ce5ac9bb93a60a6f0c7"
|
||||
],
|
||||
"version": "==2019.2"
|
||||
},
|
||||
"raven": {
|
||||
"extras": [
|
||||
"flask"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:3fa6de6efa2493a7c827472e984ce9b020797d0da16f1db67197bcc23c8fae54",
|
||||
"sha256:44a13f87670836e153951af9a3c80405d36b43097db869a36e92809673692ce4"
|
||||
],
|
||||
"version": "==6.10.0"
|
||||
},
|
||||
"readme-renderer": {
|
||||
"hashes": [
|
||||
"sha256:bb16f55b259f27f75f640acf5e00cf897845a8b3e4731b5c1a436e4b8529202f",
|
||||
"sha256:c8532b79afc0375a85f10433eca157d6b50f7d6990f337fa498c96cd4bfc203d"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==24.0"
|
||||
},
|
||||
"requests": {
|
||||
"editable": true,
|
||||
"extras": [
|
||||
"socks"
|
||||
],
|
||||
"path": ".",
|
||||
"version": "==2.22.0"
|
||||
},
|
||||
"scandir": {
|
||||
"hashes": [
|
||||
"sha256:2586c94e907d99617887daed6c1d102b5ca28f1085f90446554abf1faf73123e",
|
||||
"sha256:2ae41f43797ca0c11591c0c35f2f5875fa99f8797cb1a1fd440497ec0ae4b022",
|
||||
"sha256:2b8e3888b11abb2217a32af0766bc06b65cc4a928d8727828ee68af5a967fa6f",
|
||||
"sha256:2c712840c2e2ee8dfaf36034080108d30060d759c7b73a01a52251cc8989f11f",
|
||||
"sha256:4d4631f6062e658e9007ab3149a9b914f3548cb38bfb021c64f39a025ce578ae",
|
||||
"sha256:67f15b6f83e6507fdc6fca22fedf6ef8b334b399ca27c6b568cbfaa82a364173",
|
||||
"sha256:7d2d7a06a252764061a020407b997dd036f7bd6a175a5ba2b345f0a357f0b3f4",
|
||||
"sha256:8c5922863e44ffc00c5c693190648daa6d15e7c1207ed02d6f46a8dcc2869d32",
|
||||
"sha256:92c85ac42f41ffdc35b6da57ed991575bdbe69db895507af88b9f499b701c188",
|
||||
"sha256:b24086f2375c4a094a6b51e78b4cf7ca16c721dcee2eddd7aa6494b42d6d519d",
|
||||
"sha256:cb925555f43060a1745d0a321cca94bcea927c50114b623d73179189a4e100ac"
|
||||
],
|
||||
"markers": "python_version < '3.5'",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:3350809f0555b11f552448330d0b52d5f24c91a322ea4a15ef22629740f3761c",
|
||||
"sha256:d16a0141ec1a18405cd4ce8b4613101da75da0e9a7aec5bdd4fa804d0e0eba73"
|
||||
],
|
||||
"version": "==1.12.0"
|
||||
},
|
||||
"snowballstemmer": {
|
||||
"hashes": [
|
||||
"sha256:713e53b79cbcf97bc5245a06080a33d54a77e7cce2f789c835a143bcdb5c033e"
|
||||
],
|
||||
"version": "==1.9.1"
|
||||
},
|
||||
"sphinx": {
|
||||
"hashes": [
|
||||
"sha256:11f271e7a9398385ed730e90f0bb41dc3815294bdcd395b46ed2d033bc2e7d87",
|
||||
"sha256:4064ea6c56feeb268838cb8fbbee507d0c3d5d92fa63a7df935a916b52c9e2f5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.5.5"
|
||||
},
|
||||
"toml": {
|
||||
"hashes": [
|
||||
"sha256:229f81c57791a41d65e399fc06bf0848bab550a9dfd5ed66df18ce5f05e73d5c",
|
||||
"sha256:235682dd292d5899d361a811df37e04a8828a5b1da3115886b73cf81ebc9100e",
|
||||
"sha256:f1db651f9657708513243e61e6cc67d101a39bad662eaa9b5546f789338e07a3"
|
||||
],
|
||||
"version": "==0.10.0"
|
||||
},
|
||||
"tox": {
|
||||
"hashes": [
|
||||
"sha256:2a8d8a63660563e41e64e3b5b677e81ce1ffa5e2a93c2c565d3768c287445800",
|
||||
"sha256:edfca7809925f49bdc110d0a2d9966bbf35a0c25637216d9586e7a5c5de17bfb"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.6.1"
|
||||
},
|
||||
"typing": {
|
||||
"hashes": [
|
||||
"sha256:91dfe6f3f706ee8cc32d38edbbf304e9b7583fb37108fef38229617f8b3eba23",
|
||||
"sha256:c8cabb5ab8945cd2f54917be357d134db9cc1eb039e59d1606dc1e60cb1d9d36",
|
||||
"sha256:f38d83c5a7a7086543a0f649564d661859c5146a85775ab90c0d2f93ffaa9714"
|
||||
],
|
||||
"markers": "python_version < '3.5'",
|
||||
"version": "==3.7.4.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:319cef72311e511d94be1bb478d202fde499935d0347a9e8f0d232dc3bce47c6",
|
||||
"sha256:8a8090dd02b145256534c205e624eb20161080428ffa14408f6f283c0d0c356e"
|
||||
],
|
||||
"version": "==1.25.4"
|
||||
},
|
||||
"virtualenv": {
|
||||
"hashes": [
|
||||
"sha256:680af46846662bb38c5504b78bad9ed9e4f3ba2d54f54ba42494fdf94337fe30",
|
||||
"sha256:f78d81b62d3147396ac33fc9d77579ddc42cc2a98dd9ea38886f616b33bc7fb2"
|
||||
],
|
||||
"version": "==16.7.5"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
"sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78",
|
||||
"sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"
|
||||
],
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"werkzeug": {
|
||||
"hashes": [
|
||||
"sha256:7280924747b5733b246fe23972186c6b348f9ae29724135a6dfc1e53cea433e7",
|
||||
"sha256:e5f4a1f98b52b18a93da705a7458e55afb26f32bff83ff5d19189f92462d65c4"
|
||||
],
|
||||
"version": "==0.16.0"
|
||||
},
|
||||
"zipp": {
|
||||
"hashes": [
|
||||
"sha256:3718b1cbcd963c7d4c5511a8240812904164b7f381b647143a89d3b98f9bcd8e",
|
||||
"sha256:f06903e9f1f43b12d371004b4ac7b06ab39a44adc747266928ae6debfa7b3335"
|
||||
],
|
||||
"version": "==0.6.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
140
README.md
140
README.md
@@ -1,36 +1,10 @@
|
||||
# Requests
|
||||
|
||||
**Requests** is a simple, yet elegant, HTTP library.
|
||||
|
||||
<span align="center">
|
||||
|
||||
<pre>
|
||||
<a href="https://requests.readthedocs.io/"><img src="https://raw.githubusercontent.com/psf/requests/master/ext/requests-logo.png" align="center" /></a>
|
||||
|
||||
<div align="left">
|
||||
<p></p>
|
||||
<code> Python 3.7.4 (default, Sep 7 2019, 18:27:02)</code>
|
||||
<code> >>> <strong>import requests</strong></code>
|
||||
<code> >>> r = requests.get('https://api.github.com/repos/psf/requests')</code>
|
||||
<code> >>> r.json()["description"]</code>
|
||||
<code> 'A simple, yet elegant HTTP library.'</code>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
This software has been designed for you, with much joy,
|
||||
by <a href="https://kennethreitz.org/">Kenneth Reitz</a> & is protected by The <a href="https://www.python.org/psf/">Python Software Foundation</a>.
|
||||
</p>
|
||||
</pre>
|
||||
|
||||
</span>
|
||||
|
||||
<p> </p><p> </p>
|
||||
|
||||
<p align="center"><strong>Requests</strong> is an elegant and simple HTTP library for Python, built with ♥.</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
```pycon
|
||||
```python
|
||||
>>> import requests
|
||||
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
|
||||
>>> r = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
|
||||
>>> r.status_code
|
||||
200
|
||||
>>> r.headers['content-type']
|
||||
@@ -38,89 +12,67 @@ by <a href="https://kennethreitz.org/">Kenneth Reitz</a> & is protected by The <
|
||||
>>> r.encoding
|
||||
'utf-8'
|
||||
>>> r.text
|
||||
u'{"type":"User"...'
|
||||
'{"authenticated": true, ...'
|
||||
>>> r.json()
|
||||
{u'disk_usage': 368627, u'private_gists': 484, ...}
|
||||
{'authenticated': True, ...}
|
||||
```
|
||||
|
||||
|
||||
|
||||
---------------------------------------------------------------------
|
||||
|
||||
<p> </p>
|
||||
|
||||
Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method!
|
||||
|
||||
Requests is one of the most downloaded Python packages today, pulling in around `30M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `1,000,000+` repositories. You may certainly put your trust in this code.
|
||||
|
||||
Requests is **the most downloaded Python package today**, pulling in around `14M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `367_296` repositories. You may certainly put your trust in this code.
|
||||
[](https://pepy.tech/project/requests)
|
||||
[](https://pypi.org/project/requests)
|
||||
[](https://github.com/psf/requests/graphs/contributors)
|
||||
|
||||
## Installing Requests and Supported Versions
|
||||
|
||||
<p> </p>
|
||||
<p align="center"><a href="https://pepy.tech/project/requests" rel="nofollow"><img src="https://camo.githubusercontent.com/e1dedc9f5ce5cd6b6c699f33d2e812daadcf3645/68747470733a2f2f706570792e746563682f62616467652f7265717565737473" alt="Downloads" data-canonical-src="https://pepy.tech/badge/requests" style="max-width:100%;"></a>
|
||||
<a href="https://pypi.org/project/requests/" rel="nofollow"><img src="https://camo.githubusercontent.com/6d78aeec0a9a1cfe147ad064bfb99069e298e29b/68747470733a2f2f696d672e736869656c64732e696f2f707970692f707976657273696f6e732f72657175657374732e737667" alt="image" data-canonical-src="https://img.shields.io/pypi/pyversions/requests.svg" style="max-width:100%;"></a>
|
||||
<a href="https://github.com/psf/requests/graphs/contributors"><img src="https://camo.githubusercontent.com/a70ea15870b38bba9203b969f6a6b7e7845fbb8a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f7073662f72657175657374732e737667" alt="image" data-canonical-src="https://img.shields.io/github/contributors/psf/requests.svg" style="max-width:100%;"></a></p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
<h2 align="center">Supported Features & Best–Practices</h2>
|
||||
|
||||
Requests is ready for the demands of building robust and reliable HTTP–speak applications, for the needs of today.
|
||||
|
||||
<pre class="test">
|
||||
+ International Domains and URLs + Keep-Alive & Connection Pooling
|
||||
+ Sessions with Cookie Persistence + Browser-style SSL Verification
|
||||
+ Basic & Digest Authentication + Familiar `dict`–like Cookies
|
||||
+ Automatic Decompression of Content + Automatic Content Decoding
|
||||
+ Automatic Connection Pooling + Unicode Response Bodies<super>*</super>
|
||||
+ Multi-part File Uploads + SOCKS Proxy Support
|
||||
+ Connection Timeouts + Streaming Downloads
|
||||
+ Automatic honoring of `.netrc` + Chunked HTTP Requests
|
||||
|
||||
&, of course, rock–solid stability!
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p align="center">
|
||||
✨ 🍰 ✨
|
||||
</p>
|
||||
|
||||
<p> </p>
|
||||
|
||||
Requests Module Installation
|
||||
----------------------------
|
||||
|
||||
The recommended way to intall the `requests` module is to simply use [`pipenv`](https://pipenv.kennethreitz.org) (or `pip`, of
|
||||
course):
|
||||
Requests is available on PyPI:
|
||||
|
||||
```console
|
||||
$ pipenv install requests
|
||||
Adding requests to Pipfile's [packages]…
|
||||
✔ Installation Succeeded
|
||||
…
|
||||
$ python -m pip install requests
|
||||
```
|
||||
|
||||
Requests officially supports Python 2.7 & 3.5+.
|
||||
Requests officially supports Python 2.7 & 3.6+.
|
||||
|
||||
-------------------------------------
|
||||
## Supported Features & Best–Practices
|
||||
|
||||
## P.S. — Documentation is Available at [`//requests.readthedocs.io`](https://requests.readthedocs.io/en/latest/).
|
||||
Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://requests.readthedocs.io/"><img src="https://raw.githubusercontent.com/psf/requests/master/ext/ss.png" align="center" /></a>
|
||||
</p>
|
||||
- Keep-Alive & Connection Pooling
|
||||
- International Domains and URLs
|
||||
- Sessions with Cookie Persistence
|
||||
- Browser-style TLS/SSL Verification
|
||||
- Basic & Digest Authentication
|
||||
- Familiar `dict`–like Cookies
|
||||
- Automatic Content Decompression and Decoding
|
||||
- Multi-part File Uploads
|
||||
- SOCKS Proxy Support
|
||||
- Connection Timeouts
|
||||
- Streaming Downloads
|
||||
- Automatic honoring of `.netrc`
|
||||
- Chunked HTTP Requests
|
||||
|
||||
## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io)
|
||||
|
||||
------------------
|
||||
[](https://requests.readthedocs.io)
|
||||
|
||||
## Cloning the repository
|
||||
|
||||
<p> </p>
|
||||
When cloning the Requests repository, you may need to add the `-c
|
||||
fetch.fsck.badTimezone=ignore` flag to avoid an error about a bad commit (see
|
||||
[this issue](https://github.com/psf/requests/issues/2690) for more background):
|
||||
|
||||
<p align="center">
|
||||
<a href="https://kennethreitz.org/"><img src="https://raw.githubusercontent.com/psf/requests/master/ext/kr.png" align="center" /></a>
|
||||
</p>
|
||||
```shell
|
||||
git clone -c fetch.fsck.badTimezone=ignore https://github.com/psf/requests.git
|
||||
```
|
||||
|
||||
<p> </p>
|
||||
You can also apply this setting to your global Git config:
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.python.org/psf/"><img src="https://raw.githubusercontent.com/psf/requests/master/ext/psf.png" align="center" /></a>
|
||||
</p>
|
||||
```shell
|
||||
git config --global fetch.fsck.badTimezone ignore
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
[](https://kennethreitz.org) [](https://www.python.org/psf)
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
# Sample script to install Python and pip under Windows
|
||||
# Authors: Olivier Grisel, Jonathan Helmus, Kyle Kastner, and Alex Willmer
|
||||
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
|
||||
$BASE_URL = "https://www.python.org/ftp/python/"
|
||||
$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
|
||||
$GET_PIP_PATH = "C:\get-pip.py"
|
||||
|
||||
$PYTHON_PRERELEASE_REGEX = @"
|
||||
(?x)
|
||||
(?<major>\d+)
|
||||
\.
|
||||
(?<minor>\d+)
|
||||
\.
|
||||
(?<micro>\d+)
|
||||
(?<prerelease>[a-z]{1,2}\d+)
|
||||
"@
|
||||
|
||||
|
||||
function Download ($filename, $url) {
|
||||
$webclient = New-Object System.Net.WebClient
|
||||
|
||||
$basedir = $pwd.Path + "\"
|
||||
$filepath = $basedir + $filename
|
||||
if (Test-Path $filename) {
|
||||
Write-Host "Reusing" $filepath
|
||||
return $filepath
|
||||
}
|
||||
|
||||
# Download and retry up to 3 times in case of network transient errors.
|
||||
Write-Host "Downloading" $filename "from" $url
|
||||
$retry_attempts = 2
|
||||
for ($i = 0; $i -lt $retry_attempts; $i++) {
|
||||
try {
|
||||
$webclient.DownloadFile($url, $filepath)
|
||||
break
|
||||
}
|
||||
Catch [Exception]{
|
||||
Start-Sleep 1
|
||||
}
|
||||
}
|
||||
if (Test-Path $filepath) {
|
||||
Write-Host "File saved at" $filepath
|
||||
} else {
|
||||
# Retry once to get the error message if any at the last try
|
||||
$webclient.DownloadFile($url, $filepath)
|
||||
}
|
||||
return $filepath
|
||||
}
|
||||
|
||||
|
||||
function ParsePythonVersion ($python_version) {
|
||||
if ($python_version -match $PYTHON_PRERELEASE_REGEX) {
|
||||
return ([int]$matches.major, [int]$matches.minor, [int]$matches.micro,
|
||||
$matches.prerelease)
|
||||
}
|
||||
$version_obj = [version]$python_version
|
||||
return ($version_obj.major, $version_obj.minor, $version_obj.build, "")
|
||||
}
|
||||
|
||||
|
||||
function DownloadPython ($python_version, $platform_suffix) {
|
||||
$major, $minor, $micro, $prerelease = ParsePythonVersion $python_version
|
||||
|
||||
if (($major -le 2 -and $micro -eq 0) `
|
||||
-or ($major -eq 3 -and $minor -le 2 -and $micro -eq 0) `
|
||||
) {
|
||||
$dir = "$major.$minor"
|
||||
$python_version = "$major.$minor$prerelease"
|
||||
} else {
|
||||
$dir = "$major.$minor.$micro"
|
||||
}
|
||||
|
||||
if ($prerelease) {
|
||||
if (($major -le 2) `
|
||||
-or ($major -eq 3 -and $minor -eq 1) `
|
||||
-or ($major -eq 3 -and $minor -eq 2) `
|
||||
-or ($major -eq 3 -and $minor -eq 3) `
|
||||
) {
|
||||
$dir = "$dir/prev"
|
||||
}
|
||||
}
|
||||
|
||||
if (($major -le 2) -or ($major -le 3 -and $minor -le 4)) {
|
||||
$ext = "msi"
|
||||
if ($platform_suffix) {
|
||||
$platform_suffix = ".$platform_suffix"
|
||||
}
|
||||
} else {
|
||||
$ext = "exe"
|
||||
if ($platform_suffix) {
|
||||
$platform_suffix = "-$platform_suffix"
|
||||
}
|
||||
}
|
||||
|
||||
$filename = "python-$python_version$platform_suffix.$ext"
|
||||
$url = "$BASE_URL$dir/$filename"
|
||||
$filepath = Download $filename $url
|
||||
return $filepath
|
||||
}
|
||||
|
||||
|
||||
function InstallPython ($python_version, $architecture, $python_home) {
|
||||
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||
if (Test-Path $python_home) {
|
||||
Write-Host $python_home "already exists, skipping."
|
||||
return $false
|
||||
}
|
||||
if ($architecture -eq "32") {
|
||||
$platform_suffix = ""
|
||||
} else {
|
||||
$platform_suffix = "amd64"
|
||||
}
|
||||
$installer_path = DownloadPython $python_version $platform_suffix
|
||||
$installer_ext = [System.IO.Path]::GetExtension($installer_path)
|
||||
Write-Host "Installing $installer_path to $python_home"
|
||||
$install_log = $python_home + ".log"
|
||||
if ($installer_ext -eq '.msi') {
|
||||
InstallPythonMSI $installer_path $python_home $install_log
|
||||
} else {
|
||||
InstallPythonEXE $installer_path $python_home $install_log
|
||||
}
|
||||
if (Test-Path $python_home) {
|
||||
Write-Host "Python $python_version ($architecture) installation complete"
|
||||
} else {
|
||||
Write-Host "Failed to install Python in $python_home"
|
||||
Get-Content -Path $install_log
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function InstallPythonEXE ($exepath, $python_home, $install_log) {
|
||||
$install_args = "/quiet InstallAllUsers=1 TargetDir=$python_home"
|
||||
RunCommand $exepath $install_args
|
||||
}
|
||||
|
||||
|
||||
function InstallPythonMSI ($msipath, $python_home, $install_log) {
|
||||
$install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
|
||||
$uninstall_args = "/qn /x $msipath"
|
||||
RunCommand "msiexec.exe" $install_args
|
||||
if (-not(Test-Path $python_home)) {
|
||||
Write-Host "Python seems to be installed else-where, reinstalling."
|
||||
RunCommand "msiexec.exe" $uninstall_args
|
||||
RunCommand "msiexec.exe" $install_args
|
||||
}
|
||||
}
|
||||
|
||||
function RunCommand ($command, $command_args) {
|
||||
Write-Host $command $command_args
|
||||
Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
|
||||
}
|
||||
|
||||
|
||||
function InstallPip ($python_home) {
|
||||
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||
$python_path = $python_home + "\python.exe"
|
||||
if (-not(Test-Path $pip_path)) {
|
||||
Write-Host "Installing pip..."
|
||||
$webclient = New-Object System.Net.WebClient
|
||||
$webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
|
||||
Write-Host "Executing:" $python_path $GET_PIP_PATH
|
||||
& $python_path $GET_PIP_PATH
|
||||
} else {
|
||||
Write-Host "pip already installed."
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function DownloadMiniconda ($python_version, $platform_suffix) {
|
||||
if ($python_version -eq "3.4") {
|
||||
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||
} else {
|
||||
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||
}
|
||||
$url = $MINICONDA_URL + $filename
|
||||
$filepath = Download $filename $url
|
||||
return $filepath
|
||||
}
|
||||
|
||||
|
||||
function InstallMiniconda ($python_version, $architecture, $python_home) {
|
||||
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||
if (Test-Path $python_home) {
|
||||
Write-Host $python_home "already exists, skipping."
|
||||
return $false
|
||||
}
|
||||
if ($architecture -eq "32") {
|
||||
$platform_suffix = "x86"
|
||||
} else {
|
||||
$platform_suffix = "x86_64"
|
||||
}
|
||||
$filepath = DownloadMiniconda $python_version $platform_suffix
|
||||
Write-Host "Installing" $filepath "to" $python_home
|
||||
$install_log = $python_home + ".log"
|
||||
$args = "/S /D=$python_home"
|
||||
Write-Host $filepath $args
|
||||
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
|
||||
if (Test-Path $python_home) {
|
||||
Write-Host "Python $python_version ($architecture) installation complete"
|
||||
} else {
|
||||
Write-Host "Failed to install Python in $python_home"
|
||||
Get-Content -Path $install_log
|
||||
Exit 1
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function InstallMinicondaPip ($python_home) {
|
||||
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||
$conda_path = $python_home + "\Scripts\conda.exe"
|
||||
if (-not(Test-Path $pip_path)) {
|
||||
Write-Host "Installing pip..."
|
||||
$args = "install --yes pip"
|
||||
Write-Host $conda_path $args
|
||||
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
|
||||
} else {
|
||||
Write-Host "pip already installed."
|
||||
}
|
||||
}
|
||||
|
||||
function main () {
|
||||
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
|
||||
InstallPip $env:PYTHON
|
||||
}
|
||||
|
||||
main
|
||||
57
appveyor.yml
57
appveyor.yml
@@ -1,57 +0,0 @@
|
||||
# AppVeyor.yml from https://github.com/ogrisel/python-appveyor-demo
|
||||
# License: CC0 1.0 Universal: https://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
build: off
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
- PYTHON: "C:\\Python27-x64"
|
||||
PYTHON_VERSION: "2.7.x"
|
||||
PYTHON_ARCH: "64"
|
||||
TOXENV: "py27"
|
||||
|
||||
- PYTHON: "C:\\Python34-x64"
|
||||
PYTHON_VERSION: "3.4.x"
|
||||
PYTHON_ARCH: "64"
|
||||
TOXENV: "py34"
|
||||
|
||||
- PYTHON: "C:\\Python35-x64"
|
||||
PYTHON_VERSION: "3.5.x"
|
||||
PYTHON_ARCH: "64"
|
||||
TOXENV: "py35"
|
||||
|
||||
- PYTHON: "C:\\Python36-x64"
|
||||
PYTHON_VERSION: "3.6.x"
|
||||
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 https://www.python.org/) and pip when
|
||||
# not already installed.
|
||||
- ps: if (-not(Test-Path($env:PYTHON))) { & _appveyor\install.ps1 }
|
||||
|
||||
# Prepend newly installed Python to the PATH of this build (this cannot be
|
||||
# done from inside the powershell script as it would require to restart
|
||||
# the parent CMD process).
|
||||
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||
|
||||
# Check that we have the expected version and architecture for Python
|
||||
- "python --version"
|
||||
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||
|
||||
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||
# about it being out of date.
|
||||
- "python -m pip install --upgrade pip wheel"
|
||||
- "C:\\MinGW\\bin\\mingw32-make"
|
||||
- "pipenv install -e .[socks] --skip-lock"
|
||||
|
||||
test_script:
|
||||
- "C:\\MinGW\\bin\\mingw32-make coverage"
|
||||
|
||||
on_success:
|
||||
- "pipenv run codecov -f coverage.xml"
|
||||
116
docs/_static/konami.js
vendored
116
docs/_static/konami.js
vendored
@@ -1,116 +0,0 @@
|
||||
/*
|
||||
* Konami-JS ~
|
||||
* :: Now with support for touch events and multiple instances for
|
||||
* :: those situations that call for multiple easter eggs!
|
||||
* Code: http://konami-js.googlecode.com/
|
||||
* Examples: http://www.snaptortoise.com/konami-js
|
||||
* Copyright (c) 2009 George Mandis (georgemandis.com, snaptortoise.com)
|
||||
* Version: 1.4.2 (9/2/2013)
|
||||
* Licensed under the MIT License (http://opensource.org/licenses/MIT)
|
||||
* Tested in: Safari 4+, Google Chrome 4+, Firefox 3+, IE7+, Mobile Safari 2.2.1 and Dolphin Browser
|
||||
*/
|
||||
|
||||
var Konami = function (callback) {
|
||||
var konami = {
|
||||
addEvent: function (obj, type, fn, ref_obj) {
|
||||
if (obj.addEventListener)
|
||||
obj.addEventListener(type, fn, false);
|
||||
else if (obj.attachEvent) {
|
||||
// IE
|
||||
obj["e" + type + fn] = fn;
|
||||
obj[type + fn] = function () {
|
||||
obj["e" + type + fn](window.event, ref_obj);
|
||||
};
|
||||
obj.attachEvent("on" + type, obj[type + fn]);
|
||||
}
|
||||
},
|
||||
input: "",
|
||||
pattern: "38384040373937396665",
|
||||
load: function (link) {
|
||||
this.addEvent(document, "keydown", function (e, ref_obj) {
|
||||
if (ref_obj) konami = ref_obj; // IE
|
||||
konami.input += e ? e.keyCode : event.keyCode;
|
||||
if (konami.input.length > konami.pattern.length)
|
||||
konami.input = konami.input.substr((konami.input.length - konami.pattern.length));
|
||||
if (konami.input == konami.pattern) {
|
||||
konami.code(link);
|
||||
konami.input = "";
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
}, this);
|
||||
this.iphone.load(link);
|
||||
},
|
||||
code: function (link) {
|
||||
window.location = link
|
||||
},
|
||||
iphone: {
|
||||
start_x: 0,
|
||||
start_y: 0,
|
||||
stop_x: 0,
|
||||
stop_y: 0,
|
||||
tapTolerance: 8,
|
||||
capture: false,
|
||||
orig_keys: "",
|
||||
keys: ["UP", "UP", "DOWN", "DOWN", "LEFT", "RIGHT", "LEFT", "RIGHT", "TAP", "TAP"],
|
||||
code: function (link) {
|
||||
konami.code(link);
|
||||
},
|
||||
touchCapture: function(evt) {
|
||||
konami.iphone.start_x = evt.changedTouches[0].pageX;
|
||||
konami.iphone.start_y = evt.changedTouches[0].pageY;
|
||||
konami.iphone.capture = true;
|
||||
},
|
||||
load: function (link) {
|
||||
this.orig_keys = this.keys;
|
||||
konami.addEvent(document, "touchmove", function (e) {
|
||||
if (e.touches.length == 1 && konami.iphone.capture == true) {
|
||||
var touch = e.touches[0];
|
||||
konami.iphone.stop_x = touch.pageX;
|
||||
konami.iphone.stop_y = touch.pageY;
|
||||
konami.iphone.check_direction();
|
||||
}
|
||||
});
|
||||
konami.addEvent(document, "touchend", function (evt) {
|
||||
konami.touchCapture(evt);
|
||||
konami.iphone.check_direction(link);
|
||||
}, false);
|
||||
konami.addEvent(document, "touchstart", function (evt) {
|
||||
konami.touchCapture(evt);
|
||||
});
|
||||
},
|
||||
check_direction: function (link) {
|
||||
var x_magnitude = Math.abs(this.start_x - this.stop_x);
|
||||
var y_magnitude = Math.abs(this.start_y - this.stop_y);
|
||||
var hasMoved = (x_magnitude > this.tapTolerance || y_magnitude > this.tapTolerance);
|
||||
var result;
|
||||
if (this.capture === true && hasMoved) {
|
||||
this.capture = false;
|
||||
var x = ((this.start_x - this.stop_x) < 0) ? "RIGHT" : "LEFT";
|
||||
var y = ((this.start_y - this.stop_y) < 0) ? "DOWN" : "UP";
|
||||
var result = (x_magnitude > y_magnitude) ? x : y;
|
||||
}
|
||||
else if (this.capture === false && !hasMoved) {
|
||||
result = (this.tap == true) ? "TAP" : result;
|
||||
result = "TAP";
|
||||
}
|
||||
if (result) {
|
||||
if (result == this.keys[0]) this.keys = this.keys.slice(1, this.keys.length);
|
||||
else this.keys = this.orig_keys;
|
||||
}
|
||||
if (this.keys.length == 0) {
|
||||
this.keys = this.orig_keys;
|
||||
this.code(link);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typeof callback === "string" && konami.load(callback);
|
||||
if (typeof callback === "function") {
|
||||
konami.code = callback;
|
||||
konami.load();
|
||||
}
|
||||
|
||||
return konami;
|
||||
};
|
||||
BIN
docs/_static/requests-logo-small.jpg
vendored
BIN
docs/_static/requests-logo-small.jpg
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 83 KiB |
BIN
docs/_static/requests-sidebar.jpg
vendored
BIN
docs/_static/requests-sidebar.jpg
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 242 KiB |
BIN
docs/_static/requests-sidebar.png
vendored
Normal file
BIN
docs/_static/requests-sidebar.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 299 KiB |
30
docs/_templates/hacks.html
vendored
30
docs/_templates/hacks.html
vendored
@@ -23,38 +23,8 @@
|
||||
/* Have code blocks escape the document right-margin. */
|
||||
div.highlight pre {margin-right: -30px;}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
<!-- Analytics tracking for Kenneth. -->
|
||||
<script type="text/javascript">
|
||||
var _gauges = _gauges || [];
|
||||
(function() {
|
||||
var t = document.createElement('script');
|
||||
t.type = 'text/javascript';
|
||||
t.async = true;
|
||||
t.id = 'gauges-tracker';
|
||||
t.setAttribute('data-site-id', '56ca7a57c88d9011080024dd');
|
||||
t.setAttribute('data-track-path', 'https://track.gaug.es/track.gif');
|
||||
t.src = 'https://d36ee2fcip1434.cloudfront.net/track.js';
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(t, s);
|
||||
})();
|
||||
</script>
|
||||
|
||||
|
||||
<!-- There are no more hacks. -->
|
||||
<!-- இڿڰۣ-ڰۣ— -->
|
||||
<!-- Love, Kenneth Reitz -->
|
||||
|
||||
<script src="{{ pathto('_static/', 1) }}/konami.js"></script>
|
||||
<script>
|
||||
var easter_egg = new Konami('http://fortunes.herokuapp.com/random/raw');
|
||||
</script>
|
||||
|
||||
<!-- That was not a hack. That was art. -->
|
||||
|
||||
<!-- Native CPC by BuySellAds -->
|
||||
|
||||
<script type="text/javascript" src="//m.servedby-buysellads.com/monetization.js"></script>
|
||||
|
||||
20
docs/_templates/sidebarintro.html
vendored
20
docs/_templates/sidebarintro.html
vendored
@@ -1,6 +1,6 @@
|
||||
<p class="logo">
|
||||
<a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.jpg', 1) }}" title="https://kennethreitz.org/tattoos" />
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.png', 1) }}" alt="Requests logo" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
@@ -42,23 +42,23 @@
|
||||
src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=CKYI5K3E&placement=pythonrequestsorg"
|
||||
id="_carbonads_js"></script>
|
||||
|
||||
<h3>Stay Informed</h3>
|
||||
<p>Receive updates on new releases and upcoming projects.</p>
|
||||
|
||||
<p><iframe src="https://ghbtns.com/github-btn.html?user=kennethreitz&type=follow&count=false" allowtransparency="true"
|
||||
frameborder="0" scrolling="0" width="200" height="20"></iframe></p>
|
||||
|
||||
<h3>Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/recommended/">Recommended Packages and Extensions</a>
|
||||
</li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/user/quickstart/">Quickstart</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/user/advanced/">Advanced Usage</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/api/">API Reference</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/updates/#release-history">Release History</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/dev/contributing/">Contributors Guide</a></li>
|
||||
|
||||
<p></p>
|
||||
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/recommended/">Recommended Packages and Extensions</a></li>
|
||||
|
||||
<p></p>
|
||||
|
||||
<li><a href="https://github.com/psf/requests">Requests @ GitHub</a></li>
|
||||
<li><a href="https://pypi.org/project/requests/">Requests @ PyPI</a></li>
|
||||
<li><a href="https://github.com/psf/requests/issues">Issue Tracker</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/updates/#software-updates">Release History</a></li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
32
docs/_templates/sidebarlogo.html
vendored
32
docs/_templates/sidebarlogo.html
vendored
@@ -1,8 +1,3 @@
|
||||
<p class="logo">
|
||||
<a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/requests-sidebar.jpg', 1) }}" title="https://kennethreitz.org/tattoos" />
|
||||
</a>
|
||||
</p>
|
||||
<p>
|
||||
<iframe src="https://ghbtns.com/github-btn.html?user=psf&repo=requests&type=watch&count=true&size=large"
|
||||
allowtransparency="true" frameborder="0" scrolling="0" width="200px" height="35px"></iframe>
|
||||
@@ -37,19 +32,30 @@
|
||||
development release.
|
||||
</p>
|
||||
|
||||
<p<p>Sponsored by <strong><a href="https://www.govcert.lu">CERT Gouvernemental - GOVCERT.LU</a></strong>.</p>
|
||||
|
||||
<h3>Stay Informed</h3>
|
||||
<p>Receive updates on new releases and upcoming projects.</p>
|
||||
|
||||
<p><a href="https://tinyletter.com/kennethreitz">Join Mailing List</a>.</p>
|
||||
|
||||
<hr />
|
||||
<p>Sponsored by <strong><a href="https://www.govcert.lu">CERT Gouvernemental - GOVCERT.LU</a></strong>.</p>
|
||||
|
||||
<script async type="text/javascript"
|
||||
src="//cdn.carbonads.com/carbon.js?zoneid=1673&serve=C6AILKT&placement=pythonrequestsorg"
|
||||
id="_carbonads_js"></script>
|
||||
|
||||
<h3>Useful Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/user/quickstart/">Quickstart</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/user/advanced/">Advanced Usage</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/api/">API Reference</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/updates/#release-history">Release History</a></li>
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/dev/contributing/">Contributors Guide</a></li>
|
||||
|
||||
<p></p>
|
||||
|
||||
<li><a href="https://requests.readthedocs.io/en/latest/community/recommended/">Recommended Packages and Extensions</a></li>
|
||||
|
||||
<p></p>
|
||||
|
||||
<li><a href="https://github.com/psf/requests">Requests @ GitHub</a></li>
|
||||
<li><a href="https://pypi.org/project/requests/">Requests @ PyPI</a></li>
|
||||
<li><a href="https://github.com/psf/requests/issues">Issue Tracker</a></li>
|
||||
</ul>
|
||||
|
||||
<h3>Translations</h3>
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ API Changes
|
||||
::
|
||||
|
||||
import requests
|
||||
r = requests.get('https://github.com/timeline.json')
|
||||
r = requests.get('https://api.github.com/events')
|
||||
r.json() # This *call* raises an exception if JSON decoding fails
|
||||
|
||||
* The ``Session`` API has changed. Sessions objects no longer take parameters.
|
||||
@@ -156,7 +156,7 @@ API Changes
|
||||
::
|
||||
|
||||
# in 0.x, passing prefetch=False would accomplish the same thing
|
||||
r = requests.get('https://github.com/timeline.json', stream=True)
|
||||
r = requests.get('https://api.github.com/events', stream=True)
|
||||
for chunk in r.iter_content(8192):
|
||||
...
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
Frequently Asked Questions
|
||||
==========================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4290/35294660055_42c02b2316_k_d.jpg
|
||||
|
||||
This part of the documentation answers common questions about Requests.
|
||||
|
||||
Encoded Data?
|
||||
@@ -13,6 +11,9 @@ Encoded Data?
|
||||
Requests automatically decompresses gzip-encoded responses, and does
|
||||
its best to decode response content to unicode when possible.
|
||||
|
||||
When either the `brotli <https://pypi.org/project/Brotli/>`_ or `brotlicffi <https://pypi.org/project/brotlicffi/>`_
|
||||
package is installed, requests also decodes Brotli-encoded responses.
|
||||
|
||||
You can get direct access to the raw response (and even the socket),
|
||||
if needed as well.
|
||||
|
||||
@@ -21,7 +22,7 @@ Custom User-Agents?
|
||||
-------------------
|
||||
|
||||
Requests allows you to easily override User-Agent strings, along with
|
||||
any other HTTP Header. See `documentation about headers <https://requests.readthedocs.io/en/master/user/quickstart/#custom-headers>`_.
|
||||
any other HTTP Header. See `documentation about headers <https://requests.readthedocs.io/en/latest/user/quickstart/#custom-headers>`_.
|
||||
|
||||
|
||||
|
||||
@@ -54,19 +55,17 @@ Chris Adams gave an excellent summary on
|
||||
Python 3 Support?
|
||||
-----------------
|
||||
|
||||
Yes! Requests officially supports Python 2.7 & 3.5+ and PyPy.
|
||||
Yes! Requests officially supports Python 2.7 & 3.6+ and PyPy.
|
||||
|
||||
Python 2 Support?
|
||||
-----------------
|
||||
|
||||
Yes! We do not have immediate plans to `sunset
|
||||
<https://www.python.org/doc/sunset-python-2/>`_ our support for Python
|
||||
2.7. We understand that we have a large user base with varying needs,
|
||||
and intend to maintain Python 2.7 support within Requests until `pip
|
||||
stops supporting Python 2.7 (there's no estimated date on that yet)
|
||||
<https://pip.pypa.io/en/latest/development/release-process/#python-2-support>`_.
|
||||
Yes! We understand that we have a large user base with varying needs. Through
|
||||
**at least** Requests 2.27.x, we will be providing continued support for Python
|
||||
2.7. However, this support is likely to end some time in 2022.
|
||||
|
||||
That said, it is *highly* recommended users migrate to Python 3.5+ since Python 2.7 will no longer be receiving bug fixes or security updates after January 1, 2020.
|
||||
It is *highly* recommended users migrate to Python 3.7+ now since Python
|
||||
2.7 is no longer receiving bug fixes or security updates as of January 1, 2020.
|
||||
|
||||
What are "hostname doesn't match" errors?
|
||||
-----------------------------------------
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Integrations
|
||||
============
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4239/34450900674_15863ddea0_k_d.jpg
|
||||
|
||||
Python for iOS
|
||||
--------------
|
||||
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
Recommended Packages and Extensions
|
||||
===================================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4218/35224319272_cfc0e621fb_k_d.jpg
|
||||
|
||||
Requests has a great variety of powerful and useful third-party extensions.
|
||||
This page provides an overview of some of the best of them.
|
||||
|
||||
@@ -61,4 +59,4 @@ Betamax
|
||||
`Betamax`_ records your HTTP interactions so the NSA does not have to.
|
||||
A VCR imitation designed only for Python-Requests.
|
||||
|
||||
.. _betamax: https://github.com/sigmavirus24/betamax
|
||||
.. _betamax: https://github.com/betamaxpy/betamax
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
Release Process and Rules
|
||||
=========================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4215/34450901614_b74ae720db_k_d.jpg
|
||||
|
||||
.. versionadded:: v2.6.2
|
||||
|
||||
Starting with the version to be released after ``v2.6.2``, the following rules
|
||||
|
||||
@@ -3,26 +3,16 @@
|
||||
Support
|
||||
=======
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4198/34080352913_5c13ffb336_k_d.jpg
|
||||
|
||||
If you have questions or issues about Requests, there are several options:
|
||||
|
||||
Stack Overflow
|
||||
-------------
|
||||
--------------
|
||||
|
||||
If your question does not contain sensitive (possibly proprietary)
|
||||
information or can be properly anonymized, please ask a question on
|
||||
`Stack Overflow <https://stackoverflow.com/questions/tagged/python-requests>`_
|
||||
and use the tag ``python-requests``.
|
||||
|
||||
Send a Tweet
|
||||
------------
|
||||
|
||||
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>`_,
|
||||
`@lukasaoz <https://twitter.com/lukasaoz>`_, or
|
||||
`@nateprewitt <https://twitter.com/nateprewitt>`_.
|
||||
|
||||
File an Issue
|
||||
-------------
|
||||
@@ -32,23 +22,10 @@ for a new feature,
|
||||
`file an issue on GitHub <https://github.com/psf/requests/issues>`_.
|
||||
|
||||
|
||||
E-mail
|
||||
------
|
||||
Send a Tweet
|
||||
------------
|
||||
|
||||
I'm more than happy to answer any personal or in-depth questions about
|
||||
Requests. Feel free to email
|
||||
`requests@kennethreitz.com <mailto:requests@kennethreitz.com>`_.
|
||||
|
||||
|
||||
IRC
|
||||
---
|
||||
|
||||
The official Freenode channel for Requests is
|
||||
`#python-requests <irc://irc.freenode.net/python-requests>`_
|
||||
|
||||
The core developers of requests are on IRC throughout the day.
|
||||
You can find them in ``#python-requests`` as:
|
||||
|
||||
- kennethreitz
|
||||
- lukasa
|
||||
- sigmavirus24
|
||||
If your question is less than 280 characters, feel free to send a tweet to
|
||||
`@nateprewitt <https://twitter.com/nateprewitt>`_,
|
||||
`@sethmlarson <https://twitter.com/sethmlarson>`_, or
|
||||
`@sigmavirus24 <https://twitter.com/sigmavirus24>`_.
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
Community Updates
|
||||
=================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4244/34080354873_516c283ad0_k_d.jpg
|
||||
|
||||
If you'd like to stay up to date on the community and development of Requests,
|
||||
there are several options:
|
||||
|
||||
@@ -16,16 +14,5 @@ GitHub
|
||||
The best way to track the development of Requests is through
|
||||
`the GitHub repo <https://github.com/psf/requests>`_.
|
||||
|
||||
Twitter
|
||||
-------
|
||||
|
||||
The author, Kenneth Reitz, often tweets about new features and releases of Requests.
|
||||
|
||||
Follow `@kennethreitz <https://twitter.com/kennethreitz>`_ for updates.
|
||||
|
||||
|
||||
|
||||
Release and Version History
|
||||
===========================
|
||||
|
||||
.. include:: ../../HISTORY.md
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
Vulnerability Disclosure
|
||||
========================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4211/34709353644_b041e9e1c2_k_d.jpg
|
||||
|
||||
If you think you have found a potential security vulnerability in requests,
|
||||
please email `sigmavirus24 <mailto:graffatcolmingov@gmail.com>`_ and
|
||||
`Nate <mailto:nate.prewitt@gmail.com>`_ directly. **Do not file a public issue.**
|
||||
please email `Nate <mailto:nate.prewitt@gmail.com>`_ and `Seth <mailto:@sethmichaellarson@gmail.com>`_ directly. **Do not file a public issue.**
|
||||
|
||||
Our PGP Key fingerprints are:
|
||||
|
||||
- 0161 BB7E B208 B5E0 4FDC 9F81 D9DA 0A04 9113 F853 (@sigmavirus24)
|
||||
- 8722 7E29 AD9C FF5C FAC3 EA6A 44D3 FF97 B80D C864 (`@nateprewitt <https://keybase.io/nateprewitt>`_)
|
||||
|
||||
- 8722 7E29 AD9C FF5C FAC3 EA6A 44D3 FF97 B80D C864 (@nateprewitt)
|
||||
- EDD5 6765 A9D8 4653 CBC8 A134 51B0 6736 1740 F5FC (`@sethmlarson <https://keybase.io/sethmlarson>`_)
|
||||
|
||||
You can also contact us on `Keybase <https://keybase.io/>`_ with the
|
||||
profiles above if desired.
|
||||
|
||||
If English is not your first language, please try to describe the problem and
|
||||
its impact to the best of your ability. For greater detail, please use your
|
||||
@@ -72,7 +72,7 @@ time, to ensure that they are able to promptly release their downstream
|
||||
packages. Currently the list of people we actively contact *ahead of a public
|
||||
release* is:
|
||||
|
||||
- Jeremy Cline, Red Hat (@jeremycline)
|
||||
- Python Maintenance Team, Red Hat (python-maint@redhat.com)
|
||||
- Daniele Tricoli, Debian (@eriol)
|
||||
|
||||
We will notify these individuals at least a week ahead of our planned release
|
||||
|
||||
@@ -58,7 +58,7 @@ master_doc = "index"
|
||||
|
||||
# General information about the project.
|
||||
project = u"Requests"
|
||||
copyright = u'MMXVIX. A <a href="http://kennethreitz.com/pages/open-projects.html">Kenneth Reitz</a> Project'
|
||||
copyright = u'MMXVIX. A <a href="https://kenreitz.org/projects">Kenneth Reitz</a> Project'
|
||||
author = u"Kenneth Reitz"
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
.. image:: https://static1.squarespace.com/static/533ad9bde4b098d084a846b1/t/534f6e1ce4b09b70f38ee6c1/1432265542589/DSCF3147.jpg?format=2500w
|
||||
|
||||
.. include:: ../../AUTHORS.rst
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
Contributor's Guide
|
||||
===================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4237/35550408335_7671fde302_k_d.jpg
|
||||
|
||||
If you're reading this, you're probably interested in contributing to Requests.
|
||||
Thank you very much! Open source projects live-and-die based on the support
|
||||
they receive from others, and the fact that you're even considering
|
||||
@@ -13,23 +11,17 @@ contributing to the Requests project is *very* generous of you.
|
||||
This document lays out guidelines and advice for contributing to this project.
|
||||
If you're thinking of contributing, please start by reading this document and
|
||||
getting a feel for how contributing to this project works. If you have any
|
||||
questions, feel free to reach out to either `Ian Cordasco`_, `Cory Benfield`_,
|
||||
or `Nate Prewitt`_, the primary maintainers.
|
||||
questions, feel free to reach out to either `Nate Prewitt`_, `Ian Cordasco`_,
|
||||
or `Seth Michael Larson`_, the primary maintainers.
|
||||
|
||||
.. _Ian Cordasco: http://www.coglib.com/~icordasc/
|
||||
.. _Cory Benfield: https://lukasa.co.uk/about
|
||||
.. _Nate Prewitt: https://www.nateprewitt.com/
|
||||
|
||||
If you have non-technical feedback, philosophical ponderings, crazy ideas, or
|
||||
other general thoughts about Requests or its position within the Python
|
||||
ecosystem, the BDFL, `Kenneth Reitz`_, would love to hear from you.
|
||||
.. _Seth Michael Larson: https://sethmlarson.dev/
|
||||
|
||||
The guide is split into sections based on the type of contribution you're
|
||||
thinking of making, with a section that covers general guidelines for all
|
||||
contributors.
|
||||
|
||||
.. _Kenneth Reitz: mailto:me@kennethreitz.org
|
||||
|
||||
Be Cordial
|
||||
----------
|
||||
|
||||
@@ -42,7 +34,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: https://www.kennethreitz.org/essays/be-cordial-or-be-on-your-way
|
||||
.. _be cordial or be on your way: https://kenreitz.org/essays/2013/01/27/be-cordial-or-be-on-your-way
|
||||
|
||||
.. _early-feedback:
|
||||
|
||||
@@ -86,7 +78,7 @@ When contributing code, you'll want to follow this checklist:
|
||||
4. Make your change.
|
||||
5. Run the entire test suite again, confirming that all tests pass *including
|
||||
the ones you just added*.
|
||||
6. Send a GitHub Pull Request to the main repository's ``master`` branch.
|
||||
6. Send a GitHub Pull Request to the main repository's ``main`` branch.
|
||||
GitHub Pull Requests are the expected method of code collaboration on this
|
||||
project.
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
Development Philosophy
|
||||
======================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4231/34484831073_636008a23d_k_d.jpg
|
||||
|
||||
Requests is an open but opinionated library, created by an open but opinionated developer.
|
||||
|
||||
|
||||
Management Style
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
`Kenneth Reitz <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/>`_, `Cory Benfield <https://lukasa.co.uk/about/>`_, and `Nate Prewitt <https://www.nateprewitt.com/>`_ are the core contributors. They are responsible for triaging bug reports, reviewing pull requests and ensuring that Kenneth is kept up to speed with developments around the library. The day-to-day managing of the project is done by the core contributors. They are responsible for making judgements about whether or not a feature request is likely to be accepted by Kenneth. Their word is, in some ways, more final than Kenneth's.
|
||||
|
||||
Values
|
||||
~~~~~~
|
||||
|
||||
- Simplicity is always better than functionality.
|
||||
- Listen to everyone, then disregard it.
|
||||
- The API is all that matters. Everything else is secondary.
|
||||
- Fit the 90% use-case. Ignore the nay-sayers.
|
||||
|
||||
Semantic Versioning
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
For many years, the open source community has been plagued with version number dystonia. Numbers vary so greatly from project to project, they are practically meaningless.
|
||||
|
||||
Requests uses `Semantic Versioning <https://semver.org/>`_. This specification seeks to put an end to this madness with a small set of practical guidelines for you and your colleagues to use in your next project.
|
||||
|
||||
Standard Library?
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Requests has no *active* plans to be included in the standard library. This decision has been discussed at length with Guido as well as numerous core developers.
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script async class="speakerdeck-embed" data-id="68f22f0841734d848315c618111b13ea" data-ratio="1.33333333333333" src="//speakerdeck.com/assets/embed.js"></script>
|
||||
|
||||
Essentially, the standard library is where a library goes to die. It is appropriate for a module to be included when active development is no longer necessary.
|
||||
|
||||
Linux Distro Packages
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Distributions have been made for many Linux repositories, including: Ubuntu, Debian, RHEL, and Arch.
|
||||
|
||||
These distributions are sometimes divergent forks, or are otherwise not kept up-to-date with the latest code and bugfixes. PyPI (and its mirrors) and GitHub are the official distribution sources; alternatives are not supported by the Requests project.
|
||||
@@ -1,64 +0,0 @@
|
||||
How to Help
|
||||
===========
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4290/34450900104_bc1d424213_k_d.jpg
|
||||
|
||||
Requests is under active development, and contributions are more than welcome!
|
||||
|
||||
#. Check for open issues or open a fresh issue to start a discussion around a bug.
|
||||
There is a Contributor Friendly tag for issues that should be ideal for people who are not very
|
||||
familiar with the codebase yet.
|
||||
#. Fork `the repository <https://github.com/psf/requests>`_ on GitHub and start making your
|
||||
changes to a new branch.
|
||||
#. Write a test which shows that the bug was fixed.
|
||||
#. Send a pull request and bug the maintainer until it gets merged and published. :)
|
||||
Make sure to add yourself to `AUTHORS <https://github.com/psf/requests/blob/master/AUTHORS.rst>`_.
|
||||
|
||||
Feature Freeze
|
||||
--------------
|
||||
|
||||
As of v1.0.0, Requests has now entered a feature freeze. Requests for new
|
||||
features and Pull Requests implementing those features will not be accepted.
|
||||
|
||||
Development Dependencies
|
||||
------------------------
|
||||
|
||||
You'll need to install py.test in order to run the Requests' test suite::
|
||||
|
||||
$ venv .venv
|
||||
$ source .venv/bin/activate
|
||||
|
||||
$ make
|
||||
$ python setup.py test
|
||||
============================= test session starts ==============================
|
||||
platform darwin -- Python 3.4.4, pytest-3.0.6, py-1.4.32, pluggy-0.4.0
|
||||
...
|
||||
collected 445 items
|
||||
|
||||
tests/test_hooks.py ...
|
||||
tests/test_lowlevel.py ............
|
||||
tests/test_requests.py ...........................................................
|
||||
tests/test_structures.py ....................
|
||||
tests/test_testserver.py ...........
|
||||
tests/test_utils.py ..s...........................................................
|
||||
|
||||
============== 442 passed, 1 skipped, 2 xpassed in 46.48 seconds ===============
|
||||
|
||||
You can also run ``$ make tests`` to run against all supported Python versions, using tox/detox.
|
||||
|
||||
Runtime Environments
|
||||
--------------------
|
||||
|
||||
Requests currently supports the following versions of Python:
|
||||
|
||||
- Python 2.7
|
||||
- Python 3.4
|
||||
- Python 3.5
|
||||
- Python 3.6
|
||||
- Python 3.7
|
||||
- PyPy
|
||||
|
||||
Google AppEngine is not officially supported although support is available
|
||||
with the `Requests-Toolbelt`_.
|
||||
|
||||
.. _Requests-Toolbelt: https://toolbelt.readthedocs.io/
|
||||
@@ -9,17 +9,21 @@ Requests: HTTP for Humans™
|
||||
Release v\ |version|. (:ref:`Installation <install>`)
|
||||
|
||||
|
||||
.. image:: https://pepy.tech/badge/requests
|
||||
.. image:: https://pepy.tech/badge/requests/month
|
||||
:target: https://pepy.tech/project/requests
|
||||
:alt: Requests Downloads Per Month Badge
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/requests.svg
|
||||
:target: https://pypi.org/project/requests/
|
||||
:alt: License Badge
|
||||
|
||||
.. image:: https://img.shields.io/pypi/wheel/requests.svg
|
||||
:target: https://pypi.org/project/requests/
|
||||
:alt: Wheel Support Badge
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/requests.svg
|
||||
:target: https://pypi.org/project/requests/
|
||||
:alt: Python Version Support Badge
|
||||
|
||||
**Requests** is an elegant and simple HTTP library for Python, built for human beings.
|
||||
|
||||
@@ -35,9 +39,9 @@ Release v\ |version|. (:ref:`Installation <install>`)
|
||||
>>> r.encoding
|
||||
'utf-8'
|
||||
>>> r.text
|
||||
u'{"type":"User"...'
|
||||
'{"type":"User"...'
|
||||
>>> r.json()
|
||||
{u'private_gists': 419, u'total_private_repos': 77, ...}
|
||||
{'private_gists': 419, 'total_private_repos': 77, ...}
|
||||
|
||||
See `similar code, sans Requests <https://gist.github.com/973705>`_.
|
||||
|
||||
@@ -45,7 +49,7 @@ See `similar code, sans Requests <https://gist.github.com/973705>`_.
|
||||
**Requests** allows you to send HTTP/1.1 requests extremely easily.
|
||||
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>`_.
|
||||
are 100% automatic, thanks to `urllib3 <https://github.com/urllib3/urllib3>`_.
|
||||
|
||||
Beloved Features
|
||||
----------------
|
||||
@@ -68,7 +72,7 @@ Requests is ready for today's web.
|
||||
- Chunked Requests
|
||||
- ``.netrc`` Support
|
||||
|
||||
Requests officially supports Python 2.7 & 3.4–3.7, and runs great on PyPy.
|
||||
Requests officially supports Python 2.7 & 3.6+, and runs great on PyPy.
|
||||
|
||||
|
||||
The User Guide
|
||||
@@ -81,7 +85,6 @@ instructions for getting the most out of Requests.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
user/intro
|
||||
user/install
|
||||
user/quickstart
|
||||
user/advanced
|
||||
@@ -97,15 +100,18 @@ Requests ecosystem and community.
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
community/sponsors
|
||||
community/recommended
|
||||
community/faq
|
||||
community/out-there
|
||||
community/support
|
||||
community/vulnerabilities
|
||||
community/updates
|
||||
community/release-process
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
community/updates
|
||||
|
||||
The API Documentation / Guide
|
||||
-----------------------------
|
||||
|
||||
@@ -128,8 +134,6 @@ you.
|
||||
:maxdepth: 3
|
||||
|
||||
dev/contributing
|
||||
dev/philosophy
|
||||
dev/todo
|
||||
dev/authors
|
||||
|
||||
There are no more guides. You are now guideless.
|
||||
|
||||
3
docs/requirements.txt
Normal file
3
docs/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
# Pinning to avoid unexpected breakages.
|
||||
# Used by RTD to generate docs.
|
||||
Sphinx==4.2.0
|
||||
@@ -3,8 +3,6 @@
|
||||
Advanced Usage
|
||||
==============
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4263/35163665790_d182d84f5e_k_d.jpg
|
||||
|
||||
This document covers some of Requests more advanced features.
|
||||
|
||||
.. _session-objects:
|
||||
@@ -235,15 +233,22 @@ or persistent::
|
||||
s.verify = '/path/to/certfile'
|
||||
|
||||
.. note:: If ``verify`` is set to a path to a directory, the directory must have been processed using
|
||||
the c_rehash utility supplied with OpenSSL.
|
||||
the ``c_rehash`` utility supplied with OpenSSL.
|
||||
|
||||
This list of trusted CAs can also be specified through the ``REQUESTS_CA_BUNDLE`` environment variable.
|
||||
If ``REQUESTS_CA_BUNDLE`` is not set, ``CURL_CA_BUNDLE`` will be used as fallback.
|
||||
|
||||
Requests can also ignore verifying the SSL certificate if you set ``verify`` to False::
|
||||
|
||||
>>> requests.get('https://kennethreitz.org', verify=False)
|
||||
<Response [200]>
|
||||
|
||||
Note that when ``verify`` is set to ``False``, requests will accept any TLS
|
||||
certificate presented by the server, and will ignore hostname mismatches
|
||||
and/or expired certificates, which will make your application vulnerable to
|
||||
man-in-the-middle (MitM) attacks. Setting verify to ``False`` may be useful
|
||||
during local development or testing.
|
||||
|
||||
By default, ``verify`` is set to True. Option ``verify`` only applies to host certs.
|
||||
|
||||
Client Side Certificates
|
||||
@@ -300,7 +305,7 @@ immediately. You can override this behaviour and defer downloading the response
|
||||
body until you access the :attr:`Response.content <requests.Response.content>`
|
||||
attribute with the ``stream`` parameter::
|
||||
|
||||
tarball_url = 'https://github.com/psf/requests/tarball/master'
|
||||
tarball_url = 'https://github.com/psf/requests/tarball/main'
|
||||
r = requests.get(tarball_url, stream=True)
|
||||
|
||||
At this point only the response headers have been downloaded and the connection
|
||||
@@ -441,7 +446,7 @@ argument.
|
||||
def print_url(r, *args, **kwargs):
|
||||
print(r.url)
|
||||
|
||||
If an error occurs while executing your callback, a warning is given.
|
||||
Your callback function must handle its own exceptions. Any unhandled exception won't be passed silently and thus should be handled by the code calling Requests.
|
||||
|
||||
If the callback function returns a value, it is assumed that it is to
|
||||
replace the data that was passed in. If the function doesn't return
|
||||
@@ -482,7 +487,7 @@ they are added.
|
||||
Custom Authentication
|
||||
---------------------
|
||||
|
||||
Requests allows you to use specify your own authentication mechanism.
|
||||
Requests allows you to specify your own authentication mechanism.
|
||||
|
||||
Any callable which is passed as the ``auth`` argument to a request method will
|
||||
have the opportunity to modify the request before it is dispatched.
|
||||
@@ -584,10 +589,26 @@ If you need to use a proxy, you can configure individual requests with the
|
||||
|
||||
requests.get('http://example.org', proxies=proxies)
|
||||
|
||||
You can also configure proxies by setting the environment variables
|
||||
``HTTP_PROXY`` and ``HTTPS_PROXY``.
|
||||
Alternatively you can configure it once for an entire
|
||||
:class:`Session <requests.Session>`::
|
||||
|
||||
::
|
||||
import requests
|
||||
|
||||
proxies = {
|
||||
'http': 'http://10.10.1.10:3128',
|
||||
'https': 'http://10.10.1.10:1080',
|
||||
}
|
||||
session = requests.Session()
|
||||
session.proxies.update(proxies)
|
||||
|
||||
session.get('http://example.org')
|
||||
|
||||
When the proxies configuration is not overridden in python as shown above,
|
||||
by default Requests relies on the proxy configuration defined by standard
|
||||
environment variables ``http_proxy``, ``https_proxy``, ``no_proxy`` and
|
||||
``curl_ca_bundle``. Uppercase variants of these variables are also supported.
|
||||
You can therefore set them to configure Requests (only set the ones relevant
|
||||
to your needs)::
|
||||
|
||||
$ export HTTP_PROXY="http://10.10.1.10:3128"
|
||||
$ export HTTPS_PROXY="http://10.10.1.10:1080"
|
||||
@@ -596,9 +617,17 @@ You can also configure proxies by setting the environment variables
|
||||
>>> import requests
|
||||
>>> requests.get('http://example.org')
|
||||
|
||||
To use HTTP Basic Auth with your proxy, use the `http://user:password@host/` syntax::
|
||||
To use HTTP Basic Auth with your proxy, use the `http://user:password@host/`
|
||||
syntax in any of the above configuration entries::
|
||||
|
||||
proxies = {'http': 'http://user:pass@10.10.1.10:3128/'}
|
||||
$ export HTTPS_PROXY="http://user:pass@10.10.1.10:1080"
|
||||
|
||||
$ python
|
||||
>>> proxies = {'http': 'http://user:pass@10.10.1.10:3128/'}
|
||||
|
||||
.. warning:: Storing sensitive username and password information in an
|
||||
environment variable or a version-controlled file is a security risk and is
|
||||
highly discouraged.
|
||||
|
||||
To give a proxy for a specific scheme and host, use the
|
||||
`scheme://hostname` form for the key. This will match for
|
||||
@@ -610,6 +639,23 @@ any request to the given scheme and exact hostname.
|
||||
|
||||
Note that proxy URLs must include the scheme.
|
||||
|
||||
Finally, note that using a proxy for https connections typically requires your
|
||||
local machine to trust the proxy's root certificate. By default the list of
|
||||
certificates trusted by Requests can be found with::
|
||||
|
||||
from requests.utils import DEFAULT_CA_BUNDLE_PATH
|
||||
print(DEFAULT_CA_BUNDLE_PATH)
|
||||
|
||||
You override this default certificate bundle by setting the standard
|
||||
``curl_ca_bundle`` environment variable to another file path::
|
||||
|
||||
$ export curl_ca_bundle="/usr/local/myproxy_info/cacert.pem"
|
||||
$ export https_proxy="http://10.10.1.10:1080"
|
||||
|
||||
$ python
|
||||
>>> import requests
|
||||
>>> requests.get('https://example.org')
|
||||
|
||||
SOCKS
|
||||
^^^^^
|
||||
|
||||
@@ -623,7 +669,7 @@ You can get the dependencies for this feature from ``pip``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ pip install requests[socks]
|
||||
$ python -m pip install requests[socks]
|
||||
|
||||
Once you've installed those dependencies, using a SOCKS proxy is just as easy
|
||||
as using a HTTP one::
|
||||
@@ -651,10 +697,22 @@ Encodings
|
||||
When you receive a response, Requests makes a guess at the encoding to
|
||||
use for decoding the response when you access the :attr:`Response.text
|
||||
<requests.Response.text>` attribute. Requests will first check for an
|
||||
encoding in the HTTP header, and if none is present, will use `chardet
|
||||
<https://pypi.org/project/chardet/>`_ to attempt to guess the encoding.
|
||||
encoding in the HTTP header, and if none is present, will use
|
||||
`charset_normalizer <https://pypi.org/project/charset_normalizer/>`_
|
||||
or `chardet <https://github.com/chardet/chardet>`_ to attempt to
|
||||
guess the encoding.
|
||||
|
||||
The only time Requests will not do this is if no explicit charset
|
||||
If ``chardet`` is installed, ``requests`` uses it, however for python3
|
||||
``chardet`` is no longer a mandatory dependency. The ``chardet``
|
||||
library is an LGPL-licenced dependency and some users of requests
|
||||
cannot depend on mandatory LGPL-licensed dependencies.
|
||||
|
||||
When you install ``request`` without specifying ``[use_chardet_on_py3]]`` extra,
|
||||
and ``chardet`` is not already installed, ``requests`` uses ``charset-normalizer``
|
||||
(MIT-licensed) to guess the encoding. For Python 2, ``requests`` uses only
|
||||
``chardet`` and is a mandatory dependency there.
|
||||
|
||||
The only time Requests will not guess the encoding is if no explicit charset
|
||||
is present in the HTTP headers **and** the ``Content-Type``
|
||||
header contains ``text``. In this situation, `RFC 2616
|
||||
<https://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7.1>`_ specifies
|
||||
@@ -698,12 +756,12 @@ So, GitHub returns JSON. That's great, we can use the :meth:`r.json
|
||||
>>> commit_data = r.json()
|
||||
|
||||
>>> print(commit_data.keys())
|
||||
[u'committer', u'author', u'url', u'tree', u'sha', u'parents', u'message']
|
||||
['committer', 'author', 'url', 'tree', 'sha', 'parents', 'message']
|
||||
|
||||
>>> print(commit_data[u'committer'])
|
||||
{u'date': u'2012-05-10T11:10:50-07:00', u'email': u'me@kennethreitz.com', u'name': u'Kenneth Reitz'}
|
||||
>>> print(commit_data['committer'])
|
||||
{'date': '2012-05-10T11:10:50-07:00', 'email': 'me@kennethreitz.com', 'name': 'Kenneth Reitz'}
|
||||
|
||||
>>> print(commit_data[u'message'])
|
||||
>>> print(commit_data['message'])
|
||||
makin' history
|
||||
|
||||
So far, so simple. Well, let's investigate the GitHub API a little bit. Now,
|
||||
@@ -746,26 +804,26 @@ this issue already exists, we will use it as an example. Let's start by getting
|
||||
|
||||
>>> issue = json.loads(r.text)
|
||||
|
||||
>>> print(issue[u'title'])
|
||||
>>> print(issue['title'])
|
||||
Feature any http verb in docs
|
||||
|
||||
>>> print(issue[u'comments'])
|
||||
>>> print(issue['comments'])
|
||||
3
|
||||
|
||||
Cool, we have three comments. Let's take a look at the last of them.
|
||||
|
||||
::
|
||||
|
||||
>>> r = requests.get(r.url + u'/comments')
|
||||
>>> r = requests.get(r.url + '/comments')
|
||||
>>> r.status_code
|
||||
200
|
||||
|
||||
>>> comments = r.json()
|
||||
|
||||
>>> print(comments[0].keys())
|
||||
[u'body', u'url', u'created_at', u'updated_at', u'user', u'id']
|
||||
['body', 'url', 'created_at', 'updated_at', 'user', 'id']
|
||||
|
||||
>>> print(comments[2][u'body'])
|
||||
>>> print(comments[2]['body'])
|
||||
Probably in the "advanced" section
|
||||
|
||||
Well, that seems like a silly place. Let's post a comment telling the poster
|
||||
@@ -773,7 +831,7 @@ that he's silly. Who is the poster, anyway?
|
||||
|
||||
::
|
||||
|
||||
>>> print(comments[2][u'user'][u'login'])
|
||||
>>> print(comments[2]['user']['login'])
|
||||
kennethreitz
|
||||
|
||||
OK, so let's tell this Kenneth guy that we think this example should go in the
|
||||
@@ -803,7 +861,7 @@ the very common Basic Auth.
|
||||
201
|
||||
|
||||
>>> content = r.json()
|
||||
>>> print(content[u'body'])
|
||||
>>> print(content['body'])
|
||||
Sounds great! I'll get right on it.
|
||||
|
||||
Brilliant. Oh, wait, no! I meant to add that it would take me a while, because
|
||||
@@ -959,8 +1017,8 @@ library to use SSLv3::
|
||||
num_pools=connections, maxsize=maxsize,
|
||||
block=block, ssl_version=ssl.PROTOCOL_SSLv3)
|
||||
|
||||
.. _`described here`: https://www.kennethreitz.org/essays/the-future-of-python-http
|
||||
.. _`urllib3`: https://github.com/shazow/urllib3
|
||||
.. _`described here`: https://kenreitz.org/essays/2012/06/14/the-future-of-python-http
|
||||
.. _`urllib3`: https://github.com/urllib3/urllib3
|
||||
|
||||
.. _blocking-or-nonblocking:
|
||||
|
||||
@@ -976,12 +1034,12 @@ response at a time. However, these calls will still block.
|
||||
|
||||
If you are concerned about the use of blocking IO, there are lots of projects
|
||||
out there that combine Requests with one of Python's asynchronicity frameworks.
|
||||
Some excellent examples are `requests-threads`_, `grequests`_, `requests-futures`_, and `requests-async`_.
|
||||
Some excellent examples are `requests-threads`_, `grequests`_, `requests-futures`_, and `httpx`_.
|
||||
|
||||
.. _`requests-threads`: https://github.com/requests/requests-threads
|
||||
.. _`grequests`: https://github.com/kennethreitz/grequests
|
||||
.. _`grequests`: https://github.com/spyoungtech/grequests
|
||||
.. _`requests-futures`: https://github.com/ross/requests-futures
|
||||
.. _`requests-async`: https://github.com/encode/requests-async
|
||||
.. _`httpx`: https://github.com/encode/httpx
|
||||
|
||||
Header Ordering
|
||||
---------------
|
||||
|
||||
@@ -3,8 +3,6 @@
|
||||
Authentication
|
||||
==============
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4258/35550409215_3b08d49d22_k_d.jpg
|
||||
|
||||
This document discusses using various kinds of authentication with Requests.
|
||||
|
||||
Many web services require authentication, and there are many different types.
|
||||
@@ -21,13 +19,14 @@ the simplest kind, and Requests supports it straight out of the box.
|
||||
Making requests with HTTP Basic Auth is very simple::
|
||||
|
||||
>>> from requests.auth import HTTPBasicAuth
|
||||
>>> requests.get('https://api.github.com/user', auth=HTTPBasicAuth('user', 'pass'))
|
||||
>>> basic = HTTPBasicAuth('user', 'pass')
|
||||
>>> requests.get('https://httpbin.org/basic-auth/user/pass', auth=basic)
|
||||
<Response [200]>
|
||||
|
||||
In fact, HTTP Basic Auth is so common that Requests provides a handy shorthand
|
||||
for using it::
|
||||
|
||||
>>> requests.get('https://api.github.com/user', auth=('user', 'pass'))
|
||||
>>> requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
|
||||
<Response [200]>
|
||||
|
||||
Providing the credentials in a tuple like this is exactly the same as the
|
||||
|
||||
@@ -3,23 +3,16 @@
|
||||
Installation of Requests
|
||||
========================
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4230/35550376215_da1bf77a8c_k_d.jpg
|
||||
|
||||
|
||||
This part of the documentation covers the installation of Requests.
|
||||
The first step to using any software package is getting it properly installed.
|
||||
|
||||
|
||||
$ pipenv install requests
|
||||
-------------------------
|
||||
$ python -m pip install requests
|
||||
--------------------------------
|
||||
|
||||
To install Requests, simply run this simple command in your terminal of choice::
|
||||
|
||||
$ pipenv install requests
|
||||
|
||||
If you don't have `pipenv <https://pipenv.kennethreitz.org>`_ installed (tisk tisk!), head over to the Pipenv website for installation instructions. Or, if you prefer to just use pip and don't have it installed,
|
||||
`this Python installation guide <https://docs.python-guide.org/starting/installation/>`_
|
||||
can guide you through the process.
|
||||
$ python -m pip install requests
|
||||
|
||||
Get the Source Code
|
||||
-------------------
|
||||
@@ -31,13 +24,13 @@ You can either clone the public repository::
|
||||
|
||||
$ git clone git://github.com/psf/requests.git
|
||||
|
||||
Or, download the `tarball <https://github.com/psf/requests/tarball/master>`_::
|
||||
Or, download the `tarball <https://github.com/psf/requests/tarball/main>`_::
|
||||
|
||||
$ curl -OL https://github.com/psf/requests/tarball/master
|
||||
$ curl -OL https://github.com/psf/requests/tarball/main
|
||||
# optionally, zipball is also available (for Windows users).
|
||||
|
||||
Once you have a copy of the source, you can embed it in your own Python
|
||||
package, or install it into your site-packages easily::
|
||||
|
||||
$ cd requests
|
||||
$ pip install .
|
||||
$ python -m pip install .
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
.. _introduction:
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg
|
||||
|
||||
Philosophy
|
||||
----------
|
||||
|
||||
Requests was developed with a few :pep:`20` idioms in mind.
|
||||
|
||||
|
||||
#. Beautiful is better than ugly.
|
||||
#. Explicit is better than implicit.
|
||||
#. Simple is better than complex.
|
||||
#. Complex is better than complicated.
|
||||
#. Readability counts.
|
||||
|
||||
All contributions to Requests should keep these important rules in mind.
|
||||
|
||||
.. _`apache2`:
|
||||
|
||||
Apache2 License
|
||||
---------------
|
||||
|
||||
A large number of open source projects you find today are `GPL Licensed`_.
|
||||
While the GPL has its time and place, it should most certainly not be your
|
||||
go-to license for your next open source project.
|
||||
|
||||
A project that is released as GPL cannot be used in any commercial product
|
||||
without the product itself also being offered as open source.
|
||||
|
||||
The MIT, BSD, ISC, and Apache2 licenses are great alternatives to the GPL
|
||||
that allow your open-source software to be used freely in proprietary,
|
||||
closed-source software.
|
||||
|
||||
Requests is released under terms of `Apache2 License`_.
|
||||
|
||||
.. _`GPL Licensed`: https://opensource.org/licenses/gpl-license.php
|
||||
.. _`Apache2 License`: https://opensource.org/licenses/Apache-2.0
|
||||
|
||||
|
||||
Requests License
|
||||
----------------
|
||||
|
||||
.. include:: ../../LICENSE
|
||||
@@ -3,8 +3,6 @@
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
.. image:: https://farm5.staticflickr.com/4259/35163667010_8bfcaef274_k_d.jpg
|
||||
|
||||
.. module:: requests.models
|
||||
|
||||
Eager to get started? This page gives a good introduction in how to get started
|
||||
@@ -39,12 +37,12 @@ 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('https://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('https://httpbin.org/put', data = {'key':'value'})
|
||||
>>> 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')
|
||||
@@ -93,7 +91,7 @@ again::
|
||||
|
||||
>>> r = requests.get('https://api.github.com/events')
|
||||
>>> r.text
|
||||
u'[{"repository":{"open_issues":0,"url":"https://github.com/...
|
||||
'[{"repository":{"open_issues":0,"url":"https://github.com/...
|
||||
|
||||
Requests will automatically decode content from the server. Most unicode
|
||||
charsets are seamlessly decoded.
|
||||
@@ -130,6 +128,9 @@ You can also access the response body as bytes, for non-text requests::
|
||||
|
||||
The ``gzip`` and ``deflate`` transfer-encodings are automatically decoded for you.
|
||||
|
||||
The ``br`` transfer-encoding is automatically decoded for you if a Brotli library
|
||||
like `brotli <https://pypi.org/project/brotli>`_ or `brotlicffi <https://pypi.org/project/brotli>`_ is installed.
|
||||
|
||||
For example, to create an image from binary data returned by a request, you can
|
||||
use the following code::
|
||||
|
||||
@@ -148,11 +149,13 @@ There's also a builtin JSON decoder, in case you're dealing with JSON data::
|
||||
|
||||
>>> r = requests.get('https://api.github.com/events')
|
||||
>>> r.json()
|
||||
[{u'repository': {u'open_issues': 0, u'url': 'https://github.com/...
|
||||
[{'repository': {'open_issues': 0, 'url': 'https://github.com/...
|
||||
|
||||
In case the JSON decoding fails, ``r.json()`` raises an exception. For example, if
|
||||
the response gets a 204 (No Content), or if the response contains invalid JSON,
|
||||
attempting ``r.json()`` raises ``ValueError: No JSON object could be decoded``.
|
||||
attempting ``r.json()`` raises ``requests.exceptions.JSONDecodeError``. This wrapper exception
|
||||
provides interoperability for multiple exceptions that may be thrown by different
|
||||
python versions and json serialization libraries.
|
||||
|
||||
It should be noted that the success of the call to ``r.json()`` does **not**
|
||||
indicate the success of the response. Some servers may return a JSON object in a
|
||||
@@ -215,7 +218,8 @@ Note: Custom headers are given less precedence than more specific sources of inf
|
||||
|
||||
* Authorization headers set with `headers=` will be overridden if credentials
|
||||
are specified in ``.netrc``, which in turn will be overridden by the ``auth=``
|
||||
parameter.
|
||||
parameter. Requests will search for the netrc file at `~/.netrc`, `~/_netrc`,
|
||||
or at the path specified by the `NETRC` environment variable.
|
||||
* Authorization headers will be removed if you get redirected off-host.
|
||||
* Proxy-Authorization headers will be overridden by proxy credentials provided in the URL.
|
||||
* Content-Length headers will be overridden when we can determine the length of the content.
|
||||
@@ -279,8 +283,12 @@ For example, the GitHub API v3 accepts JSON-Encoded POST/PATCH data::
|
||||
|
||||
>>> r = requests.post(url, data=json.dumps(payload))
|
||||
|
||||
Instead of encoding the ``dict`` yourself, you can also pass it directly using
|
||||
the ``json`` parameter (added in version 2.4.2) and it will be encoded automatically::
|
||||
Please note that the above code will NOT add the ``Content-Type`` header
|
||||
(so in particular it will NOT set it to ``application/json``).
|
||||
|
||||
If you need that header set and you don't want to encode the ``dict`` yourself,
|
||||
you can also pass it directly using the ``json`` parameter (added in version 2.4.2)
|
||||
and it will be encoded automatically:
|
||||
|
||||
>>> url = 'https://api.github.com/some/endpoint'
|
||||
>>> payload = {'some': 'data'}
|
||||
@@ -289,8 +297,6 @@ the ``json`` parameter (added in version 2.4.2) and it will be encoded automatic
|
||||
|
||||
Note, the ``json`` parameter is ignored if either ``data`` or ``files`` is passed.
|
||||
|
||||
Using the ``json`` parameter in the request will change the ``Content-Type`` in the header to ``application/json``.
|
||||
|
||||
POST a Multipart-Encoded File
|
||||
-----------------------------
|
||||
|
||||
|
||||
@@ -41,12 +41,20 @@ is at <https://requests.readthedocs.io>.
|
||||
"""
|
||||
|
||||
import urllib3
|
||||
import chardet
|
||||
import warnings
|
||||
from .exceptions import RequestsDependencyWarning
|
||||
|
||||
try:
|
||||
from charset_normalizer import __version__ as charset_normalizer_version
|
||||
except ImportError:
|
||||
charset_normalizer_version = None
|
||||
|
||||
def check_compatibility(urllib3_version, chardet_version):
|
||||
try:
|
||||
from chardet import __version__ as chardet_version
|
||||
except ImportError:
|
||||
chardet_version = None
|
||||
|
||||
def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version):
|
||||
urllib3_version = urllib3_version.split('.')
|
||||
assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git.
|
||||
|
||||
@@ -57,19 +65,24 @@ 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.25
|
||||
# urllib3 >= 1.21.1, <= 1.26
|
||||
assert major == 1
|
||||
assert minor >= 21
|
||||
assert minor <= 25
|
||||
|
||||
# Check chardet for compatibility.
|
||||
major, minor, patch = chardet_version.split('.')[:3]
|
||||
major, minor, patch = int(major), int(minor), int(patch)
|
||||
# chardet >= 3.0.2, < 3.1.0
|
||||
assert major == 3
|
||||
assert minor < 1
|
||||
assert patch >= 2
|
||||
assert minor <= 26
|
||||
|
||||
# Check charset_normalizer for compatibility.
|
||||
if chardet_version:
|
||||
major, minor, patch = chardet_version.split('.')[:3]
|
||||
major, minor, patch = int(major), int(minor), int(patch)
|
||||
# chardet_version >= 3.0.2, < 5.0.0
|
||||
assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0)
|
||||
elif charset_normalizer_version:
|
||||
major, minor, patch = charset_normalizer_version.split('.')[:3]
|
||||
major, minor, patch = int(major), int(minor), int(patch)
|
||||
# charset_normalizer >= 2.0.0 < 3.0.0
|
||||
assert (2, 0, 0) <= (major, minor, patch) < (3, 0, 0)
|
||||
else:
|
||||
raise Exception("You need either charset_normalizer or chardet installed")
|
||||
|
||||
def _check_cryptography(cryptography_version):
|
||||
# cryptography < 1.3.4
|
||||
@@ -84,20 +97,28 @@ def _check_cryptography(cryptography_version):
|
||||
|
||||
# Check imported dependencies for compatibility.
|
||||
try:
|
||||
check_compatibility(urllib3.__version__, chardet.__version__)
|
||||
check_compatibility(urllib3.__version__, chardet_version, charset_normalizer_version)
|
||||
except (AssertionError, ValueError):
|
||||
warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported "
|
||||
"version!".format(urllib3.__version__, chardet.__version__),
|
||||
warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
|
||||
"version!".format(urllib3.__version__, chardet_version, charset_normalizer_version),
|
||||
RequestsDependencyWarning)
|
||||
|
||||
# Attempt to enable urllib3's SNI support, if possible
|
||||
# Attempt to enable urllib3's fallback for SNI support
|
||||
# if the standard library doesn't support SNI or the
|
||||
# 'ssl' library isn't available.
|
||||
try:
|
||||
from urllib3.contrib import pyopenssl
|
||||
pyopenssl.inject_into_urllib3()
|
||||
try:
|
||||
import ssl
|
||||
except ImportError:
|
||||
ssl = None
|
||||
|
||||
# Check cryptography version
|
||||
from cryptography import __version__ as cryptography_version
|
||||
_check_cryptography(cryptography_version)
|
||||
if not getattr(ssl, "HAS_SNI", False):
|
||||
from urllib3.contrib import pyopenssl
|
||||
pyopenssl.inject_into_urllib3()
|
||||
|
||||
# Check cryptography version
|
||||
from cryptography import __version__ as cryptography_version
|
||||
_check_cryptography(cryptography_version)
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@@ -118,7 +139,7 @@ from .status_codes import codes
|
||||
from .exceptions import (
|
||||
RequestException, Timeout, URLRequired,
|
||||
TooManyRedirects, HTTPError, ConnectionError,
|
||||
FileModeWarning, ConnectTimeout, ReadTimeout
|
||||
FileModeWarning, ConnectTimeout, ReadTimeout, JSONDecodeError
|
||||
)
|
||||
|
||||
# Set default logging handler to avoid "No handler found" warnings.
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
__title__ = 'requests'
|
||||
__description__ = 'Python HTTP for Humans.'
|
||||
__url__ = 'https://requests.readthedocs.io'
|
||||
__version__ = '2.23.0'
|
||||
__build__ = 0x022300
|
||||
__version__ = '2.27.0'
|
||||
__build__ = 0x022700
|
||||
__author__ = 'Kenneth Reitz'
|
||||
__author_email__ = 'me@kennethreitz.org'
|
||||
__license__ = 'Apache 2.0'
|
||||
__copyright__ = 'Copyright 2020 Kenneth Reitz'
|
||||
__copyright__ = 'Copyright 2022 Kenneth Reitz'
|
||||
__cake__ = u'\u2728 \U0001f370 \u2728'
|
||||
|
||||
@@ -19,6 +19,7 @@ from urllib3.util.retry import Retry
|
||||
from urllib3.exceptions import ClosedPoolError
|
||||
from urllib3.exceptions import ConnectTimeoutError
|
||||
from urllib3.exceptions import HTTPError as _HTTPError
|
||||
from urllib3.exceptions import InvalidHeader as _InvalidHeader
|
||||
from urllib3.exceptions import MaxRetryError
|
||||
from urllib3.exceptions import NewConnectionError
|
||||
from urllib3.exceptions import ProxyError as _ProxyError
|
||||
@@ -37,7 +38,7 @@ from .structures import CaseInsensitiveDict
|
||||
from .cookies import extract_cookies_to_jar
|
||||
from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError,
|
||||
ProxyError, RetryError, InvalidSchema, InvalidProxyURL,
|
||||
InvalidURL)
|
||||
InvalidURL, InvalidHeader)
|
||||
from .auth import _basic_auth_str
|
||||
|
||||
try:
|
||||
@@ -457,9 +458,11 @@ class HTTPAdapter(BaseAdapter):
|
||||
low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT)
|
||||
|
||||
try:
|
||||
skip_host = 'Host' in request.headers
|
||||
low_conn.putrequest(request.method,
|
||||
url,
|
||||
skip_accept_encoding=True)
|
||||
skip_accept_encoding=True,
|
||||
skip_host=skip_host)
|
||||
|
||||
for header, value in request.headers.items():
|
||||
low_conn.putheader(header, value)
|
||||
@@ -527,6 +530,8 @@ class HTTPAdapter(BaseAdapter):
|
||||
raise SSLError(e, request=request)
|
||||
elif isinstance(e, ReadTimeoutError):
|
||||
raise ReadTimeout(e, request=request)
|
||||
elif isinstance(e, _InvalidHeader):
|
||||
raise InvalidHeader(e, request=request)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ def get(url, params=None, **kwargs):
|
||||
:rtype: requests.Response
|
||||
"""
|
||||
|
||||
kwargs.setdefault('allow_redirects', True)
|
||||
return request('get', url, params=params, **kwargs)
|
||||
|
||||
|
||||
@@ -85,7 +84,6 @@ def options(url, **kwargs):
|
||||
:rtype: requests.Response
|
||||
"""
|
||||
|
||||
kwargs.setdefault('allow_redirects', True)
|
||||
return request('options', url, **kwargs)
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@ This module handles import compatibility issues between Python 2 and
|
||||
Python 3.
|
||||
"""
|
||||
|
||||
import chardet
|
||||
try:
|
||||
import chardet
|
||||
except ImportError:
|
||||
import charset_normalizer as chardet
|
||||
|
||||
import sys
|
||||
|
||||
@@ -25,8 +28,10 @@ is_py2 = (_ver[0] == 2)
|
||||
#: Python 3.x?
|
||||
is_py3 = (_ver[0] == 3)
|
||||
|
||||
has_simplejson = False
|
||||
try:
|
||||
import simplejson as json
|
||||
has_simplejson = True
|
||||
except ImportError:
|
||||
import json
|
||||
|
||||
@@ -46,13 +51,13 @@ if is_py2:
|
||||
# Keep OrderedDict for backwards compatibility.
|
||||
from collections import Callable, Mapping, MutableMapping, OrderedDict
|
||||
|
||||
|
||||
builtin_str = str
|
||||
bytes = str
|
||||
str = unicode
|
||||
basestring = basestring
|
||||
numeric_types = (int, long, float)
|
||||
integer_types = (int, long)
|
||||
JSONDecodeError = ValueError
|
||||
|
||||
elif is_py3:
|
||||
from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag
|
||||
@@ -63,6 +68,10 @@ elif is_py3:
|
||||
# Keep OrderedDict for backwards compatibility.
|
||||
from collections import OrderedDict
|
||||
from collections.abc import Callable, Mapping, MutableMapping
|
||||
if has_simplejson:
|
||||
from simplejson import JSONDecodeError
|
||||
else:
|
||||
from json import JSONDecodeError
|
||||
|
||||
builtin_str = str
|
||||
str = str
|
||||
|
||||
@@ -8,6 +8,8 @@ This module contains the set of Requests' exceptions.
|
||||
"""
|
||||
from urllib3.exceptions import HTTPError as BaseHTTPError
|
||||
|
||||
from .compat import JSONDecodeError as CompatJSONDecodeError
|
||||
|
||||
|
||||
class RequestException(IOError):
|
||||
"""There was an ambiguous exception that occurred while handling your
|
||||
@@ -25,6 +27,14 @@ class RequestException(IOError):
|
||||
super(RequestException, self).__init__(*args, **kwargs)
|
||||
|
||||
|
||||
class InvalidJSONError(RequestException):
|
||||
"""A JSON error occurred."""
|
||||
|
||||
|
||||
class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError):
|
||||
"""Couldn't decode the text into json"""
|
||||
|
||||
|
||||
class HTTPError(RequestException):
|
||||
"""An HTTP error occurred."""
|
||||
|
||||
@@ -70,11 +80,11 @@ class TooManyRedirects(RequestException):
|
||||
|
||||
|
||||
class MissingSchema(RequestException, ValueError):
|
||||
"""The URL schema (e.g. http or https) is missing."""
|
||||
"""The URL scheme (e.g. http or https) is missing."""
|
||||
|
||||
|
||||
class InvalidSchema(RequestException, ValueError):
|
||||
"""See defaults.py for valid schemas."""
|
||||
"""The URL scheme provided is either invalid or unsupported."""
|
||||
|
||||
|
||||
class InvalidURL(RequestException, ValueError):
|
||||
@@ -94,11 +104,11 @@ class ChunkedEncodingError(RequestException):
|
||||
|
||||
|
||||
class ContentDecodingError(RequestException, BaseHTTPError):
|
||||
"""Failed to decode response content"""
|
||||
"""Failed to decode response content."""
|
||||
|
||||
|
||||
class StreamConsumedError(RequestException, TypeError):
|
||||
"""The content for this response was already consumed"""
|
||||
"""The content for this response was already consumed."""
|
||||
|
||||
|
||||
class RetryError(RequestException):
|
||||
@@ -106,21 +116,18 @@ class RetryError(RequestException):
|
||||
|
||||
|
||||
class UnrewindableBodyError(RequestException):
|
||||
"""Requests encountered an error when trying to rewind a body"""
|
||||
"""Requests encountered an error when trying to rewind a body."""
|
||||
|
||||
# Warnings
|
||||
|
||||
|
||||
class RequestsWarning(Warning):
|
||||
"""Base warning for Requests."""
|
||||
pass
|
||||
|
||||
|
||||
class FileModeWarning(RequestsWarning, DeprecationWarning):
|
||||
"""A file was opened in text mode, but Requests determined its binary length."""
|
||||
pass
|
||||
|
||||
|
||||
class RequestsDependencyWarning(RequestsWarning):
|
||||
"""An imported dependency doesn't match the expected version range."""
|
||||
pass
|
||||
|
||||
@@ -8,10 +8,19 @@ import ssl
|
||||
|
||||
import idna
|
||||
import urllib3
|
||||
import chardet
|
||||
|
||||
from . import __version__ as requests_version
|
||||
|
||||
try:
|
||||
import charset_normalizer
|
||||
except ImportError:
|
||||
charset_normalizer = None
|
||||
|
||||
try:
|
||||
import chardet
|
||||
except ImportError:
|
||||
chardet = None
|
||||
|
||||
try:
|
||||
from urllib3.contrib import pyopenssl
|
||||
except ImportError:
|
||||
@@ -71,7 +80,12 @@ def info():
|
||||
|
||||
implementation_info = _implementation()
|
||||
urllib3_info = {'version': urllib3.__version__}
|
||||
chardet_info = {'version': chardet.__version__}
|
||||
charset_normalizer_info = {'version': None}
|
||||
chardet_info = {'version': None}
|
||||
if charset_normalizer:
|
||||
charset_normalizer_info = {'version': charset_normalizer.__version__}
|
||||
if chardet:
|
||||
chardet_info = {'version': chardet.__version__}
|
||||
|
||||
pyopenssl_info = {
|
||||
'version': None,
|
||||
@@ -99,9 +113,11 @@ def info():
|
||||
'implementation': implementation_info,
|
||||
'system_ssl': system_ssl_info,
|
||||
'using_pyopenssl': pyopenssl is not None,
|
||||
'using_charset_normalizer': chardet is None,
|
||||
'pyOpenSSL': pyopenssl_info,
|
||||
'urllib3': urllib3_info,
|
||||
'chardet': chardet_info,
|
||||
'charset_normalizer': charset_normalizer_info,
|
||||
'cryptography': cryptography_info,
|
||||
'idna': idna_info,
|
||||
'requests': {
|
||||
|
||||
@@ -29,7 +29,9 @@ from .auth import HTTPBasicAuth
|
||||
from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar
|
||||
from .exceptions import (
|
||||
HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError,
|
||||
ContentDecodingError, ConnectionError, StreamConsumedError)
|
||||
ContentDecodingError, ConnectionError, StreamConsumedError,
|
||||
InvalidJSONError)
|
||||
from .exceptions import JSONDecodeError as RequestsJSONDecodeError
|
||||
from ._internal_utils import to_native_string, unicode_is_ascii
|
||||
from .utils import (
|
||||
guess_filename, get_auth_from_url, requote_uri,
|
||||
@@ -38,7 +40,7 @@ from .utils import (
|
||||
from .compat import (
|
||||
Callable, Mapping,
|
||||
cookielib, urlunparse, urlsplit, urlencode, str, bytes,
|
||||
is_py2, chardet, builtin_str, basestring)
|
||||
is_py2, chardet, builtin_str, basestring, JSONDecodeError)
|
||||
from .compat import json as complexjson
|
||||
from .status_codes import codes
|
||||
|
||||
@@ -273,7 +275,9 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
"""The fully mutable :class:`PreparedRequest <PreparedRequest>` object,
|
||||
containing the exact bytes that will be sent to the server.
|
||||
|
||||
Generated from either a :class:`Request <Request>` object or manually.
|
||||
Instances are generated from a :class:`Request <Request>` object, and
|
||||
should not be instantiated manually; doing so may produce undesirable
|
||||
effects.
|
||||
|
||||
Usage::
|
||||
|
||||
@@ -382,7 +386,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
raise InvalidURL(*e.args)
|
||||
|
||||
if not scheme:
|
||||
error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?")
|
||||
error = ("Invalid URL {0!r}: No scheme supplied. Perhaps you meant http://{0}?")
|
||||
error = error.format(to_native_string(url, 'utf8'))
|
||||
|
||||
raise MissingSchema(error)
|
||||
@@ -399,7 +403,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
host = self._get_idna_encoded_host(host)
|
||||
except UnicodeError:
|
||||
raise InvalidURL('URL has an invalid label.')
|
||||
elif host.startswith(u'*'):
|
||||
elif host.startswith((u'*', u'.')):
|
||||
raise InvalidURL('URL has an invalid label.')
|
||||
|
||||
# Carefully reconstruct the network location
|
||||
@@ -464,7 +468,12 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
# urllib3 requires a bytes-like body. Python 2's json.dumps
|
||||
# provides this natively, but Python 3 gives a Unicode string.
|
||||
content_type = 'application/json'
|
||||
body = complexjson.dumps(json)
|
||||
|
||||
try:
|
||||
body = complexjson.dumps(json, allow_nan=False)
|
||||
except ValueError as ve:
|
||||
raise InvalidJSONError(ve, request=self)
|
||||
|
||||
if not isinstance(body, bytes):
|
||||
body = body.encode('utf-8')
|
||||
|
||||
@@ -473,12 +482,12 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
|
||||
not isinstance(data, (basestring, list, tuple, Mapping))
|
||||
])
|
||||
|
||||
try:
|
||||
length = super_len(data)
|
||||
except (TypeError, AttributeError, UnsupportedOperation):
|
||||
length = None
|
||||
|
||||
if is_stream:
|
||||
try:
|
||||
length = super_len(data)
|
||||
except (TypeError, AttributeError, UnsupportedOperation):
|
||||
length = None
|
||||
|
||||
body = data
|
||||
|
||||
if getattr(body, 'tell', None) is not None:
|
||||
@@ -724,7 +733,7 @@ class Response(object):
|
||||
|
||||
@property
|
||||
def apparent_encoding(self):
|
||||
"""The apparent encoding, provided by the chardet library."""
|
||||
"""The apparent encoding, provided by the charset_normalizer or chardet libraries."""
|
||||
return chardet.detect(self.content)['encoding']
|
||||
|
||||
def iter_content(self, chunk_size=1, decode_unicode=False):
|
||||
@@ -838,7 +847,7 @@ class Response(object):
|
||||
"""Content of the response, in unicode.
|
||||
|
||||
If Response.encoding is None, encoding will be guessed using
|
||||
``chardet``.
|
||||
``charset_normalizer`` or ``chardet``.
|
||||
|
||||
The encoding of the response content is determined based solely on HTTP
|
||||
headers, following RFC 2616 to the letter. If you can take advantage of
|
||||
@@ -875,13 +884,14 @@ class Response(object):
|
||||
r"""Returns the json-encoded content of a response, if any.
|
||||
|
||||
:param \*\*kwargs: Optional arguments that ``json.loads`` takes.
|
||||
:raises ValueError: If the response body does not contain valid json.
|
||||
:raises requests.exceptions.JSONDecodeError: If the response body does not
|
||||
contain valid json.
|
||||
"""
|
||||
|
||||
if not self.encoding and self.content and len(self.content) > 3:
|
||||
# No encoding set. JSON RFC 4627 section 3 states we should expect
|
||||
# UTF-8, -16 or -32. Detect which one to use; If the detection or
|
||||
# decoding fails, fall back to `self.text` (using chardet to make
|
||||
# decoding fails, fall back to `self.text` (using charset_normalizer to make
|
||||
# a best guess).
|
||||
encoding = guess_json_utf(self.content)
|
||||
if encoding is not None:
|
||||
@@ -895,7 +905,16 @@ class Response(object):
|
||||
# and the server didn't bother to tell us what codec *was*
|
||||
# used.
|
||||
pass
|
||||
return complexjson.loads(self.text, **kwargs)
|
||||
|
||||
try:
|
||||
return complexjson.loads(self.text, **kwargs)
|
||||
except JSONDecodeError as e:
|
||||
# Catch JSON-related errors and raise as requests.JSONDecodeError
|
||||
# This aliases json.JSONDecodeError and simplejson.JSONDecodeError
|
||||
if is_py2: # e is a ValueError
|
||||
raise RequestsJSONDecodeError(e.message)
|
||||
else:
|
||||
raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
|
||||
|
||||
@property
|
||||
def links(self):
|
||||
@@ -916,7 +935,7 @@ class Response(object):
|
||||
return l
|
||||
|
||||
def raise_for_status(self):
|
||||
"""Raises stored :class:`HTTPError`, if one occurred."""
|
||||
"""Raises :class:`HTTPError`, if one occurred."""
|
||||
|
||||
http_error_msg = ''
|
||||
if isinstance(self.reason, bytes):
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
import sys
|
||||
|
||||
try:
|
||||
import chardet
|
||||
except ImportError:
|
||||
import charset_normalizer as chardet
|
||||
import warnings
|
||||
|
||||
warnings.filterwarnings('ignore', 'Trying to detect', module='charset_normalizer')
|
||||
|
||||
# This code exists for backwards compatibility reasons.
|
||||
# I don't like it either. Just look the other way. :)
|
||||
|
||||
for package in ('urllib3', 'idna', 'chardet'):
|
||||
for package in ('urllib3', 'idna'):
|
||||
locals()[package] = __import__(package)
|
||||
# This traversal is apparently necessary such that the identities are
|
||||
# preserved (requests.packages.urllib3.* is urllib3.*)
|
||||
@@ -11,4 +19,8 @@ for package in ('urllib3', 'idna', 'chardet'):
|
||||
if mod == package or mod.startswith(package + '.'):
|
||||
sys.modules['requests.packages.' + mod] = sys.modules[mod]
|
||||
|
||||
target = chardet.__name__
|
||||
for mod in list(sys.modules):
|
||||
if mod == target or mod.startswith(target + '.'):
|
||||
sys.modules['requests.packages.' + target.replace(target, 'chardet')] = sys.modules[mod]
|
||||
# Kinda cool, though, right?
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
requests.session
|
||||
~~~~~~~~~~~~~~~~
|
||||
requests.sessions
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
This module provides a Session object to manage and persist settings across
|
||||
requests (cookies, auth, proxies).
|
||||
@@ -29,7 +29,7 @@ from .adapters import HTTPAdapter
|
||||
|
||||
from .utils import (
|
||||
requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies,
|
||||
get_auth_from_url, rewind_body
|
||||
get_auth_from_url, rewind_body, resolve_proxies
|
||||
)
|
||||
|
||||
from .status_codes import codes
|
||||
@@ -269,7 +269,6 @@ class SessionRedirectMixin(object):
|
||||
if new_auth is not None:
|
||||
prepared_request.prepare_auth(new_auth)
|
||||
|
||||
|
||||
def rebuild_proxies(self, prepared_request, proxies):
|
||||
"""This method re-evaluates the proxy configuration by considering the
|
||||
environment variables. If we are redirected to a URL covered by
|
||||
@@ -282,21 +281,9 @@ class SessionRedirectMixin(object):
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
proxies = proxies if proxies is not None else {}
|
||||
headers = prepared_request.headers
|
||||
url = prepared_request.url
|
||||
scheme = urlparse(url).scheme
|
||||
new_proxies = proxies.copy()
|
||||
no_proxy = proxies.get('no_proxy')
|
||||
|
||||
bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy)
|
||||
if self.trust_env and not bypass_proxy:
|
||||
environ_proxies = get_environ_proxies(url, no_proxy=no_proxy)
|
||||
|
||||
proxy = environ_proxies.get(scheme, environ_proxies.get('all'))
|
||||
|
||||
if proxy:
|
||||
new_proxies.setdefault(scheme, proxy)
|
||||
scheme = urlparse(prepared_request.url).scheme
|
||||
new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env)
|
||||
|
||||
if 'Proxy-Authorization' in headers:
|
||||
del headers['Proxy-Authorization']
|
||||
@@ -387,6 +374,13 @@ class Session(SessionRedirectMixin):
|
||||
self.stream = False
|
||||
|
||||
#: SSL Verification default.
|
||||
#: Defaults to `True`, requiring requests to verify the TLS certificate at the
|
||||
#: remote end.
|
||||
#: If verify is set to `False`, requests will accept any TLS certificate
|
||||
#: presented by the server, and will ignore hostname mismatches and/or
|
||||
#: expired certificates, which will make your application vulnerable to
|
||||
#: man-in-the-middle (MitM) attacks.
|
||||
#: Only set this to `False` for testing.
|
||||
self.verify = True
|
||||
|
||||
#: SSL client certificate default, if String, path to ssl client
|
||||
@@ -495,7 +489,12 @@ class Session(SessionRedirectMixin):
|
||||
content. Defaults to ``False``.
|
||||
:param verify: (optional) Either a boolean, in which case it controls whether we verify
|
||||
the server's TLS certificate, or a string, in which case it must be a path
|
||||
to a CA bundle to use. Defaults to ``True``.
|
||||
to a CA bundle to use. Defaults to ``True``. When set to
|
||||
``False``, requests will accept any TLS certificate presented by
|
||||
the server, and will ignore hostname mismatches and/or expired
|
||||
certificates, which will make your application vulnerable to
|
||||
man-in-the-middle (MitM) attacks. Setting verify to ``False``
|
||||
may be useful during local development or testing.
|
||||
:param cert: (optional) if String, path to ssl client cert file (.pem).
|
||||
If Tuple, ('cert', 'key') pair.
|
||||
:rtype: requests.Response
|
||||
@@ -621,7 +620,10 @@ class Session(SessionRedirectMixin):
|
||||
kwargs.setdefault('stream', self.stream)
|
||||
kwargs.setdefault('verify', self.verify)
|
||||
kwargs.setdefault('cert', self.cert)
|
||||
kwargs.setdefault('proxies', self.proxies)
|
||||
if 'proxies' not in kwargs:
|
||||
kwargs['proxies'] = resolve_proxies(
|
||||
request, self.proxies, self.trust_env
|
||||
)
|
||||
|
||||
# It's possible that users might accidentally send a Request object.
|
||||
# Guard against that specific failure case.
|
||||
@@ -658,11 +660,13 @@ class Session(SessionRedirectMixin):
|
||||
|
||||
extract_cookies_to_jar(self.cookies, request, r.raw)
|
||||
|
||||
# Redirect resolving generator.
|
||||
gen = self.resolve_redirects(r, request, **kwargs)
|
||||
|
||||
# Resolve redirects if allowed.
|
||||
history = [resp for resp in gen] if allow_redirects else []
|
||||
if allow_redirects:
|
||||
# Redirect resolving generator.
|
||||
gen = self.resolve_redirects(r, request, **kwargs)
|
||||
history = [resp for resp in gen]
|
||||
else:
|
||||
history = []
|
||||
|
||||
# Shuffle things around if there's history.
|
||||
if history:
|
||||
|
||||
@@ -20,6 +20,8 @@ import tempfile
|
||||
import warnings
|
||||
import zipfile
|
||||
from collections import OrderedDict
|
||||
from urllib3.util import make_headers
|
||||
from urllib3.util import parse_url
|
||||
|
||||
from .__version__ import __version__
|
||||
from . import certs
|
||||
@@ -41,6 +43,11 @@ DEFAULT_CA_BUNDLE_PATH = certs.where()
|
||||
|
||||
DEFAULT_PORTS = {'http': 80, 'https': 443}
|
||||
|
||||
# Ensure that ', ' is used to preserve previous delimiter behavior.
|
||||
DEFAULT_ACCEPT_ENCODING = ", ".join(
|
||||
re.split(r",\s*", make_headers(accept_encoding=True)["accept-encoding"])
|
||||
)
|
||||
|
||||
|
||||
if sys.platform == 'win32':
|
||||
# provide a proxy_bypass version on Windows without DNS lookups
|
||||
@@ -118,7 +125,10 @@ def super_len(o):
|
||||
elif hasattr(o, 'fileno'):
|
||||
try:
|
||||
fileno = o.fileno()
|
||||
except io.UnsupportedOperation:
|
||||
except (io.UnsupportedOperation, AttributeError):
|
||||
# AttributeError is a surprising exception, seeing as how we've just checked
|
||||
# that `hasattr(o, 'fileno')`. It happens for objects obtained via
|
||||
# `Tarfile.extractfile()`, per issue 5229.
|
||||
pass
|
||||
else:
|
||||
total_length = os.fstat(fileno).st_size
|
||||
@@ -148,7 +158,7 @@ def super_len(o):
|
||||
current_position = total_length
|
||||
else:
|
||||
if hasattr(o, 'seek') and total_length is None:
|
||||
# StringIO and BytesIO have seek but no useable fileno
|
||||
# StringIO and BytesIO have seek but no usable fileno
|
||||
try:
|
||||
# seek to end of file
|
||||
o.seek(0, 2)
|
||||
@@ -169,14 +179,20 @@ def super_len(o):
|
||||
def get_netrc_auth(url, raise_errors=False):
|
||||
"""Returns the Requests tuple auth for a given url from netrc."""
|
||||
|
||||
netrc_file = os.environ.get('NETRC')
|
||||
if netrc_file is not None:
|
||||
netrc_locations = (netrc_file,)
|
||||
else:
|
||||
netrc_locations = ('~/{}'.format(f) for f in NETRC_FILES)
|
||||
|
||||
try:
|
||||
from netrc import netrc, NetrcParseError
|
||||
|
||||
netrc_path = None
|
||||
|
||||
for f in NETRC_FILES:
|
||||
for f in netrc_locations:
|
||||
try:
|
||||
loc = os.path.expanduser('~/{}'.format(f))
|
||||
loc = os.path.expanduser(f)
|
||||
except KeyError:
|
||||
# os.path.expanduser can fail when $HOME is undefined and
|
||||
# getpwuid fails. See https://bugs.python.org/issue20164 &
|
||||
@@ -212,7 +228,7 @@ def get_netrc_auth(url, raise_errors=False):
|
||||
if raise_errors:
|
||||
raise
|
||||
|
||||
# AppEngine hackiness.
|
||||
# App Engine hackiness.
|
||||
except (ImportError, AttributeError):
|
||||
pass
|
||||
|
||||
@@ -239,6 +255,10 @@ def extract_zipped_paths(path):
|
||||
archive, member = os.path.split(path)
|
||||
while archive and not os.path.exists(archive):
|
||||
archive, prefix = os.path.split(archive)
|
||||
if not prefix:
|
||||
# If we don't check for an empty prefix after the split (in other words, archive remains unchanged after the split),
|
||||
# we _can_ end up in an infinite loop on a rare corner case affecting a small number of users
|
||||
break
|
||||
member = '/'.join([prefix, member])
|
||||
|
||||
if not zipfile.is_zipfile(archive):
|
||||
@@ -250,13 +270,28 @@ def extract_zipped_paths(path):
|
||||
|
||||
# we have a valid zip archive and a valid member of that archive
|
||||
tmp = tempfile.gettempdir()
|
||||
extracted_path = os.path.join(tmp, *member.split('/'))
|
||||
extracted_path = os.path.join(tmp, member.split('/')[-1])
|
||||
if not os.path.exists(extracted_path):
|
||||
extracted_path = zip_file.extract(member, path=tmp)
|
||||
|
||||
# use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition
|
||||
with atomic_open(extracted_path) as file_handler:
|
||||
file_handler.write(zip_file.read(member))
|
||||
return extracted_path
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def atomic_open(filename):
|
||||
"""Write a file to the disk in an atomic fashion"""
|
||||
replacer = os.rename if sys.version_info[0] == 2 else os.replace
|
||||
tmp_descriptor, tmp_name = tempfile.mkstemp(dir=os.path.dirname(filename))
|
||||
try:
|
||||
with os.fdopen(tmp_descriptor, 'wb') as tmp_handler:
|
||||
yield tmp_handler
|
||||
replacer(tmp_name, filename)
|
||||
except BaseException:
|
||||
os.remove(tmp_name)
|
||||
raise
|
||||
|
||||
|
||||
def from_key_val_list(value):
|
||||
"""Take an object and test to see if it can be represented as a
|
||||
dictionary. Unless it can not be represented as such, return an
|
||||
@@ -497,6 +532,10 @@ def get_encoding_from_headers(headers):
|
||||
if 'text' in content_type:
|
||||
return 'ISO-8859-1'
|
||||
|
||||
if 'application/json' in content_type:
|
||||
# Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset
|
||||
return 'utf-8'
|
||||
|
||||
|
||||
def stream_decode_response_unicode(iterator, r):
|
||||
"""Stream decodes a iterator."""
|
||||
@@ -795,6 +834,33 @@ def select_proxy(url, proxies):
|
||||
return proxy
|
||||
|
||||
|
||||
def resolve_proxies(request, proxies, trust_env=True):
|
||||
"""This method takes proxy information from a request and configuration
|
||||
input to resolve a mapping of target proxies. This will consider settings
|
||||
such a NO_PROXY to strip proxy configurations.
|
||||
|
||||
:param request: Request or PreparedRequest
|
||||
:param proxies: A dictionary of schemes or schemes and hosts to proxy URLs
|
||||
:param trust_env: Boolean declaring whether to trust environment configs
|
||||
|
||||
:rtype: dict
|
||||
"""
|
||||
proxies = proxies if proxies is not None else {}
|
||||
url = request.url
|
||||
scheme = urlparse(url).scheme
|
||||
no_proxy = proxies.get('no_proxy')
|
||||
new_proxies = proxies.copy()
|
||||
|
||||
if trust_env and not should_bypass_proxies(url, no_proxy=no_proxy):
|
||||
environ_proxies = get_environ_proxies(url, no_proxy=no_proxy)
|
||||
|
||||
proxy = environ_proxies.get(scheme, environ_proxies.get('all'))
|
||||
|
||||
if proxy:
|
||||
new_proxies.setdefault(scheme, proxy)
|
||||
return new_proxies
|
||||
|
||||
|
||||
def default_user_agent(name="python-requests"):
|
||||
"""
|
||||
Return a string representing the default user agent.
|
||||
@@ -810,7 +876,7 @@ def default_headers():
|
||||
"""
|
||||
return CaseInsensitiveDict({
|
||||
'User-Agent': default_user_agent(),
|
||||
'Accept-Encoding': ', '.join(('gzip', 'deflate')),
|
||||
'Accept-Encoding': DEFAULT_ACCEPT_ENCODING,
|
||||
'Accept': '*/*',
|
||||
'Connection': 'keep-alive',
|
||||
})
|
||||
@@ -897,15 +963,23 @@ def prepend_scheme_if_needed(url, new_scheme):
|
||||
|
||||
:rtype: str
|
||||
"""
|
||||
scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme)
|
||||
parsed = parse_url(url)
|
||||
scheme, auth, host, port, path, query, fragment = parsed
|
||||
|
||||
# urlparse is a finicky beast, and sometimes decides that there isn't a
|
||||
# netloc present. Assume that it's being over-cautious, and switch netloc
|
||||
# and path if urlparse decided there was no netloc.
|
||||
# A defect in urlparse determines that there isn't a netloc present in some
|
||||
# urls. We previously assumed parsing was overly cautious, and swapped the
|
||||
# netloc and path. Due to a lack of tests on the original defect, this is
|
||||
# maintained with parse_url for backwards compatibility.
|
||||
netloc = parsed.netloc
|
||||
if not netloc:
|
||||
netloc, path = path, netloc
|
||||
|
||||
return urlunparse((scheme, netloc, path, params, query, fragment))
|
||||
if scheme is None:
|
||||
scheme = new_scheme
|
||||
if path is None:
|
||||
path = ''
|
||||
|
||||
return urlunparse((scheme, netloc, path, '', query, fragment))
|
||||
|
||||
|
||||
def get_auth_from_url(url):
|
||||
|
||||
8
requirements-dev.txt
Normal file
8
requirements-dev.txt
Normal file
@@ -0,0 +1,8 @@
|
||||
pytest>=2.8.0,<=6.2.5
|
||||
pytest-cov
|
||||
pytest-httpbin==1.0.0
|
||||
pytest-mock==2.0.0
|
||||
httpbin==0.7.0
|
||||
Flask>=1.0,<2.0
|
||||
trustme
|
||||
wheel
|
||||
29
setup.py
29
setup.py
@@ -1,7 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# Learn more: https://github.com/kennethreitz/setup.py
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
from codecs import open
|
||||
@@ -42,9 +41,11 @@ if sys.argv[-1] == 'publish':
|
||||
packages = ['requests']
|
||||
|
||||
requires = [
|
||||
'chardet>=3.0.2,<4',
|
||||
'idna>=2.5,<3',
|
||||
'urllib3>=1.21.1,<1.26,!=1.25.0,!=1.25.1',
|
||||
'charset_normalizer~=2.0.0; python_version >= "3"',
|
||||
'chardet>=3.0.2,<5; python_version < "3"',
|
||||
'idna>=2.5,<3; python_version < "3"',
|
||||
'idna>=2.5,<4; python_version >= "3"',
|
||||
'urllib3>=1.21.1,<1.27',
|
||||
'certifi>=2017.4.17'
|
||||
|
||||
]
|
||||
@@ -63,8 +64,6 @@ with open(os.path.join(here, 'requests', '__version__.py'), 'r', 'utf-8') as f:
|
||||
|
||||
with open('README.md', 'r', 'utf-8') as f:
|
||||
readme = f.read()
|
||||
with open('HISTORY.md', 'r', 'utf-8') as f:
|
||||
history = f.read()
|
||||
|
||||
setup(
|
||||
name=about['__title__'],
|
||||
@@ -76,35 +75,41 @@ setup(
|
||||
author_email=about['__author_email__'],
|
||||
url=about['__url__'],
|
||||
packages=packages,
|
||||
package_data={'': ['LICENSE', 'NOTICE'], 'requests': ['*.pem']},
|
||||
package_data={'': ['LICENSE', 'NOTICE']},
|
||||
package_dir={'requests': 'requests'},
|
||||
include_package_data=True,
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*",
|
||||
python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*",
|
||||
install_requires=requires,
|
||||
license=about['__license__'],
|
||||
zip_safe=False,
|
||||
classifiers=[
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'Environment :: Web Environment',
|
||||
'Intended Audience :: Developers',
|
||||
'Natural Language :: English',
|
||||
'License :: OSI Approved :: Apache Software License',
|
||||
'Natural Language :: English',
|
||||
'Operating System :: OS Independent',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 2',
|
||||
'Programming Language :: Python :: 2.7',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
'Programming Language :: Python :: 3.9',
|
||||
'Programming Language :: Python :: 3.10',
|
||||
'Programming Language :: Python :: Implementation :: CPython',
|
||||
'Programming Language :: Python :: Implementation :: PyPy'
|
||||
'Programming Language :: Python :: Implementation :: PyPy',
|
||||
'Topic :: Internet :: WWW/HTTP',
|
||||
'Topic :: Software Development :: Libraries',
|
||||
],
|
||||
cmdclass={'test': PyTest},
|
||||
tests_require=test_requirements,
|
||||
extras_require={
|
||||
'security': ['pyOpenSSL >= 0.14', 'cryptography>=1.3.4'],
|
||||
'security': [],
|
||||
'socks': ['PySocks>=1.5.6, !=1.5.7'],
|
||||
'socks:sys_platform == "win32" and python_version == "2.7"': ['win_inet_pton'],
|
||||
'use_chardet_on_py3': ['chardet>=3.0.2,<5']
|
||||
},
|
||||
project_urls={
|
||||
'Documentation': 'https://requests.readthedocs.io',
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
try:
|
||||
from http.server import HTTPServer
|
||||
from http.server import SimpleHTTPRequestHandler
|
||||
except ImportError:
|
||||
from BaseHTTPServer import HTTPServer
|
||||
from SimpleHTTPServer import SimpleHTTPRequestHandler
|
||||
|
||||
import ssl
|
||||
import tempfile
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
from requests.compat import urljoin
|
||||
|
||||
@@ -22,3 +33,29 @@ def httpbin(httpbin):
|
||||
@pytest.fixture
|
||||
def httpbin_secure(httpbin_secure):
|
||||
return prepare_url(httpbin_secure)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def nosan_server(tmp_path_factory):
|
||||
# delay importing until the fixture in order to make it possible
|
||||
# to deselect the test via command-line when trustme is not available
|
||||
import trustme
|
||||
|
||||
tmpdir = tmp_path_factory.mktemp("certs")
|
||||
ca = trustme.CA()
|
||||
# only commonName, no subjectAltName
|
||||
server_cert = ca.issue_cert(common_name=u"localhost")
|
||||
ca_bundle = str(tmpdir / "ca.pem")
|
||||
ca.cert_pem.write_to_path(ca_bundle)
|
||||
|
||||
context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
|
||||
server_cert.configure_cert(context)
|
||||
server = HTTPServer(("localhost", 0), SimpleHTTPRequestHandler)
|
||||
server.socket = context.wrap_socket(server.socket, server_side=True)
|
||||
server_thread = threading.Thread(target=server.serve_forever)
|
||||
server_thread.start()
|
||||
|
||||
yield "localhost", server.server_address[1], ca_bundle
|
||||
|
||||
server.shutdown()
|
||||
server_thread.join()
|
||||
|
||||
@@ -9,6 +9,18 @@ from tests.testserver.server import Server, consume_socket_content
|
||||
from .utils import override_environ
|
||||
|
||||
|
||||
def echo_response_handler(sock):
|
||||
"""Simple handler that will take request and echo it back to requester."""
|
||||
request_content = consume_socket_content(sock, timeout=0.5)
|
||||
|
||||
text_200 = (
|
||||
b'HTTP/1.1 200 OK\r\n'
|
||||
b'Content-Length: %d\r\n\r\n'
|
||||
b'%s'
|
||||
) % (len(request_content), request_content)
|
||||
sock.send(text_200)
|
||||
|
||||
|
||||
def test_chunked_upload():
|
||||
"""can safely send generators"""
|
||||
close_server = threading.Event()
|
||||
@@ -24,6 +36,90 @@ def test_chunked_upload():
|
||||
assert r.request.headers['Transfer-Encoding'] == 'chunked'
|
||||
|
||||
|
||||
def test_chunked_encoding_error():
|
||||
"""get a ChunkedEncodingError if the server returns a bad response"""
|
||||
|
||||
def incomplete_chunked_response_handler(sock):
|
||||
request_content = consume_socket_content(sock, timeout=0.5)
|
||||
|
||||
# The server never ends the request and doesn't provide any valid chunks
|
||||
sock.send(b"HTTP/1.1 200 OK\r\n" +
|
||||
b"Transfer-Encoding: chunked\r\n")
|
||||
|
||||
return request_content
|
||||
|
||||
close_server = threading.Event()
|
||||
server = Server(incomplete_chunked_response_handler)
|
||||
|
||||
with server as (host, port):
|
||||
url = 'http://{}:{}/'.format(host, port)
|
||||
with pytest.raises(requests.exceptions.ChunkedEncodingError):
|
||||
r = requests.get(url)
|
||||
close_server.set() # release server block
|
||||
|
||||
|
||||
def test_chunked_upload_uses_only_specified_host_header():
|
||||
"""Ensure we use only the specified Host header for chunked requests."""
|
||||
close_server = threading.Event()
|
||||
server = Server(echo_response_handler, wait_to_close_event=close_server)
|
||||
|
||||
data = iter([b'a', b'b', b'c'])
|
||||
custom_host = 'sample-host'
|
||||
|
||||
with server as (host, port):
|
||||
url = 'http://{}:{}/'.format(host, port)
|
||||
r = requests.post(url, data=data, headers={'Host': custom_host}, stream=True)
|
||||
close_server.set() # release server block
|
||||
|
||||
expected_header = b'Host: %s\r\n' % custom_host.encode('utf-8')
|
||||
assert expected_header in r.content
|
||||
assert r.content.count(b'Host: ') == 1
|
||||
|
||||
|
||||
def test_chunked_upload_doesnt_skip_host_header():
|
||||
"""Ensure we don't omit all Host headers with chunked requests."""
|
||||
close_server = threading.Event()
|
||||
server = Server(echo_response_handler, wait_to_close_event=close_server)
|
||||
|
||||
data = iter([b'a', b'b', b'c'])
|
||||
|
||||
with server as (host, port):
|
||||
expected_host = '{}:{}'.format(host, port)
|
||||
url = 'http://{}:{}/'.format(host, port)
|
||||
r = requests.post(url, data=data, stream=True)
|
||||
close_server.set() # release server block
|
||||
|
||||
expected_header = b'Host: %s\r\n' % expected_host.encode('utf-8')
|
||||
assert expected_header in r.content
|
||||
assert r.content.count(b'Host: ') == 1
|
||||
|
||||
|
||||
def test_conflicting_content_lengths():
|
||||
"""Ensure we correctly throw an InvalidHeader error if multiple
|
||||
conflicting Content-Length headers are returned.
|
||||
"""
|
||||
|
||||
def multiple_content_length_response_handler(sock):
|
||||
request_content = consume_socket_content(sock, timeout=0.5)
|
||||
|
||||
sock.send(b"HTTP/1.1 200 OK\r\n" +
|
||||
b"Content-Type: text/plain\r\n" +
|
||||
b"Content-Length: 16\r\n" +
|
||||
b"Content-Length: 32\r\n\r\n" +
|
||||
b"-- Bad Actor -- Original Content\r\n")
|
||||
|
||||
return request_content
|
||||
|
||||
close_server = threading.Event()
|
||||
server = Server(multiple_content_length_response_handler)
|
||||
|
||||
with server as (host, port):
|
||||
url = 'http://{}:{}/'.format(host, port)
|
||||
with pytest.raises(requests.exceptions.InvalidHeader):
|
||||
r = requests.get(url)
|
||||
close_server.set()
|
||||
|
||||
|
||||
def test_digestauth_401_count_reset_on_redirect():
|
||||
"""Ensure we correctly reset num_401_calls after a successful digest auth,
|
||||
followed by a 302 redirect to another digest auth prompt.
|
||||
|
||||
@@ -24,7 +24,7 @@ from requests.cookies import (
|
||||
from requests.exceptions import (
|
||||
ConnectionError, ConnectTimeout, InvalidSchema, InvalidURL,
|
||||
MissingSchema, ReadTimeout, Timeout, RetryError, TooManyRedirects,
|
||||
ProxyError, InvalidHeader, UnrewindableBodyError, SSLError, InvalidProxyURL)
|
||||
ProxyError, InvalidHeader, UnrewindableBodyError, SSLError, InvalidProxyURL, InvalidJSONError)
|
||||
from requests.models import PreparedRequest
|
||||
from requests.structures import CaseInsensitiveDict
|
||||
from requests.sessions import SessionRedirectMixin
|
||||
@@ -40,6 +40,9 @@ from urllib3.util import Timeout as Urllib3Timeout
|
||||
# listening on that port)
|
||||
TARPIT = 'http://10.255.255.1'
|
||||
|
||||
# This is to avoid waiting the timeout of using TARPIT
|
||||
INVALID_PROXY='http://localhost:1'
|
||||
|
||||
try:
|
||||
from ssl import SSLContext
|
||||
del SSLContext
|
||||
@@ -78,6 +81,8 @@ class TestRequests:
|
||||
(InvalidSchema, 'localhost.localdomain:3128/'),
|
||||
(InvalidSchema, '10.122.1.1:3128/'),
|
||||
(InvalidURL, 'http://'),
|
||||
(InvalidURL, 'http://*example.com'),
|
||||
(InvalidURL, 'http://.example.com'),
|
||||
))
|
||||
def test_invalid_url(self, exception, url):
|
||||
with pytest.raises(exception):
|
||||
@@ -551,6 +556,51 @@ class TestRequests:
|
||||
with pytest.raises(InvalidProxyURL):
|
||||
requests.get(httpbin(), proxies={'http': 'http:///example.com:8080'})
|
||||
|
||||
def test_respect_proxy_env_on_send_self_prepared_request(self, httpbin):
|
||||
with override_environ(http_proxy=INVALID_PROXY):
|
||||
with pytest.raises(ProxyError):
|
||||
session = requests.Session()
|
||||
request = requests.Request('GET', httpbin())
|
||||
session.send(request.prepare())
|
||||
|
||||
def test_respect_proxy_env_on_send_session_prepared_request(self, httpbin):
|
||||
with override_environ(http_proxy=INVALID_PROXY):
|
||||
with pytest.raises(ProxyError):
|
||||
session = requests.Session()
|
||||
request = requests.Request('GET', httpbin())
|
||||
prepared = session.prepare_request(request)
|
||||
session.send(prepared)
|
||||
|
||||
def test_respect_proxy_env_on_send_with_redirects(self, httpbin):
|
||||
with override_environ(http_proxy=INVALID_PROXY):
|
||||
with pytest.raises(ProxyError):
|
||||
session = requests.Session()
|
||||
url = httpbin('redirect/1')
|
||||
print(url)
|
||||
request = requests.Request('GET', url)
|
||||
session.send(request.prepare())
|
||||
|
||||
def test_respect_proxy_env_on_get(self, httpbin):
|
||||
with override_environ(http_proxy=INVALID_PROXY):
|
||||
with pytest.raises(ProxyError):
|
||||
session = requests.Session()
|
||||
session.get(httpbin())
|
||||
|
||||
def test_respect_proxy_env_on_request(self, httpbin):
|
||||
with override_environ(http_proxy=INVALID_PROXY):
|
||||
with pytest.raises(ProxyError):
|
||||
session = requests.Session()
|
||||
session.request(method='GET', url=httpbin())
|
||||
|
||||
def test_proxy_authorization_preserved_on_request(self, httpbin):
|
||||
proxy_auth_value = "Bearer XXX"
|
||||
session = requests.Session()
|
||||
session.headers.update({"Proxy-Authorization": proxy_auth_value})
|
||||
resp = session.request(method='GET', url=httpbin('get'))
|
||||
sent_headers = resp.json().get('headers', {})
|
||||
|
||||
assert sent_headers.get("Proxy-Authorization") == proxy_auth_value
|
||||
|
||||
def test_basicauth_with_netrc(self, httpbin):
|
||||
auth = ('user', 'pass')
|
||||
wrong_auth = ('wronguser', 'wrongpass')
|
||||
@@ -668,7 +718,7 @@ class TestRequests:
|
||||
post1 = requests.post(url, data={'some': 'data'})
|
||||
assert post1.status_code == 200
|
||||
|
||||
with open('Pipfile') as f:
|
||||
with open('requirements-dev.txt') as f:
|
||||
post2 = requests.post(url, files={'some': f})
|
||||
assert post2.status_code == 200
|
||||
|
||||
@@ -736,7 +786,7 @@ class TestRequests:
|
||||
post1 = requests.post(url, data={'some': 'data'})
|
||||
assert post1.status_code == 200
|
||||
|
||||
with open('Pipfile') as f:
|
||||
with open('requirements-dev.txt') as f:
|
||||
post2 = requests.post(url, data={'some': 'data'}, files={'some': f})
|
||||
assert post2.status_code == 200
|
||||
|
||||
@@ -773,9 +823,11 @@ class TestRequests:
|
||||
|
||||
def test_conflicting_post_params(self, httpbin):
|
||||
url = httpbin('post')
|
||||
with open('Pipfile') as f:
|
||||
pytest.raises(ValueError, "requests.post(url, data='[{\"some\": \"data\"}]', files={'some': f})")
|
||||
pytest.raises(ValueError, "requests.post(url, data=u('[{\"some\": \"data\"}]'), files={'some': f})")
|
||||
with open('requirements-dev.txt') as f:
|
||||
with pytest.raises(ValueError):
|
||||
requests.post(url, data='[{"some": "data"}]', files={'some': f})
|
||||
with pytest.raises(ValueError):
|
||||
requests.post(url, data=u('[{"some": "data"}]'), files={'some': f})
|
||||
|
||||
def test_request_ok_set(self, httpbin):
|
||||
r = requests.get(httpbin('status', '404'))
|
||||
@@ -833,8 +885,9 @@ class TestRequests:
|
||||
r = requests.get(httpbin(), cert='.')
|
||||
assert r.status_code == 200
|
||||
|
||||
def test_https_warnings(self, httpbin_secure, httpbin_ca_bundle):
|
||||
def test_https_warnings(self, nosan_server):
|
||||
"""warnings are emitted with requests.get"""
|
||||
host, port, ca_bundle = nosan_server
|
||||
if HAS_MODERN_SSL or HAS_PYOPENSSL:
|
||||
warnings_expected = ('SubjectAltNameWarning', )
|
||||
else:
|
||||
@@ -844,8 +897,7 @@ class TestRequests:
|
||||
|
||||
with pytest.warns(None) as warning_records:
|
||||
warnings.simplefilter('always')
|
||||
requests.get(httpbin_secure('status', '200'),
|
||||
verify=httpbin_ca_bundle)
|
||||
requests.get("https://localhost:{}/".format(port), verify=ca_bundle)
|
||||
|
||||
warning_records = [item for item in warning_records
|
||||
if item.category.__name__ != 'ResourceWarning']
|
||||
@@ -2525,3 +2577,13 @@ class TestPreparingURLs(object):
|
||||
r = requests.Request('GET', url=input, params=params)
|
||||
p = r.prepare()
|
||||
assert p.url == expected
|
||||
|
||||
def test_post_json_nan(self, httpbin):
|
||||
data = {"foo": float("nan")}
|
||||
with pytest.raises(requests.exceptions.InvalidJSONError):
|
||||
r = requests.post(httpbin('post'), json=data)
|
||||
|
||||
def test_json_decode_compatibility(self, httpbin):
|
||||
r = requests.get(httpbin('bytes/20'))
|
||||
with pytest.raises(requests.exceptions.JSONDecodeError):
|
||||
r.json()
|
||||
|
||||
@@ -4,6 +4,7 @@ import os
|
||||
import copy
|
||||
import filecmp
|
||||
from io import BytesIO
|
||||
import tarfile
|
||||
import zipfile
|
||||
from collections import deque
|
||||
|
||||
@@ -86,6 +87,18 @@ class TestSuperLen:
|
||||
assert super_len(fd) == 4
|
||||
assert len(recwarn) == warnings_num
|
||||
|
||||
def test_tarfile_member(self, tmpdir):
|
||||
file_obj = tmpdir.join('test.txt')
|
||||
file_obj.write('Test')
|
||||
|
||||
tar_obj = str(tmpdir.join('test.tar'))
|
||||
with tarfile.open(tar_obj, 'w') as tar:
|
||||
tar.add(str(file_obj), arcname='test.txt')
|
||||
|
||||
with tarfile.open(tar_obj) as tar:
|
||||
member = tar.extractfile('test.txt')
|
||||
assert super_len(member) == 4
|
||||
|
||||
def test_super_len_with__len__(self):
|
||||
foo = [1,2,3,4]
|
||||
len_foo = super_len(foo)
|
||||
@@ -285,6 +298,10 @@ class TestExtractZippedPaths:
|
||||
assert os.path.exists(extracted_path)
|
||||
assert filecmp.cmp(extracted_path, __file__)
|
||||
|
||||
def test_invalid_unc_path(self):
|
||||
path = r"\\localhost\invalid\location"
|
||||
assert extract_zipped_paths(path) == path
|
||||
|
||||
|
||||
class TestContentEncodingDetection:
|
||||
|
||||
@@ -584,6 +601,7 @@ def test_parse_header_links(value, expected):
|
||||
'value, expected', (
|
||||
('example.com/path', 'http://example.com/path'),
|
||||
('//example.com/path', 'http://example.com/path'),
|
||||
('example.com:80', 'http://example.com:80'),
|
||||
))
|
||||
def test_prepend_scheme_if_needed(value, expected):
|
||||
assert prepend_scheme_if_needed(value, 'http') == expected
|
||||
|
||||
@@ -78,7 +78,9 @@ class Server(threading.Thread):
|
||||
def _create_socket_and_bind(self):
|
||||
sock = socket.socket()
|
||||
sock.bind((self.host, self.port))
|
||||
sock.listen(0)
|
||||
# NB: when Python 2.7 is no longer supported, the argument
|
||||
# can be removed to use a default backlog size
|
||||
sock.listen(5)
|
||||
return sock
|
||||
|
||||
def _close_server_sock_ignore_errors(self):
|
||||
|
||||
17
tox.ini
17
tox.ini
@@ -1,7 +1,18 @@
|
||||
[tox]
|
||||
envlist = py27,py35,py36,py37,py38
|
||||
envlist = py{27,36,37,38,39}-{default,use_chardet_on_py3}
|
||||
|
||||
[testenv]
|
||||
|
||||
deps = -rrequirements-dev.txt
|
||||
extras =
|
||||
security
|
||||
socks
|
||||
commands =
|
||||
python setup.py test
|
||||
pytest tests
|
||||
|
||||
[testenv:default]
|
||||
|
||||
[testenv:use_chardet_on_py3]
|
||||
extras =
|
||||
security
|
||||
socks
|
||||
use_chardet_on_py3
|
||||
|
||||
Reference in New Issue
Block a user