Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: pypa/pip
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 18.1
Choose a base ref
...
head repository: pypa/pip
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 19.2
Choose a head ref

Commits on May 15, 2018

  1. Preliminary manylinux2 support.

    markrwilliams authored and wtolson committed May 15, 2018

    Unverified

    This commit is not signed, but one or more authors requires that any commit attributed to them is signed.
    Copy the full SHA
    fde4a82 View commit details
  2. News file.

    markrwilliams authored and wtolson committed May 15, 2018
    Copy the full SHA
    94f3318 View commit details
  3. Rename manylinux2 tag as manylinux2010

    This reflects the change in the tag name in PEP 571.
    wtolson committed May 15, 2018
    Copy the full SHA
    8d20689 View commit details
  4. Copy the full SHA
    84eef80 View commit details
  5. Copy the full SHA
    eb867a6 View commit details
  6. Copy the full SHA
    9303895 View commit details

Commits on Jul 26, 2018

  1. Copy the full SHA
    aef521e View commit details
  2. Copy the full SHA
    4e0c433 View commit details

Commits on Jul 29, 2018

  1. Make the ascii progress bar really be ascii, not Unicode

    Found while debugging #5665
    segevfiner committed Jul 29, 2018
    Copy the full SHA
    6db3f88 View commit details
  2. Add news/5671.bugfix

    segevfiner committed Jul 29, 2018
    Copy the full SHA
    b0a6737 View commit details

Commits on Aug 17, 2018

  1. Copy the full SHA
    b7222f3 View commit details
  2. Copy the full SHA
    e3c869f View commit details

Commits on Sep 15, 2018

  1. Copy the full SHA
    60ff4a6 View commit details
  2. Copy the full SHA
    be3fb93 View commit details
  3. Add .trivial file for change

    brcrista committed Sep 15, 2018
    Copy the full SHA
    ef94c93 View commit details
  4. Revert "Add .trivial file for change"

    This reverts commit ef94c93.
    dstufft already added the 'trivial' tag to the PR.
    brcrista committed Sep 15, 2018
    Copy the full SHA
    fd490b5 View commit details

Commits on Sep 26, 2018

  1. Reduce the heading level

    pradyunsg committed Sep 26, 2018
    Copy the full SHA
    dbf758a View commit details

Commits on Oct 1, 2018

  1. Copy the full SHA
    8dcae5b View commit details
  2. Copy the full SHA
    7a17a1f View commit details
  3. Extract request part of get_page into helper

    Also switch to use exceptions as flow control for VCS and Content-Type
    detection. Hopefully this makes the flow much clearer.
    uranusjr committed Oct 1, 2018
    Copy the full SHA
    72779c6 View commit details
  4. Copy the full SHA
    bb6dae6 View commit details
  5. Copy the full SHA
    025dc45 View commit details
  6. rename YAMLs for pool name

    brcrista committed Oct 1, 2018
    Copy the full SHA
    7dfb765 View commit details
  7. Copy the full SHA
    ee9d3ea View commit details
  8. Copy the full SHA
    7a612ee View commit details
  9. Copy the full SHA
    fe76e4f View commit details
  10. Copy the full SHA
    55f15be View commit details
  11. Copy the full SHA
    69c74f9 View commit details
  12. Copy the full SHA
    d6b2991 View commit details
  13. Fix job reference

    brcrista committed Oct 1, 2018
    Copy the full SHA
    3f6f28d View commit details
  14. Copy the full SHA
    3f7af32 View commit details
  15. Copy the full SHA
    012d76b View commit details

Commits on Oct 2, 2018

  1. Copy the full SHA
    b36d91c View commit details
  2. Copy the full SHA
    41a9d5e View commit details
  3. add news fragments

    popravich committed Oct 2, 2018
    Copy the full SHA
    ad64091 View commit details
  4. fix lint issues

    popravich committed Oct 2, 2018
    Copy the full SHA
    a853ca0 View commit details
  5. Copy the full SHA
    5295d8b View commit details
  6. Copy the full SHA
    cfac80f View commit details
  7. Copy the full SHA
    172a71b View commit details
  8. Copy the full SHA
    3ec6775 View commit details
  9. Add news entry

    takluyver committed Oct 2, 2018
    Copy the full SHA
    7343154 View commit details
  10. fix support for invoking pip using python src/pip ...

    Ensure the subprocess call to pip for installing the PEP 518
    build dependencies is using the same version of pip.
    benoit-pierre committed Oct 2, 2018
    Copy the full SHA
    464b2f3 View commit details
  11. split test into two

    popravich committed Oct 2, 2018
    Copy the full SHA
    290e3d5 View commit details
  12. Copy the full SHA
    9a1194e View commit details
  13. Copy the full SHA
    4286f49 View commit details
  14. Remove unused variable

    takluyver committed Oct 2, 2018
    Copy the full SHA
    32b8a79 View commit details

Commits on Oct 5, 2018

  1. Copy the full SHA
    c86b742 View commit details
  2. Copy the full SHA
    767eafc View commit details
  3. fix wrong vmImage name

    brcrista committed Oct 5, 2018
    Copy the full SHA
    35b1ea3 View commit details
  4. Copy the full SHA
    a4d1569 View commit details
Showing 373 changed files with 24,311 additions and 7,775 deletions.
23 changes: 13 additions & 10 deletions appveyor.yml → .appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
environment:
matrix:
# Unit and integration tests.
- PYTHON: "C:\\Python27"
- PYTHON: "C:\\Python36-x64"
- PYTHON: "C:\\Python27"
RUN_INTEGRATION_TESTS: "True"
- PYTHON: "C:\\Python36-x64"
RUN_INTEGRATION_TESTS: "True"
# Unit tests only.
- PYTHON: "C:\\Python27-x64"
- PYTHON: "C:\\Python34"
- PYTHON: "C:\\Python34-x64"
- PYTHON: "C:\\Python35"
- PYTHON: "C:\\Python35-x64"
- PYTHON: "C:\\Python36"

matrix:
fast_finish: true

clone_depth: 50

install:
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
- "python --version"
- "pip install certifi tox"
- "python -m pip install --upgrade --disable-pip-version-check pip setuptools wheel"
- "pip install --upgrade certifi tox tox-venv"
- "pip freeze --all"
# Fix git SSL errors.
- "python -m certifi >cacert.txt"
- "set /p GIT_SSL_CAINFO=<cacert.txt"
@@ -31,6 +34,8 @@ cache:

test_script:
- ps: |
$ErrorActionPreference = "Stop"
function should_run_tests {
if ("$env:APPVEYOR_PULL_REQUEST_NUMBER" -eq "") {
Write-Host "Not a pull request - running tests"
@@ -60,10 +65,8 @@ test_script:
subst T: $env:TEMP
$env:TEMP = "T:\"
$env:TMP = "T:\"
if ($env:RUN_INTEGRATION_TESTS -eq "True") {
tox -e py -- -m integration -n 3 --duration=5
}
else {
tox -e py -- -m unit -n 3
tox -e py -- -m unit
if ($LastExitCode -eq 0 -and $env:RUN_INTEGRATION_TESTS -eq "True") {
tox -e py -- --use-venv -m integration -n2 --durations=20
}
}
37 changes: 37 additions & 0 deletions .azure-pipelines/jobs/package.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
parameters:
vmImage:

jobs:
- job: Package
dependsOn:
- Test_Primary
- Test_Secondary
pool:
vmImage: ${{ parameters.vmImage }}

steps:
- task: UsePythonVersion@0
displayName: Use Python 3 latest
inputs:
versionSpec: '3'

- bash: pip install setuptools tox wheel invoke towncrier requests
displayName: Install dependencies

- bash: invoke generate.authors
displayName: Generate AUTHORS.txt

- bash: invoke generate.news --yes
displayName: Generate NEWS.rst

- bash: tox -e packaging
displayName: Run Tox packaging

- bash: python setup.py sdist bdist_wheel
displayName: Create sdist and wheel

- task: PublishBuildArtifacts@1
displayName: 'Publish Artifact: dist'
inputs:
pathtoPublish: dist
artifactName: dist
59 changes: 59 additions & 0 deletions .azure-pipelines/jobs/test-windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
parameters:
vmImage:

jobs:
- job: Test_Primary
displayName: Test Primary

pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python27-x64:
python.version: '2.7'
python.architecture: x64
Python36-x64:
python.version: '3.6'
python.architecture: x64
maxParallel: 2

steps:
- template: ../steps/run-tests-windows.yml
parameters:
runIntegrationTests: true

- job: Test_Secondary
displayName: Test Secondary
# Don't run integration tests for these runs
# Run after Test_Primary so we don't devour time and jobs if tests are going to fail
dependsOn: Test_Primary

pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python35-x64:
python.version: '3.5'
python.architecture: x64
Python37-x64:
python.version: '3.7'
python.architecture: x64
# This is for Windows, so test x86 builds
Python27-x86:
python.version: '2.7'
python.architecture: x86
Python35-x86:
python.version: '3.5'
python.architecture: x86
Python36-x86:
python.version: '3.6'
python.architecture: x86
Python37-x86:
python.version: '3.7'
python.architecture: x86
maxParallel: 5

steps:
- template: ../steps/run-tests-windows.yml
parameters:
runIntegrationTests: false
41 changes: 41 additions & 0 deletions .azure-pipelines/jobs/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
parameters:
vmImage:

jobs:
- job: Test_Primary
displayName: Test Primary

pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python27:
python.version: '2.7'
python.architecture: x64
Python36:
python.version: '3.6'
python.architecture: x64
maxParallel: 2

steps:
- template: ../steps/run-tests.yml

- job: Test_Secondary
displayName: Test Secondary
# Run after Test_Primary so we don't devour time and jobs if tests are going to fail
dependsOn: Test_Primary

pool:
vmImage: ${{ parameters.vmImage }}
strategy:
matrix:
Python35:
python.version: '3.5'
python.architecture: x64
Python37:
python.version: '3.7'
python.architecture: x64
maxParallel: 3

steps:
- template: ../steps/run-tests.yml
8 changes: 8 additions & 0 deletions .azure-pipelines/linux.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
jobs:
- template: jobs/test.yml
parameters:
vmImage: ubuntu-16.04

- template: jobs/package.yml
parameters:
vmImage: ubuntu-16.04
8 changes: 8 additions & 0 deletions .azure-pipelines/macos.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
jobs:
- template: jobs/test.yml
parameters:
vmImage: xcode9-macos10.13

- template: jobs/package.yml
parameters:
vmImage: xcode9-macos10.13
38 changes: 38 additions & 0 deletions .azure-pipelines/steps/run-tests-windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
parameters:
runIntegrationTests:

steps:
- task: UsePythonVersion@0
displayName: Use Python $(python.version)
inputs:
versionSpec: '$(python.version)'
architecture: '$(python.architecture)'

- bash: pip install --upgrade setuptools tox
displayName: Install Tox

- script: tox -e py -- -m unit -n 3 --junit-xml=junit/unit-test.xml
displayName: Tox run unit tests

- ${{ if eq(parameters.runIntegrationTests, 'true') }}:
- powershell: |
# Fix Git SSL errors
pip install certifi tox
python -m certifi > cacert.txt
$env:GIT_SSL_CAINFO = $(Get-Content cacert.txt)
# Shorten paths to get under MAX_PATH or else integration tests will fail
# https://bugs.python.org/issue18199
subst T: $env:TEMP
$env:TEMP = "T:\"
$env:TMP = "T:\"
tox -e py -- -m integration -n 3 --duration=5 --junit-xml=junit/integration-test.xml
displayName: Tox run integration tests
- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
testResultsFiles: junit/*.xml
testRunTitle: 'Python $(python.version)'
condition: succeededOrFailed()
25 changes: 25 additions & 0 deletions .azure-pipelines/steps/run-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
steps:
- task: UsePythonVersion@0
displayName: Use Python $(python.version)
inputs:
versionSpec: '$(python.version)'

- bash: pip install --upgrade setuptools tox
displayName: Install Tox

- script: tox -e py -- -m unit --junit-xml=junit/unit-test.xml
displayName: Tox run unit tests

# Run integration tests in two groups so we will fail faster if there is a failure in the first group
- script: tox -e py -- -m integration -n 4 --duration=5 -k "not test_install" --junit-xml=junit/integration-test-group0.xml
displayName: Tox run Group 0 integration tests

- script: tox -e py -- -m integration -n 4 --duration=5 -k "test_install" --junit-xml=junit/integration-test-group1.xml
displayName: Tox run Group 1 integration tests

- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
testResultsFiles: junit/*.xml
testRunTitle: 'Python $(python.version)'
condition: succeededOrFailed()
8 changes: 8 additions & 0 deletions .azure-pipelines/windows.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
jobs:
- template: jobs/test-windows.yml
parameters:
vmImage: vs2017-win2016

- template: jobs/package.yml
parameters:
vmImage: vs2017-win2016
3 changes: 3 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,9 @@ As a reminder, all contributors are expected to follow our [Code of Conduct][coc

[coc]: https://www.pypa.io/en/latest/code-of-conduct/

## Development Documentation

Our [development documentation](https://pip.pypa.io/en/latest/development/) contains details on how to get started with contributing to pip, and details of our development processes.

## Bot Commands

8 changes: 8 additions & 0 deletions .github/lock.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 30
# Issues and pull requests with these labels will not be locked.
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: "S: auto-locked"
# Comment to post before locking. Set to `false` to disable
lockComment: false
11 changes: 11 additions & 0 deletions .github/no-response.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Number of days of inactivity before issue is closed for lack of response
daysUntilClose: 30
# Label requiring a response
responseRequiredLabel: "S: awaiting response"
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.
7 changes: 7 additions & 0 deletions .github/triage-new-issues.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# This is based off of reading the actual source code of the bot. :/
# https://github.com/tunnckoCoreLabs/triage-new-issues/blob/2ff406030ecce4c25f7bdd454125ba54db1301bd/src/index.js#L7
#
# While this file is currently a no-op, it serves the purpose of
# documenting that this bot is indeed being used, since this is a
# non-standard probot bot.
label: "needs triage"
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -26,13 +26,22 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
tests/data/common_wheels/
pip-wheel-metadata

# Misc
*~
.*.sw?
.env/

# For IntelliJ IDEs (basically PyCharm)
.idea/

# For Visual Studio Code
.vscode/

# Scratch Pad for experiments
.scratch/

# Mac
.DS_Store
2 changes: 2 additions & 0 deletions .mailmap
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
Adam Wentz <awentz@theonion.com>
Alethea Flowers <magicalgirl@google.com> <jjramone13@gmail.com>
Alethea Flowers <magicalgirl@google.com> Thea Flowers <theaflowers@google.com>
Alex Grönholm <alex.gronholm@nextday.fi>
Alex Grönholm <alex.gronholm@nextday.fi> <alex.gronholm+git@nextday.fi>
Anatoly Techtonik <techtonik@gmail.com>
33 changes: 13 additions & 20 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
language: python
sudo: false
cache: pip
dist: trusty
dist: xenial
python: 3.6
addons:
apt:
packages:
- bzr

stages:
- primary
@@ -13,8 +17,8 @@ jobs:
- stage: primary
env: TOXENV=docs
- env: TOXENV=lint-py2
python: 2.7
- env: TOXENV=lint-py3
python: 3.6
- env: TOXENV=mypy
- env: TOXENV=packaging
# Latest CPython
@@ -26,46 +30,35 @@ jobs:
python: 3.6
- env: GROUP=2
python: 3.6

# Complete checking for ensuring compatibility
# PyPy
- stage: secondary
env: GROUP=1
python: pypy3
python: pypy3.5-6.0
- env: GROUP=2
python: pypy3
python: pypy3.5-6.0
- env: GROUP=1
python: pypy
python: pypy2.7-6.0
- env: GROUP=2
python: pypy
python: pypy2.7-6.0
# Other Supported CPython
- env: GROUP=1
python: 3.7
dist: xenial
sudo: required
- env: GROUP=2
python: 3.7
dist: xenial
sudo: required
- env: GROUP=1
python: 3.5
- env: GROUP=2
python: 3.5
- env: GROUP=1
python: 3.4
- env: GROUP=2
python: 3.4

- env: GROUP=1
python: 3.8-dev
dist: xenial
sudo: required
- env: GROUP=2
python: 3.8-dev
dist: xenial
sudo: required

# It's okay to fail on the in-development CPython version.
fast_finish: true
# It's okay to fail on the in-development CPython version.
allow_failures:
- python: 3.8-dev

80 changes: 79 additions & 1 deletion AUTHORS.txt
Original file line number Diff line number Diff line change
@@ -1,22 +1,38 @@
A_Rog <adam.thomas.rogerson@gmail.com>
Abhinav Sagar <40603139+abhinavsagar@users.noreply.github.com>
ABHYUDAY PRATAP SINGH <abhyudaypratap@outlook.com>
AceGentile <ventogrigio83@gmail.com>
Adam Chainz <adam@adamj.eu>
Adam Tse <adam.tse@me.com>
Adam Tse <atse@users.noreply.github.com>
Adam Wentz <awentz@theonion.com>
Adrien Morison <adrien.morison@gmail.com>
Alan Yee <alyee@ucsd.edu>
Albert Tugushev <albert@tugushev.ru>
Albert-Guan <albert.guan94@gmail.com>
albertg <albert.guan94@gmail.com>
Aleks Bunin <github@compuix.com>
Alethea Flowers <magicalgirl@google.com>
Alex Gaynor <alex.gaynor@gmail.com>
Alex Grönholm <alex.gronholm@nextday.fi>
Alex Loosley <a.loosley@reply.de>
Alex Morega <alex@grep.ro>
Alex Stachowiak <alexander@computer.org>
Alexander Shtyrov <rawzausho@gmail.com>
Alexandre Conrad <alexandre.conrad@gmail.com>
Alexey Popravka <a.popravka@smartweb.com.ua>
Alexey Popravka <alexey.popravka@horsedevel.com>
Alli <alzeih@users.noreply.github.com>
Ami Fischman <ami@fischman.org>
Anatoly Techtonik <techtonik@gmail.com>
Andreas Lutro <anlutro@gmail.com>
Andrei Geacar <andrei.geacar@gmail.com>
Andrew Gaul <andrew@gaul.org>
Andrey Bulgakov <mail@andreiko.ru>
Andrés Delfino <34587441+andresdelfino@users.noreply.github.com>
Andrés Delfino <adelfino@gmail.com>
Andy Freeland <andy.freeland@redjack.com>
Andy Freeland <andy@andyfreeland.net>
Andy Kluger <AndydeCleyre@users.noreply.github.com>
Anish Tambe <anish.tambe@yahoo.in>
Anrs Hu <anrs@douban.com>
@@ -33,6 +49,7 @@ AQNOUCH Mohammed <aqnouch.mohammed@gmail.com>
AraHaan <seandhunt_7@yahoo.com>
Arindam Choudhury <arindam@live.com>
Armin Ronacher <armin.ronacher@active-4.com>
Artem <duketemon@users.noreply.github.com>
Ashley Manton <ajd.manton@googlemail.com>
Atsushi Odagiri <aodagx@gmail.com>
Avner Cohen <israbirding@gmail.com>
@@ -45,16 +62,21 @@ Ben Darnell <ben@bendarnell.com>
Ben Hoyt <benhoyt@gmail.com>
Ben Rosser <rosser.bjr@gmail.com>
Bence Nagy <bence@underyx.me>
Benjamin Peterson <benjamin@python.org>
Benjamin VanEvery <ben@simondata.com>
Benoit Pierre <benoit.pierre@gmail.com>
Berker Peksag <berker.peksag@gmail.com>
Bernardo B. Marques <bernardo.fire@gmail.com>
Bernhard M. Wiedemann <bwiedemann@suse.de>
Bertil Hatt <bertil.hatt@farfetch.com>
Bogdan Opanchuk <bogdan@opanchuk.net>
Brad Erickson <eosrei@gmail.com>
Bradley Ayers <bradley.ayers@gmail.com>
Brandon L. Reiss <brandon@damyata.co>
Brandt Bucher <brandtbucher@gmail.com>
Brett Randall <javabrett@gmail.com>
Brian Cristante <33549821+brcrista@users.noreply.github.com>
Brian Cristante <brcrista@microsoft.com>
Brian Rosner <brosner@gmail.com>
BrownTruck <BrownTruck@users.noreply.github.com>
Bruno Oliveira <nicoddemus@gmail.com>
@@ -64,19 +86,24 @@ Buck Golemon <buck@yelp.com>
burrows <burrows@preveil.com>
Bussonnier Matthias <bussonniermatthias@gmail.com>
c22 <c22@users.noreply.github.com>
Caleb Martinez <accounts@calebmartinez.com>
Calvin Smith <eukaryote@users.noreply.github.com>
Carl Meyer <carl@oddbird.net>
Carlos Liam <carlos@aarzee.me>
Carol Willing <carolcode@willingconsulting.com>
Carter Thayer <carterwthayer@gmail.com>
Cass <cass.petrus@gmail.com>
Chandrasekhar Atina <chandu.atina@gmail.com>
Chih-Hsuan Yen <yan12125@gmail.com>
Chih-Hsuan Yen <yen@chyen.cc>
Chris Brinker <chris.brinker@gmail.com>
Chris Hunt <chrahunt@gmail.com>
Chris Jerdonek <chris.jerdonek@gmail.com>
Chris McDonough <chrism@plope.com>
Chris Wolfe <chriswwolfe@gmail.com>
Christian Heimes <christian@python.org>
Christian Oudard <christian.oudard@gmail.com>
Christopher Hunt <chrahunt@gmail.com>
Christopher Snyder <cnsnyder@users.noreply.github.com>
Clark Boylan <clark.boylan@gmail.com>
Clay McClure <clay@daemons.net>
@@ -91,6 +118,7 @@ Cory Wright <corywright@gmail.com>
Craig Kerstiens <craig.kerstiens@gmail.com>
Cristian Sorinel <cristian.sorinel@gmail.com>
Curtis Doty <Curtis@GreenKey.net>
cytolentino <ctolentino8@bloomberg.net>
Damian Quiroga <qdamian@gmail.com>
Dan Black <dyspop@gmail.com>
Dan Savilonis <djs@n-cube.org>
@@ -101,12 +129,16 @@ Daniel Hahler <git@thequod.de>
Daniel Holth <dholth@fastmail.fm>
Daniel Jost <torpedojost@gmail.com>
Daniel Shaulov <daniel.shaulov@gmail.com>
Daniele Esposti <expobrain@users.noreply.github.com>
Daniele Procida <daniele@vurt.org>
Danny Hermes <daniel.j.hermes@gmail.com>
Dav Clark <davclark@gmail.com>
Dave Abrahams <dave@boostpro.com>
Dave Jones <dave@waveform.org.uk>
David Aguilar <davvid@gmail.com>
David Black <db@d1b.org>
David Bordeynik <david.bordeynik@gmail.com>
David Bordeynik <david@zebra-med.com>
David Caro <david@dcaro.es>
David Evans <d@drhevans.com>
David Linke <dr.david.linke@gmail.com>
@@ -115,6 +147,8 @@ David Tucker <david@tucker.name>
David Wales <daviewales@gmail.com>
Davidovich <david.genest@gmail.com>
derwolfe <chriswwolfe@gmail.com>
Diego Caraballo <diegocaraballo84@gmail.com>
DiegoCaraballo <diegocaraballo84@gmail.com>
Dmitry Gladkov <dmitry.gladkov@gmail.com>
Domen Kožar <domen@dev.si>
Donald Stufft <donald@stufft.io>
@@ -125,10 +159,14 @@ Dustin Ingram <di@di.codes>
Dwayne Bailey <dwayne@translate.org.za>
Ed Morley <501702+edmorley@users.noreply.github.com>
Ed Morley <emorley@mozilla.com>
ekristina <panacejja@gmail.com>
elainechan <elaine.chan@outlook.com>
Eli Schwartz <eschwartz93@gmail.com>
Eli Schwartz <eschwartz@archlinux.org>
Emil Styrke <emil.styrke@gmail.com>
Endoh Takanao <djmchl@gmail.com>
enoch <lanxenet@gmail.com>
Erdinc Mutlu <erdinc_mutlu@yahoo.com>
Eric Gillingham <Gillingham@bikezen.net>
Eric Hanchrow <eric.hanchrow@gmail.com>
Eric Hopper <hopper@omnifarious.org>
@@ -138,9 +176,11 @@ Ernest W Durbin III <ewdurbin@gmail.com>
Ernest W. Durbin III <ewdurbin@gmail.com>
Erwin Janssen <erwinjanssen@outlook.com>
Eugene Vereshchagin <evvers@gmail.com>
Felix Yan <felixonmars@archlinux.org>
fiber-space <fiber-space@users.noreply.github.com>
Filip Kokosiński <filip.kokosinski@gmail.com>
Florian Briand <ownerfrance+github@hotmail.com>
Florian Rathgeber <florian.rathgeber@gmail.com>
Francesco <f.guerrieri@gmail.com>
Francesco Montesano <franz.bergesund@gmail.com>
Gabriel Curio <g.curio@gmail.com>
@@ -157,6 +197,7 @@ gkdoc <40815324+gkdoc@users.noreply.github.com>
GOTO Hayato <3532528+gh640@users.noreply.github.com>
Guilherme Espada <porcariadagata@gmail.com>
Guy Rozendorn <guy@rzn.co.il>
gzpan123 <gzpan123@gmail.com>
Hari Charan <hcharan997@gmail.com>
Herbert Pfennig <herbert@albinen.com>
Hsiaoming Yang <lepture@me.com>
@@ -176,6 +217,7 @@ Ilya Baryshev <baryshev@gmail.com>
INADA Naoki <songofacandy@gmail.com>
Ionel Cristian Mărieș <contact@ionelmc.ro>
Ionel Maries Cristian <ionel.mc@gmail.com>
jakirkham <jakirkham@gmail.com>
Jakub Stasiak <kuba.stasiak@gmail.com>
Jakub Vysoky <jakub@borka.cz>
Jakub Wilk <jwilk@jwilk.net>
@@ -191,15 +233,17 @@ Jay Graves <jay@skabber.com>
Jean-Christophe Fillion-Robin <jchris.fillionr@kitware.com>
Jeff Barber <jbarber@computer.org>
Jeff Dairiki <dairiki@dairiki.org>
Jelmer Vernooij <jelmer@jelmer.uk>
Jeremy Stanley <fungi@yuggoth.org>
Jeremy Zafran <jzafran@users.noreply.github.com>
Jim Garrison <jim@garrison.cc>
Jivan Amara <Development@JivanAmara.net>
John-Scott Atlakson <john.scott.atlakson@gmail.com>
johnthagen <johnthagen@gmail.com>
johnthagen <johnthagen@users.noreply.github.com>
Jon Banafato <jon@jonafato.com>
Jon Dufresne <jon.dufresne@gmail.com>
Jon Parise <jon@indelible.org>
Jon Wayne Parrott <jjramone13@gmail.com>
Jonas Nockert <jonasnockert@gmail.com>
Jonathan Herbert <foohyfooh@gmail.com>
Joost Molenaar <j.j.molenaar@gmail.com>
@@ -208,6 +252,9 @@ Joseph Long <jdl@fastmail.fm>
Josh Bronson <jabronson@gmail.com>
Josh Hansen <josh@skwash.net>
Josh Schneier <josh.schneier@gmail.com>
Juanjo Bazán <jjbazan@gmail.com>
Julian Berman <Julian@GrayVines.com>
Julian Gethmann <julian.gethmann@kit.edu>
Julien Demoor <julien@jdemoor.com>
jwg4 <jack.grahl@yahoo.co.uk>
Jyrki Pulliainen <jyrki@spotify.com>
@@ -221,11 +268,14 @@ Kenneth Reitz <me@kennethreitz.org>
Kevin Burke <kev@inburke.com>
Kevin Carter <kevin.carter@rackspace.com>
Kevin Frommelt <kevin.frommelt@webfilings.com>
Kevin R Patterson <kevin.r.patterson@intel.com>
Kexuan Sun <me@kianasun.com>
Kit Randel <kit@nocturne.net.nz>
kpinc <kop@meme.com>
Kumar McMillan <kumar.mcmillan@gmail.com>
Kyle Persohn <kyle.persohn@gmail.com>
lakshmanaram <lakshmanaram.n@gmail.com>
Laszlo Kiss-Kollar <kiss.kollar.laszlo@gmail.com>
Laurent Bristiel <laurent@bristiel.com>
Laurie Opperman <laurie@sitesee.com.au>
Leon Sasson <leonsassonha@gmail.com>
@@ -239,12 +289,17 @@ Luke Macken <lmacken@redhat.com>
Luo Jiebin <luo.jiebin@qq.com>
luojiebin <luojiebin@users.noreply.github.com>
luz.paz <luzpaz@users.noreply.github.com>
László Kiss Kollár <lkisskollar@bloomberg.net>
László Kiss Kollár <lkollar@users.noreply.github.com>
Marc Abramowitz <marc@marc-abramowitz.com>
Marc Tamlyn <marc.tamlyn@gmail.com>
Marcus Smith <qwcode@gmail.com>
Mariatta <Mariatta@users.noreply.github.com>
Mark Kohler <mark.kohler@proteinsimple.com>
Mark Williams <markrwilliams@gmail.com>
Mark Williams <mrw@enotuniq.org>
Markus Hametner <fin+github@xbhd.org>
Masaki <mk5986@nyu.edu>
Masklinn <bitbucket.org@masklinn.net>
Matej Stuchlik <mstuchli@redhat.com>
Mathew Jennings <mjennings@foursquare.com>
@@ -262,6 +317,7 @@ Matthias Bussonnier <bussonniermatthias@gmail.com>
mattip <matti.picus@gmail.com>
Maxim Kurnikov <maxim.kurnikov@gmail.com>
Maxime Rouyrre <rouyrre+git@gmail.com>
mbaluna <44498973+mbaluna@users.noreply.github.com>
memoselyk <memoselyk@gmail.com>
Michael <michael-k@users.noreply.github.com>
Michael Aquilina <michaelaquilina@gmail.com>
@@ -275,13 +331,16 @@ Mihir Singh <git.service@mihirsingh.com>
Min RK <benjaminrk@gmail.com>
MinRK <benjaminrk@gmail.com>
Miro Hrončok <miro@hroncok.cz>
Monica Baluna <mbaluna@bloomberg.net>
montefra <franz.bergesund@gmail.com>
Monty Taylor <mordred@inaugust.com>
Nate Coraor <nate@bx.psu.edu>
Nathaniel J. Smith <njs@pobox.com>
Nehal J Wani <nehaljw.kkd1@gmail.com>
Nick Coghlan <ncoghlan@gmail.com>
Nick Stenning <nick@whiteink.com>
Nick Timkovich <prometheus235@gmail.com>
Nicolas Bock <nicolasbock@gmail.com>
Nikhil Benesch <nikhil.benesch@gmail.com>
Nitesh Sharma <nbsharma@outlook.com>
Nowell Strite <nowell@strite.org>
@@ -306,29 +365,38 @@ Paul Nasrat <pnasrat@gmail.com>
Paul Oswald <pauloswald@gmail.com>
Paul van der Linden <mail@paultjuh.org>
Paulus Schoutsen <paulus@paulusschoutsen.nl>
Pavithra Eswaramoorthy <33131404+QueenCoffee@users.noreply.github.com>
Pawel Jasinski <pawel.jasinski@gmail.com>
Pekka Klärck <peke@iki.fi>
Peter Lisák <peter.lisak@showmax.com>
Peter Waller <peter.waller@gmail.com>
petr-tik <petr-tik@users.noreply.github.com>
Phaneendra Chiruvella <hi@pcx.io>
Phil Freo <phil@philfreo.com>
Phil Pennock <phil@pennock-tech.com>
Phil Whelan <phil123@gmail.com>
Philip Jägenstedt <philip@foolip.org>
Philip Molloy <pamolloy@users.noreply.github.com>
Philippe Ombredanne <pombredanne@gmail.com>
Pi Delport <pjdelport@gmail.com>
Pierre-Yves Rofes <github@rofes.fr>
pip <pypa-dev@googlegroups.com>
Prabakaran Kumaresshan <k_prabakaran+github@hotmail.com>
Prabhjyotsing Surjit Singh Sodhi <psinghsodhi@bloomberg.net>
Pradyun Gedam <pradyunsg@gmail.com>
Pratik Mallya <mallya@us.ibm.com>
Preston Holmes <preston@ptone.com>
Przemek Wrzos <hetmankp@none>
Pulkit Goyal <7895pulkit@gmail.com>
Qiangning Hong <hongqn@gmail.com>
Quentin Pradet <quentin.pradet@gmail.com>
R. David Murray <rdmurray@bitdance.com>
Rafael Caricio <rafael.jacinto@gmail.com>
Ralf Schmitt <ralf@systemexit.de>
Razzi Abuissa <razzi53@gmail.com>
Remi Rampin <remirampin@gmail.com>
Rene Dudfield <renesd@gmail.com>
Riccardo Magliocchetti <riccardo.magliocchetti@gmail.com>
Richard Jones <r1chardj0n3s@gmail.com>
RobberPhex <robberphex@gmail.com>
Robert Collins <rbtcollins@hp.com>
@@ -349,11 +417,14 @@ Ryan Wooden <rygwdn@gmail.com>
ryneeverett <ryneeverett@gmail.com>
Sachi King <nakato@nakato.io>
Salvatore Rinchiera <salvatore@rinchiera.com>
Savio Jomton <sajo240519@gmail.com>
schlamar <marc.schlaich@gmail.com>
Scott Kitterman <sklist@kitterman.com>
Sean <me@sean.taipei>
seanj <seanj@xyke.com>
Sebastian Schaetz <sschaetz@butterflynetinc.com>
Segev Finer <segev208@gmail.com>
SeongSoo Cho <ppiyakk2@printf.kr>
Sergey Vasilyev <nolar@nolar.info>
Seth Woodworth <seth@sethish.com>
Shlomi Fish <shlomif@shlomifish.org>
@@ -367,6 +438,7 @@ Stephan Erb <github@stephanerb.eu>
stepshal <nessento@openmailbox.org>
Steve (Gadget) Barnes <gadgetsteve@hotmail.com>
Steve Barnes <gadgetsteve@hotmail.com>
Steve Dower <steve.dower@microsoft.com>
Steve Kowalik <steven@wedontsleep.org>
Steven Myint <git@stevenmyint.com>
stonebig <stonebig34@gmail.com>
@@ -382,10 +454,12 @@ Thomas Johansson <devnull@localhost>
Thomas Kluyver <thomas@kluyver.me.uk>
Thomas Smith <smithtg@ncbi.nlm.nih.gov>
Tim D. Smith <github@tim-smith.us>
Tim Gates <tim.gates@iress.com>
Tim Harder <radhermit@gmail.com>
Tim Heap <tim@timheap.me>
tim smith <github@tim-smith.us>
tinruufu <tinruufu@gmail.com>
Tom Forbes <tom@tomforb.es>
Tom Freudenheim <tom.freudenheim@onepeloton.com>
Tom V <tom@viner.tv>
Tomer Chachamu <tomer.chachamu@gmail.com>
@@ -405,14 +479,18 @@ W. Trevor King <wking@drexel.edu>
Wil Tan <wil@dready.org>
Wilfred Hughes <me@wilfred.me.uk>
William ML Leslie <william.leslie.ttg@gmail.com>
William T Olson <trevor@heytrevor.com>
wim glenn <wim.glenn@gmail.com>
Wolfgang Maier <wolfgang.maier@biologie.uni-freiburg.de>
Xavier Fernandez <xav.fernandez@gmail.com>
Xavier Fernandez <xavier.fernandez@polyconseil.fr>
xoviat <xoviat@users.noreply.github.com>
xtreak <tir.karthi@gmail.com>
YAMAMOTO Takashi <yamamoto@midokura.com>
Yen Chi Hsuan <yan12125@gmail.com>
Yoval P <yoval@gmx.com>
Yu Jian <askingyj@gmail.com>
Yuan Jing Vincent Yan <yyan82@bloomberg.net>
Zearin <zearin@gonk.net>
Zearin <Zearin@users.noreply.github.com>
Zhiping Deng <kofreestyler@gmail.com>
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2008-2018 The pip developers (see AUTHORS.txt file)
Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
5 changes: 4 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -6,14 +6,16 @@ include pyproject.toml

include src/pip/_vendor/README.rst
include src/pip/_vendor/vendor.txt
recursive-include src/pip/_vendor *LICENSE*
recursive-include src/pip/_vendor *COPYING*

include docs/docutils.conf

exclude .coveragerc
exclude .mailmap
exclude .appveyor.yml
exclude .travis.yml
exclude tox.ini
exclude appveyor.yml

recursive-include src/pip/_vendor *.pem
recursive-include docs Makefile *.rst *.py *.bat
@@ -23,6 +25,7 @@ exclude src/pip/_vendor/six/moves
recursive-exclude src/pip/_vendor *.pyi

prune .github
prune .azure-pipelines
prune docs/build
prune news
prune tasks
291 changes: 288 additions & 3 deletions NEWS.rst

Large diffs are not rendered by default.

60 changes: 36 additions & 24 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,42 +1,54 @@
pip
===

The `PyPA recommended`_ tool for installing Python packages.
pip - The Python Package Installer
==================================

.. image:: https://img.shields.io/pypi/v/pip.svg
:target: https://pypi.org/project/pip/

.. image:: https://img.shields.io/travis/pypa/pip/master.svg?label=travis-ci
:target: https://travis-ci.org/pypa/pip

.. image:: https://img.shields.io/appveyor/ci/pypa/pip.svg?label=appveyor-ci
:target: https://ci.appveyor.com/project/pypa/pip/history

.. image:: https://readthedocs.org/projects/pip/badge/?version=latest
:target: https://pip.pypa.io/en/latest

pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.

Please take a look at our documentation for how to install and use pip:

* `Installation`_
* `Documentation`_
* `Changelog`_
* `GitHub Page`_
* `Issue Tracking`_
* `User mailing list`_
* `Usage`_

Updates are released regularly, with a new version every 3 months. More details can be found in our documentation:

* `Release notes`_
* `Release process`_

If you find bugs, need help, or want to talk to the developers please use our mailing lists or chat rooms:

* `Issue tracking`_
* `Discourse channel`_
* `User IRC`_

If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:

* `GitHub page`_
* `Dev documentation`_
* `Dev mailing list`_
* User IRC: #pypa on Freenode.
* Dev IRC: #pypa-dev on Freenode.
* `Dev IRC`_

Code of Conduct
---------------

Everyone interacting in the pip project's codebases, issue trackers, chat
rooms and mailing lists is expected to follow the `PyPA Code of Conduct`_.
rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_.

.. _PyPA recommended: https://packaging.python.org/en/latest/current/
.. _package installer: https://packaging.python.org/en/latest/current/
.. _Python Package Index: https://pypi.org
.. _Installation: https://pip.pypa.io/en/stable/installing.html
.. _Documentation: https://pip.pypa.io/en/stable/
.. _Changelog: https://pip.pypa.io/en/stable/news.html
.. _GitHub Page: https://github.com/pypa/pip
.. _Issue Tracking: https://github.com/pypa/pip/issues
.. _User mailing list: https://groups.google.com/forum/#!forum/python-virtualenv
.. _Usage: https://pip.pypa.io/en/stable/
.. _Release notes: https://pip.pypa.io/en/stable/news.html
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
.. _GitHub page: https://github.com/pypa/pip
.. _Dev documentation: https://pip.pypa.io/en/latest/development
.. _Issue tracking: https://github.com/pypa/pip/issues
.. _Discourse channel: https://discuss.python.org/c/packaging
.. _Dev mailing list: https://groups.google.com/forum/#!forum/pypa-dev
.. _User IRC: https://webchat.freenode.net/?channels=%23pypa
.. _Dev IRC: https://webchat.freenode.net/?channels=%23pypa-dev
.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/
32 changes: 25 additions & 7 deletions docs/html/conf.py
Original file line number Diff line number Diff line change
@@ -83,7 +83,7 @@
break

# We have this here because readthedocs plays tricks sometimes and there seems
# to be a hiesenbug, related to the version of pip discovered. This is here to
# to be a heisenbug, related to the version of pip discovered. This is here to
# help debug that if someone decides to do that in the future.
print(version)

@@ -173,9 +173,21 @@
# using the given strftime format.
html_last_updated_fmt = '%b %d, %Y'

# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
smart_quotes = False
# If true, the Docutils Smart Quotes transform (originally based on
# SmartyPants) will be used to convert characters like quotes and dashes
# to typographically correct entities. The default is True.
smartquotes = True

# This string, for use with Docutils 0.14 or later, customizes the
# SmartQuotes transform. The default of "qDe" converts normal quote
# characters ('"' and "'"), en and em dashes ("--" and "---"), and
# ellipses "...".
# For now, we disable the conversion of dashes so that long options
# like "--find-links" won't render as "-find-links" if included in the
# text in places where monospaced type can't be used. For example, backticks
# can't be used inside roles like :ref:`--no-index <--no-index>` because
# of nesting.
smartquotes_action = "qe"

# Custom sidebar templates, maps document names to template names.
html_sidebars = {
@@ -263,9 +275,15 @@

# Here, we crawl the entire man/commands/ directory and list every file with
# appropriate name and details
for fname in glob.glob('man/commands/*.rst'):
fname_base = fname[4:-4]
outname = 'pip-' + fname_base[13:]
man_dir = os.path.join(docs_dir, 'man/')
raw_subcommands = glob.glob(os.path.join(man_dir, 'commands/*.rst'))
if not raw_subcommands:
raise FileNotFoundError(
'The individual subcommand manpages could not be found!'
)
for fname in raw_subcommands:
fname_base = fname[len(man_dir):-4]
outname = 'pip-' + fname_base[9:]
description = u'description of {} command'.format(
outname.replace('-', ' ')
)
11 changes: 8 additions & 3 deletions docs/html/development/contributing.rst
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ Automated Testing
=================

All pull requests and merges to 'master' branch are tested using `Travis CI`_
and `Appveyor CI`_ based on our `.travis.yml`_ and `appveyor.yml`_ files.
and `Appveyor CI`_ based on our `.travis.yml`_ and `.appveyor.yml`_ files.

You can find the status and results to the CI runs for your PR on GitHub's Web
UI for the pull request. You can also find links to the CI services' pages for
@@ -226,8 +226,13 @@ Becoming a maintainer

If you want to become an official maintainer, start by helping out.

As a first step, we welcome you to triage issues on pip's issue tracker. pip
maintainers provide triage abilities to contributors once they have been around
for some time and contributed positively to the project. This is optional and highly
recommended for becoming a pip maintainer.

Later, when you think you're ready, get in touch with one of the maintainers
and they will initiate a vote.
and they will initiate a vote among the existing maintainers.

.. note::

@@ -245,5 +250,5 @@ and they will initiate a vote.
.. _`Travis CI`: https://travis-ci.org/
.. _`Appveyor CI`: https://www.appveyor.com/
.. _`.travis.yml`: https://github.com/pypa/pip/blob/master/.travis.yml
.. _`appveyor.yml`: https://github.com/pypa/pip/blob/master/appveyor.yml
.. _`.appveyor.yml`: https://github.com/pypa/pip/blob/master/.appveyor.yml
.. _`towncrier`: https://pypi.org/project/towncrier/
18 changes: 12 additions & 6 deletions docs/html/development/getting-started.rst
Original file line number Diff line number Diff line change
@@ -8,15 +8,25 @@ This document is meant to get you setup to work on pip and to act as a guide and
reference to the the development setup. If you face any issues during this
process, please `open an issue`_ about it on the issue tracker.

Development tools
=================
Development Environment
-----------------------

pip uses :pypi:`tox` for testing against multiple different Python environments
and ensuring reproducible environments for linting and building documentation.

For developing pip, you need to install ``tox`` on your system. Often, you can
just do ``python -m pip install tox`` to install and use it.

Running pip From Source Tree
----------------------------

To run the pip executable from your source tree during development, run pip
from the ``src`` directory:

.. code-block:: console
$ python src/pip --version
Running Tests
-------------

@@ -73,9 +83,6 @@ The above commands run the linters on Python 2 followed by Python 3.
.. note::

Do not silence errors from flake8 with ``# noqa`` comments or otherwise.
The only exception to this is silencing unused-import errors for imports
related to static type checking as currently `flake8 does not understand
PEP 484 type-comments`_.

Running mypy
------------
@@ -105,6 +112,5 @@ To build it locally, run:
The built documentation can be found in the ``docs/build`` folder.

.. _`open an issue`: https://github.com/pypa/pip/issues/new?title=Trouble+with+pip+development+environment
.. _`flake8 does not understand PEP 484 type-comments`: https://gitlab.com/pycqa/flake8/issues/118
.. _`PEP 484 type-comments`: https://www.python.org/dev/peps/pep-0484/#suggested-syntax-for-python-2-7-and-straddling-code
.. _`rich CLI`: https://docs.pytest.org/en/latest/usage.html#specifying-tests-selecting-tests
1 change: 1 addition & 0 deletions docs/html/development/index.rst
Original file line number Diff line number Diff line change
@@ -15,6 +15,7 @@ or the `pypa-dev mailing list`_, to ask questions or get involved.
getting-started
contributing
release-process
vendoring-policy

.. note::

19 changes: 19 additions & 0 deletions docs/html/development/release-process.rst
Original file line number Diff line number Diff line change
@@ -57,6 +57,21 @@ their merits.
``pip._internal.utils.deprecation.deprecated``. The function is not a part of
pip's public API.

Python 2 support
----------------

pip will continue to ensure that it runs on Python 2.7 after the CPython 2.7
EOL date. Support for Python 2.7 will be dropped, if bugs in Python 2.7 itself
make this necessary (which is unlikely) or Python 2 usage reduces to a level
where pip maintainers feel it is OK to drop support. The same approach is used
to determine when to drop support for other Python versions.

However, bugs reported with pip which only occur on Python 2.7 would likely not
be addressed directly by pip's maintainers. Pull Requests to fix Python 2.7
only bugs will be considered, and merged (subject to normal review processes).
Note that there may be delays due to the lack of developer resources for
reviewing such pull requests.


Release Process
===============
@@ -83,6 +98,9 @@ Creating a new release
#. Push all of the changes including the tag.
#. Regenerate the ``get-pip.py`` script in the `get-pip repository`_ (as
documented there) and commit the results.
#. Submit a Pull Request to `CPython`_ adding the new version of pip (and upgrading
setuptools) to ``Lib/ensurepip/_bundled``, removing the existing version, and
adjusting the versions listed in ``Lib/ensurepip/__init__.py``.

Creating a bug-fix release
--------------------------
@@ -102,3 +120,4 @@ order to create one of these the changes should already be merged into the
the above release process starting with step 4.

.. _`get-pip repository`: https://github.com/pypa/get-pip
.. _`CPython`: https://github.com/pypa/cpython
1 change: 1 addition & 0 deletions docs/html/development/vendoring-policy.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. include:: ../../../src/pip/_vendor/README.rst
45 changes: 35 additions & 10 deletions docs/html/index.rst
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
pip
===
pip - The Python Package Installer
==================================

`User list <https://groups.google.com/forum/#!forum/python-virtualenv>`_ |
`Dev list <https://groups.google.com/forum/#!forum/pypa-dev>`_ |
`GitHub <https://github.com/pypa/pip>`_ |
`PyPI <https://pypi.org/project/pip/>`_ |
User IRC: #pypa |
Dev IRC: #pypa-dev
pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.

The `PyPA recommended <https://packaging.python.org/en/latest/current/>`_ tool
for installing Python packages.
Please take a look at our documentation for how to install and use pip:

.. toctree::
:maxdepth: 1
@@ -20,3 +14,34 @@ for installing Python packages.
reference/index
development/index
news

If you find bugs, need help, or want to talk to the developers please use our mailing lists or chat rooms:

* `Issue tracking`_
* `Discourse channel`_
* `User IRC`_

If you want to get involved head over to GitHub to get the source code and feel free to jump on the developer mailing lists and chat rooms:

* `GitHub page`_
* `Dev mailing list`_
* `Dev IRC`_

Code of Conduct
---------------

Everyone interacting in the pip project's codebases, issue trackers, chat
rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_.

.. _package installer: https://packaging.python.org/en/latest/current/
.. _Python Package Index: https://pypi.org
.. _Installation: https://pip.pypa.io/en/stable/installing.html
.. _Documentation: https://pip.pypa.io/en/stable/
.. _Changelog: https://pip.pypa.io/en/stable/news.html
.. _GitHub page: https://github.com/pypa/pip
.. _Issue tracking: https://github.com/pypa/pip/issues
.. _Discourse channel: https://discuss.python.org/c/packaging
.. _Dev mailing list: https://groups.google.com/forum/#!forum/pypa-dev
.. _User IRC: https://webchat.freenode.net/?channels=%23pypa
.. _Dev IRC: https://webchat.freenode.net/?channels=%23pypa-dev
.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/
4 changes: 2 additions & 2 deletions docs/html/installing.rst
Original file line number Diff line number Diff line change
@@ -77,7 +77,7 @@ Install behind a proxy::
python get-pip.py --proxy="http://[user:passwd@]proxy.server:port"

``get-pip.py`` can also be used to install a specified combination of ``pip``,
``setuptools``, and ``wheel`` using the same requirements syntax as ``pip``::
``setuptools``, and ``wheel`` using the same requirements syntax as pip::

python get-pip.py pip==9.0.2 wheel==0.30.0 setuptools==28.8.0

@@ -109,7 +109,7 @@ On Windows [4]_::
Python and OS Compatibility
---------------------------

pip works with CPython versions 2.7, 3.4, 3.5, 3.6, 3.7 and also pypy.
pip works with CPython versions 2.7, 3.5, 3.6, 3.7 and also PyPy.

This means pip works on the latest patch version of each of these minor
versions. Previous patch versions are supported on a best effort approach.
1 change: 1 addition & 0 deletions docs/html/reference/index.rst
Original file line number Diff line number Diff line change
@@ -17,3 +17,4 @@ Reference Guide
pip_config
pip_wheel
pip_hash
pip_debug
113 changes: 76 additions & 37 deletions docs/html/reference/pip.rst
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ when decision is needed.

*(s)witch*
Only relevant to VCS checkout. Attempt to switch the checkout
to the appropriate url and/or revision.
to the appropriate URL and/or revision.
*(i)gnore*
Abort current operation (e.g. don't copy file, don't create archive,
don't modify a checkout).
@@ -71,13 +71,13 @@ when decision is needed.
Build System Interface
======================

Pip builds packages by invoking the build system. Presently, the only supported
build system is ``setuptools``, but in the future, pip will support :pep:`517`
which allows projects to specify an alternative build system in a
``pyproject.toml`` file. As well as package building, the build system is also
invoked to install packages direct from source. This is handled by invoking
the build system to build a wheel, and then installing from that wheel. The
built wheel is cached locally by pip to avoid repeated identical builds.
Pip builds packages by invoking the build system. By default, builds will use
``setuptools``, but if a project specifies a different build system using a
``pyproject.toml`` file, as per :pep:`517`, pip will use that instead. As well
as package building, the build system is also invoked to install packages
direct from source. This is handled by invoking the build system to build a
wheel, and then installing from that wheel. The built wheel is cached locally
by pip to avoid repeated identical builds.

The current interface to the build system is via the ``setup.py`` command line
script - all build actions are defined in terms of the specific ``setup.py``
@@ -86,13 +86,16 @@ command line that will be run to invoke the required action.
Setuptools Injection
~~~~~~~~~~~~~~~~~~~~

As noted above, the supported build system is ``setuptools``. However, not all
packages use ``setuptools`` in their build scripts. To support projects that
use "pure ``distutils``", pip injects ``setuptools`` into ``sys.modules``
before invoking ``setup.py``. The injection should be transparent to
``distutils``-based projects, but 3rd party build tools wishing to provide a
``setup.py`` emulating the commands pip requires may need to be aware that it
takes place.
When :pep:`517` is not used, the supported build system is ``setuptools``.
However, not all packages use ``setuptools`` in their build scripts. To support
projects that use "pure ``distutils``", pip injects ``setuptools`` into
``sys.modules`` before invoking ``setup.py``. The injection should be
transparent to ``distutils``-based projects, but 3rd party build tools wishing
to provide a ``setup.py`` emulating the commands pip requires may need to be
aware that it takes place.

Projects using :pep:`517` *must* explicitly use setuptools - pip does not do
the above injection process in this case.

Build System Output
~~~~~~~~~~~~~~~~~~~
@@ -113,13 +116,20 @@ unexpected byte sequences to Python-style hexadecimal escape sequences
(``"\x80\xff"``, etc). However, it is still possible for output to be displayed
using an incorrect encoding (mojibake).

PEP 518 Support
~~~~~~~~~~~~~~~
Under :pep:`517`, handling of build tool output is the backend's responsibility,
and pip simply displays the output produced by the backend. (Backends, however,
will likely still have to address the issues described above).

PEP 517 and 518 Support
~~~~~~~~~~~~~~~~~~~~~~~

As of 10.0, pip supports projects declaring dependencies that are required at
install time using a ``pyproject.toml`` file, in the form described in
:pep:`518`. When building a project, pip will install the required dependencies
locally, and make them available to the build process.
As of version 10.0, pip supports projects declaring dependencies that are
required at install time using a ``pyproject.toml`` file, in the form described
in :pep:`518`. When building a project, pip will install the required
dependencies locally, and make them available to the build process.
Furthermore, from version 19.0 onwards, pip supports projects specifying the
build backend they use in ``pyproject.toml``, in the form described in
:pep:`517`.

When making build requirements available, pip does so in an *isolated
environment*. That is, pip does not install those requirements into the user's
@@ -135,29 +145,58 @@ explicitly manage the build environment. For such workflows, build isolation
can be problematic. If this is the case, pip provides a
``--no-build-isolation`` flag to disable build isolation. Users supplying this
flag are responsible for ensuring the build environment is managed
appropriately.
appropriately (including ensuring that all required build dependencies are
installed).

By default, pip will continue to use the legacy (direct ``setup.py`` execution
based) build processing for projects that do not have a ``pyproject.toml`` file.
Projects with a ``pyproject.toml`` file will use a :pep:`517` backend. Projects
with a ``pyproject.toml`` file, but which don't have a ``build-system`` section,
will be assumed to have the following backend settings::

[build-system]
requires = ["setuptools>=40.8.0", "wheel"]
build-backend = "setuptools.build_meta:__legacy__"

.. note::

``setuptools`` 40.8.0 is the first version of setuptools that offers a
:pep:`517` backend that closely mimics directly executing ``setup.py``.

If a project has ``[build-system]``, but no ``build-backend``, pip will also use
``setuptools.build_meta:__legacy__``, but will expect the project requirements
to include ``setuptools`` and ``wheel`` (and will report an error if the
installed version of ``setuptools`` is not recent enough).

If a user wants to explicitly request :pep:`517` handling even though a project
doesn't have a ``pyproject.toml`` file, this can be done using the
``--use-pep517`` command line option. Similarly, to request legacy processing
even though ``pyproject.toml`` is present, the ``--no-use-pep517`` option is
available (although obviously it is an error to choose ``--no-use-pep517`` if
the project has no ``setup.py``, or explicitly requests a build backend). As
with other command line flags, pip recognises the ``PIP_USE_PEP517``
environment veriable and a ``use-pep517`` config file option (set to true or
false) to set this option globally. Note that overriding pip's choice of
whether to use :pep:`517` processing in this way does *not* affect whether pip
will use an isolated build environment (which is controlled via
``--no-build-isolation`` as noted above).

Except in the case noted above (projects with no :pep:`518` ``[build-system]``
section in ``pyproject.toml``), pip will never implicitly install a build
system. Projects **must** ensure that the correct build system is listed in
their ``requires`` list (this applies even if pip assumes that the
``setuptools`` backend is being used, as noted above).

.. _pep-518-limitations:

**Limitations**:

* until :pep:`517` support is added, ``setuptools`` and ``wheel`` **must** be
included in the list of build requirements: pip will assume these as default,
but will not automatically add them to the list of build requirements if
explicitly defined in ``pyproject.toml``.

* the current implementation only support installing build requirements from
wheels: this is a technical limitation of the implementation - source
installs would require a build step of their own, potentially recursively
triggering another :pep:`518` dependency installation process. The possible
unbounded recursion involved was not considered acceptable, and so
installation of build dependencies from source has been disabled until a safe
resolution of this issue is found.
**Historical Limitations**:

* ``pip<18.0``: only support installing build requirements from wheels, and
* ``pip<18.0``: only supports installing build requirements from wheels, and
does not support the use of environment markers and extras (only version
specifiers are respected).

* ``pip<18.1``: build dependencies using .pth files are not properly supported;
as a result namespace packages do not work under Python 3.2 and earlier.

Future Developments
~~~~~~~~~~~~~~~~~~~
28 changes: 28 additions & 0 deletions docs/html/reference/pip_debug.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
.. _`pip debug`:

pip debug
-----------

.. contents::

Usage
*****

.. pip-command-usage:: debug


.. warning::
This command is only meant for debugging.
Its options and outputs are provisional and may change without notice.


Description
***********

.. pip-command-description:: debug


Options
*******

.. pip-command-options:: debug
71 changes: 40 additions & 31 deletions docs/html/reference/pip_install.rst
Original file line number Diff line number Diff line change
@@ -71,8 +71,12 @@ the chosen version is available, it is assumed that any source is acceptable
Installation Order
++++++++++++++++++

.. note::
This section is only about installation order of runtime dependencies, and
does not apply to build dependencies (those are specified using PEP 518).

As of v6.1.0, pip installs dependencies before their dependents, i.e. in
"topological order". This is the only commitment pip currently makes related
"topological order." This is the only commitment pip currently makes related
to order. While it may be coincidentally true that pip will install things in
the order of the install arguments or in the order of the items in a
requirements file, this is not a promise.
@@ -153,8 +157,10 @@ The following options are supported:
* :ref:`--no-binary <install_--no-binary>`
* :ref:`--only-binary <install_--only-binary>`
* :ref:`--require-hashes <--require-hashes>`
* :ref:`--trusted-host <--trusted-host>`

For example, to specify :ref:`--no-index <--no-index>` and 2 :ref:`--find-links <--find-links>` locations:
For example, to specify :ref:`--no-index <--no-index>` and two
:ref:`--find-links <--find-links>` locations:

::

@@ -238,7 +244,7 @@ pip supports installing from a package index using a :term:`requirement
specifier <pypug:Requirement Specifier>`. Generally speaking, a requirement
specifier is composed of a project name followed by optional :term:`version
specifiers <pypug:Version Specifier>`. :pep:`508` contains a full specification
of the format of a requirement (``pip`` does not support the ``url_req`` form
of the format of a requirement (pip does not support the ``url_req`` form
of specifier at this time).

Some examples:
@@ -247,7 +253,7 @@ Some examples:

SomeProject
SomeProject == 1.3
SomeProject >=1.2,<.2.0
SomeProject >=1.2,<2.0
SomeProject[foo, bar]
SomeProject~=1.4.2

@@ -331,34 +337,35 @@ VCS Support
+++++++++++

pip supports installing from Git, Mercurial, Subversion and Bazaar, and detects
the type of VCS using url prefixes: "git+", "hg+", "bzr+", "svn+".
the type of VCS using URL prefixes: ``git+``, ``hg+``, ``svn+``, and ``bzr+``.

pip requires a working VCS command on your path: git, hg, svn, or bzr.
pip requires a working VCS command on your path: ``git``, ``hg``, ``svn``, or
``bzr``.

VCS projects can be installed in :ref:`editable mode <editable-installs>` (using
the :ref:`--editable <install_--editable>` option) or not.

* For editable installs, the clone location by default is "<venv
path>/src/SomeProject" in virtual environments, and "<cwd>/src/SomeProject"
* For editable installs, the clone location by default is ``<venv
path>/src/SomeProject`` in virtual environments, and
``<cwd>/src/SomeProject``
for global installs. The :ref:`--src <install_--src>` option can be used to
modify this location.
* For non-editable installs, the project is built locally in a temp dir and then
installed normally. Note that if a satisfactory version of the package is
already installed, the VCS source will not overwrite it without an `--upgrade`
flag. VCS requirements pin the package version (specified in the `setup.py`
file) of the target commit, not necessarily the commit itself.
already installed, the VCS source will not overwrite it without an
``--upgrade`` flag. VCS requirements pin the package version (specified
in the ``setup.py`` file) of the target commit, not necessarily the commit
itself.
* The :ref:`pip freeze` subcommand will record the VCS requirement specifier
(referencing a specific commit) if and only if the install is done using the
editable option.

The "project name" component of the url suffix "egg=<project name>-<version>"
The "project name" component of the URL suffix ``egg=<project name>``
is used by pip in its dependency logic to identify the project prior
to pip downloading and analyzing the metadata. The optional "version"
component of the egg name is not functionally important. It merely
provides a human-readable clue as to what version is in use. For projects
where setup.py is not in the root of project, "subdirectory" component
is used. Value of "subdirectory" component should be a path starting from root
of the project to where setup.py is located.
to pip downloading and analyzing the metadata. For projects
where ``setup.py`` is not in the root of project, the "subdirectory" component
is used. The value of the "subdirectory" component should be a path starting
from the root of the project to where ``setup.py`` is located.

So if your repository layout is:

@@ -390,11 +397,12 @@ Here are the supported forms::
[-e] git+file:///home/user/projects/MyProject#egg=MyProject
-e git+git@git.example.com:MyProject#egg=MyProject

Passing branch names, a commit hash or a tag name is possible like so::
Passing a branch name, a commit hash, a tag name or a git ref is possible like so::

[-e] git://git.example.com/MyProject.git@master#egg=MyProject
[-e] git://git.example.com/MyProject.git@v1.0#egg=MyProject
[-e] git://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject
[-e] git://git.example.com/MyProject.git@refs/pull/123/head#egg=MyProject

When passing a commit hash, specifying a full hash is preferable to a partial
hash because a full hash allows pip to operate more efficiently (e.g. by
@@ -480,16 +488,17 @@ Finding Packages
++++++++++++++++

pip searches for packages on `PyPI`_ using the
`http simple interface <https://pypi.org/simple/>`_,
`HTTP simple interface <https://pypi.org/simple/>`_,
which is documented `here <https://setuptools.readthedocs.io/en/latest/easy_install.html#package-index-api>`_
and `there <https://www.python.org/dev/peps/pep-0301/>`_
and `there <https://www.python.org/dev/peps/pep-0301/>`_.

pip offers a number of Package Index Options for modifying how packages are found.
pip offers a number of package index options for modifying how packages are
found.

pip looks for packages in a number of places, on PyPI (if not disabled via
```--no-index```), in the local filesystem, and in any additional repositories
specified via ```--find-links``` or ```--index-url```. There is no ordering in
the locations that are searched, rather they are all checked, and the "best"
pip looks for packages in a number of places: on PyPI (if not disabled via
``--no-index``), in the local filesystem, and in any additional repositories
specified via ``--find-links`` or ``--index-url``. There is no ordering in
the locations that are searched. Rather they are all checked, and the "best"
match for the requirements (in terms of version number - see :pep:`440` for
details) is selected.

@@ -713,12 +722,12 @@ Controlling setup_requires

Setuptools offers the ``setup_requires`` `setup() keyword
<https://setuptools.readthedocs.io/en/latest/setuptools.html#new-and-changed-setup-keywords>`_
for specifying dependencies that need to be present in order for the `setup.py`
script to run. Internally, Setuptools uses ``easy_install`` to fulfill these
dependencies.
for specifying dependencies that need to be present in order for the
``setup.py`` script to run. Internally, Setuptools uses ``easy_install``
to fulfill these dependencies.

pip has no way to control how these dependencies are located. None of the
Package Index Options have an effect.
package index options have an effect.

The solution is to configure a "system" or "personal" `Distutils configuration
file
@@ -847,8 +856,8 @@ Examples

$ pip install SomePackage[PDF]
$ pip install git+https://git.repo/some_pkg.git#egg=SomePackage[PDF]
$ pip install .[PDF] # project in current directory
$ pip install SomePackage[PDF]==3.0
$ pip install -e .[PDF]==3.0 # editable project in current directory
$ pip install SomePackage[PDF,EPUB] # multiple extras


11 changes: 9 additions & 2 deletions docs/html/user_guide.rst
Original file line number Diff line number Diff line change
@@ -62,6 +62,8 @@ pip can be configured to connect through a proxy server in various ways:
* using ``proxy`` in a :ref:`config-file`
* by setting the standard environment-variables ``http_proxy``, ``https_proxy``
and ``no_proxy``.
* using the environment variable ``PIP_USER_AGENT_USER_DATA`` to include
a JSON-encoded string in the user-agent variable used in pip's requests.


.. _`Requirements Files`:
@@ -443,6 +445,11 @@ is the same as calling::

pip install --find-links=http://mirror1.example.com --find-links=http://mirror2.example.com

.. note::

Environment variables set to be empty string will not be treated as false. Please use ``no``,
``false`` or ``0`` instead.


Config Precedence
-----------------
@@ -493,10 +500,10 @@ to PyPI.

First, download the archives that fulfill your requirements::

$ pip install --download DIR -r requirements.txt
$ pip download --destination-directory DIR -r requirements.txt


Note that ``pip install --download`` will look in your wheel cache first, before
Note that ``pip download`` will look in your wheel cache first, before
trying to download from PyPI. If you've never installed your requirements
before, you won't have a wheel cache for those items. In that case, if some of
your requirements don't come as wheels from PyPI, and you want wheels, then run
26 changes: 26 additions & 0 deletions docs/man/commands/debug.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
:orphan:

==========
pip-debug
==========

Description
***********

.. pip-command-description:: debug

Usage
*****

.. pip-command-usage:: debug


.. warning::
This command is only meant for debugging.
Its options and outputs are provisional and may change without notice.


Options
*******

.. pip-command-options:: debug
4 changes: 3 additions & 1 deletion docs/pip_sphinxext.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,9 @@ class PipCommandUsage(rst.Directive):

def run(self):
cmd = commands[self.arguments[0]]
usage = dedent(cmd.usage.replace('%prog', 'pip')).strip()
usage = dedent(
cmd.usage.replace('%prog', 'pip {}'.format(cmd.name))
).strip()
node = nodes.literal_block(usage, usage)
return [node]

75 changes: 75 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -20,10 +20,85 @@ exclude =
_vendor,
data
select = E,W,F
ignore = W504

[mypy]
follow_imports = silent
ignore_missing_imports = True

[mypy-pip/_internal/build_env]
strict_optional = False

[mypy-pip/_internal/cache]
strict_optional = False

[mypy-pip/_internal/cli/base_command]
strict_optional = False

[mypy-pip/_internal/cli/cmdoptions]
strict_optional = False

[mypy-pip/_internal/configuration]
strict_optional = False

[mypy-pip/_internal/index]
strict_optional = False

[mypy-pip/_internal/legacy_resolve]
strict_optional = False

[mypy-pip/_internal/locations]
strict_optional = False

[mypy-pip/_internal/models/format_control]
strict_optional = False

[mypy-pip/_internal/operations/check]
strict_optional = False

[mypy-pip/_internal/operations/freeze]
strict_optional = False

[mypy-pip/_internal/operations/prepare]
strict_optional = False

[mypy-pip/_internal/pep425tags]
strict_optional = False

[mypy-pip/_internal/req/*]
disallow_untyped_defs = True

[mypy-pip/_internal/req]
strict_optional = False

[mypy-pip/_internal/req/constructors]
strict_optional = False

[mypy-pip/_internal/req/req_file]
strict_optional = False

[mypy-pip/_internal/req/req_install]
strict_optional = False

[mypy-pip/_internal/req/req_set]
strict_optional = False

[mypy-pip/_internal/req/req_tracker]
strict_optional = False

[mypy-pip/_internal/utils/encoding]
strict_optional = False

[mypy-pip/_internal/utils/glibc]
strict_optional = False

[mypy-pip/_internal/utils/misc]
strict_optional = False

[mypy-pip/_internal/utils/ui]
strict_optional = False

[mypy-pip/_internal/wheel]
strict_optional = False

[mypy-pip/_vendor/*]
3 changes: 1 addition & 2 deletions setup.py
Original file line number Diff line number Diff line change
@@ -46,7 +46,6 @@ def find_version(*file_paths):
"Programming Language :: Python :: 2",
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.4",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
@@ -79,5 +78,5 @@ def find_version(*file_paths):
},

zip_safe=False,
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*',
)
2 changes: 1 addition & 1 deletion src/pip/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "18.1"
__version__ = "19.2"
3 changes: 1 addition & 2 deletions src/pip/_internal/__init__.py
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@
# isn't available. requests unconditionally imports urllib3's socks contrib
# module, triggering this warning. The warning breaks DEP-8 tests (because of
# the stderr output) and is just plain annoying in normal usage. I don't want
# to add socks as yet another dependency for pip, nor do I want to allow-stder
# to add socks as yet another dependency for pip, nor do I want to allow-stderr
# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to
# be done before the import of pip.vcs.
from pip._vendor.urllib3.exceptions import DependencyWarning
@@ -42,7 +42,6 @@
from pip._internal.commands import commands_dict
from pip._internal.exceptions import PipError
from pip._internal.utils import deprecation
from pip._internal.vcs import git, mercurial, subversion, bazaar # noqa
from pip._vendor.urllib3.exceptions import InsecureRequestWarning

logger = logging.getLogger(__name__)
200 changes: 138 additions & 62 deletions src/pip/_internal/build_env.py
Original file line number Diff line number Diff line change
@@ -4,122 +4,198 @@
import logging
import os
import sys
import textwrap
from collections import OrderedDict
from distutils.sysconfig import get_python_lib
from sysconfig import get_paths

from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet

from pip import __file__ as pip_location
from pip._internal.utils.misc import call_subprocess
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.utils.ui import open_spinner

if MYPY_CHECK_RUNNING:
from typing import Tuple, Set, Iterable, Optional, List
from pip._internal.index import PackageFinder

logger = logging.getLogger(__name__)


class _Prefix:

def __init__(self, path):
# type: (str) -> None
self.path = path
self.setup = False
self.bin_dir = get_paths(
'nt' if os.name == 'nt' else 'posix_prefix',
vars={'base': path, 'platbase': path}
)['scripts']
# Note: prefer distutils' sysconfig to get the
# library paths so PyPy is correctly supported.
purelib = get_python_lib(plat_specific=False, prefix=path)
platlib = get_python_lib(plat_specific=True, prefix=path)
if purelib == platlib:
self.lib_dirs = [purelib]
else:
self.lib_dirs = [purelib, platlib]


class BuildEnvironment(object):
"""Creates and manages an isolated environment to install build deps
"""

def __init__(self):
# type: () -> None
self._temp_dir = TempDirectory(kind="build-env")
self._temp_dir.create()

@property
def path(self):
return self._temp_dir.path
self._prefixes = OrderedDict((
(name, _Prefix(os.path.join(self._temp_dir.path, name)))
for name in ('normal', 'overlay')
))

self._bin_dirs = [] # type: List[str]
self._lib_dirs = [] # type: List[str]
for prefix in reversed(list(self._prefixes.values())):
self._bin_dirs.append(prefix.bin_dir)
self._lib_dirs.extend(prefix.lib_dirs)

# Customize site to:
# - ensure .pth files are honored
# - prevent access to system site packages
system_sites = {
os.path.normcase(site) for site in (
get_python_lib(plat_specific=False),
get_python_lib(plat_specific=True),
)
}
self._site_dir = os.path.join(self._temp_dir.path, 'site')
if not os.path.exists(self._site_dir):
os.mkdir(self._site_dir)
with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp:
fp.write(textwrap.dedent(
'''
import os, site, sys
# First, drop system-sites related paths.
original_sys_path = sys.path[:]
known_paths = set()
for path in {system_sites!r}:
site.addsitedir(path, known_paths=known_paths)
system_paths = set(
os.path.normcase(path)
for path in sys.path[len(original_sys_path):]
)
original_sys_path = [
path for path in original_sys_path
if os.path.normcase(path) not in system_paths
]
sys.path = original_sys_path
# Second, add lib directories.
# ensuring .pth file are processed.
for path in {lib_dirs!r}:
assert not path in sys.path
site.addsitedir(path)
'''
).format(system_sites=system_sites, lib_dirs=self._lib_dirs))

def __enter__(self):
self.save_path = os.environ.get('PATH', None)
self.save_pythonpath = os.environ.get('PYTHONPATH', None)
self.save_nousersite = os.environ.get('PYTHONNOUSERSITE', None)

install_scheme = 'nt' if (os.name == 'nt') else 'posix_prefix'
install_dirs = get_paths(install_scheme, vars={
'base': self.path,
'platbase': self.path,
self._save_env = {
name: os.environ.get(name, None)
for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH')
}

path = self._bin_dirs[:]
old_path = self._save_env['PATH']
if old_path:
path.extend(old_path.split(os.pathsep))

pythonpath = [self._site_dir]

os.environ.update({
'PATH': os.pathsep.join(path),
'PYTHONNOUSERSITE': '1',
'PYTHONPATH': os.pathsep.join(pythonpath),
})

scripts = install_dirs['scripts']
if self.save_path:
os.environ['PATH'] = scripts + os.pathsep + self.save_path
else:
os.environ['PATH'] = scripts + os.pathsep + os.defpath

# Note: prefer distutils' sysconfig to get the
# library paths so PyPy is correctly supported.
purelib = get_python_lib(plat_specific=0, prefix=self.path)
platlib = get_python_lib(plat_specific=1, prefix=self.path)
if purelib == platlib:
lib_dirs = purelib
else:
lib_dirs = purelib + os.pathsep + platlib
if self.save_pythonpath:
os.environ['PYTHONPATH'] = lib_dirs + os.pathsep + \
self.save_pythonpath
else:
os.environ['PYTHONPATH'] = lib_dirs

os.environ['PYTHONNOUSERSITE'] = '1'

return self.path

def __exit__(self, exc_type, exc_val, exc_tb):
def restore_var(varname, old_value):
for varname, old_value in self._save_env.items():
if old_value is None:
os.environ.pop(varname, None)
else:
os.environ[varname] = old_value

restore_var('PATH', self.save_path)
restore_var('PYTHONPATH', self.save_pythonpath)
restore_var('PYTHONNOUSERSITE', self.save_nousersite)

def cleanup(self):
# type: () -> None
self._temp_dir.cleanup()

def missing_requirements(self, reqs):
"""Return a list of the requirements from reqs that are not present
def check_requirements(self, reqs):
# type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]
"""Return 2 sets:
- conflicting requirements: set of (installed, wanted) reqs tuples
- missing requirements: set of reqs
"""
missing = []
with self:
ws = WorkingSet(os.environ["PYTHONPATH"].split(os.pathsep))
missing = set()
conflicting = set()
if reqs:
ws = WorkingSet(self._lib_dirs)
for req in reqs:
try:
if ws.find(Requirement.parse(req)) is None:
missing.append(req)
except VersionConflict:
missing.append(req)
return missing

def install_requirements(self, finder, requirements, message):
missing.add(req)
except VersionConflict as e:
conflicting.add((str(e.args[0].as_requirement()),
str(e.args[1])))
return conflicting, missing

def install_requirements(
self,
finder, # type: PackageFinder
requirements, # type: Iterable[str]
prefix_as_string, # type: str
message # type: Optional[str]
):
# type: (...) -> None
prefix = self._prefixes[prefix_as_string]
assert not prefix.setup
prefix.setup = True
if not requirements:
return
args = [
sys.executable, '-m', 'pip', 'install', '--ignore-installed',
'--no-user', '--prefix', self.path, '--no-warn-script-location',
]
sys.executable, os.path.dirname(pip_location), 'install',
'--ignore-installed', '--no-user', '--prefix', prefix.path,
'--no-warn-script-location',
] # type: List[str]
if logger.getEffectiveLevel() <= logging.DEBUG:
args.append('-v')
for format_control in ('no_binary', 'only_binary'):
formats = getattr(finder.format_control, format_control)
args.extend(('--' + format_control.replace('_', '-'),
','.join(sorted(formats or {':none:'}))))
if finder.index_urls:
args.extend(['-i', finder.index_urls[0]])
for extra_index in finder.index_urls[1:]:

index_urls = finder.index_urls
if index_urls:
args.extend(['-i', index_urls[0]])
for extra_index in index_urls[1:]:
args.extend(['--extra-index-url', extra_index])
else:
args.append('--no-index')
for link in finder.find_links:
args.extend(['--find-links', link])
for _, host, _ in finder.secure_origins:

for host in finder.trusted_hosts:
args.extend(['--trusted-host', host])
if finder.allow_all_prereleases:
args.append('--pre')
if finder.process_dependency_links:
args.append('--process-dependency-links')
args.append('--')
args.extend(requirements)
with open_spinner(message) as spinner:
call_subprocess(args, show_stdout=False, spinner=spinner)
call_subprocess(args, spinner=spinner)


class NoOpBuildEnvironment(BuildEnvironment):
@@ -138,5 +214,5 @@ def __exit__(self, exc_type, exc_val, exc_tb):
def cleanup(self):
pass

def install_requirements(self, finder, requirements, message):
def install_requirements(self, finder, requirements, prefix, message):
raise NotImplementedError()
24 changes: 23 additions & 1 deletion src/pip/_internal/cache.py
Original file line number Diff line number Diff line change
@@ -8,12 +8,17 @@

from pip._vendor.packaging.utils import canonicalize_name

from pip._internal.download import path_to_url
from pip._internal.models.link import Link
from pip._internal.utils.compat import expanduser
from pip._internal.utils.misc import path_to_url
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.wheel import InvalidWheelFilename, Wheel

if MYPY_CHECK_RUNNING:
from typing import Optional, Set, List, Any
from pip._internal.index import FormatControl

logger = logging.getLogger(__name__)


@@ -29,6 +34,7 @@ class Cache(object):
"""

def __init__(self, cache_dir, format_control, allowed_formats):
# type: (str, FormatControl, Set[str]) -> None
super(Cache, self).__init__()
self.cache_dir = expanduser(cache_dir) if cache_dir else None
self.format_control = format_control
@@ -38,6 +44,7 @@ def __init__(self, cache_dir, format_control, allowed_formats):
assert self.allowed_formats.union(_valid_formats) == _valid_formats

def _get_cache_path_parts(self, link):
# type: (Link) -> List[str]
"""Get parts of part that must be os.path.joined with cache_dir
"""

@@ -63,6 +70,7 @@ def _get_cache_path_parts(self, link):
return parts

def _get_candidates(self, link, package_name):
# type: (Link, Optional[str]) -> List[Any]
can_not_cache = (
not self.cache_dir or
not package_name or
@@ -87,23 +95,27 @@ def _get_candidates(self, link, package_name):
raise

def get_path_for_link(self, link):
# type: (Link) -> str
"""Return a directory to store cached items in for link.
"""
raise NotImplementedError()

def get(self, link, package_name):
# type: (Link, Optional[str]) -> Link
"""Returns a link to a cached item if it exists, otherwise returns the
passed link.
"""
raise NotImplementedError()

def _link_for_candidate(self, link, candidate):
# type: (Link, str) -> Link
root = self.get_path_for_link(link)
path = os.path.join(root, candidate)

return Link(path_to_url(path))

def cleanup(self):
# type: () -> None
pass


@@ -112,11 +124,13 @@ class SimpleWheelCache(Cache):
"""

def __init__(self, cache_dir, format_control):
# type: (str, FormatControl) -> None
super(SimpleWheelCache, self).__init__(
cache_dir, format_control, {"binary"}
)

def get_path_for_link(self, link):
# type: (Link) -> str
"""Return a directory to store cached wheels for link
Because there are M wheels for any one sdist, we provide a directory
@@ -137,6 +151,7 @@ def get_path_for_link(self, link):
return os.path.join(self.cache_dir, "wheels", *parts)

def get(self, link, package_name):
# type: (Link, Optional[str]) -> Link
candidates = []

for wheel_name in self._get_candidates(link, package_name):
@@ -160,6 +175,7 @@ class EphemWheelCache(SimpleWheelCache):
"""

def __init__(self, format_control):
# type: (FormatControl) -> None
self._temp_dir = TempDirectory(kind="ephem-wheel-cache")
self._temp_dir.create()

@@ -168,6 +184,7 @@ def __init__(self, format_control):
)

def cleanup(self):
# type: () -> None
self._temp_dir.cleanup()


@@ -179,24 +196,29 @@ class WheelCache(Cache):
"""

def __init__(self, cache_dir, format_control):
# type: (str, FormatControl) -> None
super(WheelCache, self).__init__(
cache_dir, format_control, {'binary'}
)
self._wheel_cache = SimpleWheelCache(cache_dir, format_control)
self._ephem_cache = EphemWheelCache(format_control)

def get_path_for_link(self, link):
# type: (Link) -> str
return self._wheel_cache.get_path_for_link(link)

def get_ephem_path_for_link(self, link):
# type: (Link) -> str
return self._ephem_cache.get_path_for_link(link)

def get(self, link, package_name):
# type: (Link, Optional[str]) -> Link
retval = self._wheel_cache.get(link, package_name)
if retval is link:
retval = self._ephem_cache.get(link, package_name)
return retval

def cleanup(self):
# type: () -> None
self._wheel_cache.cleanup()
self._ephem_cache.cleanup()
124 changes: 96 additions & 28 deletions src/pip/_internal/cli/base_command.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
"""Base Command class, and related routines"""
from __future__ import absolute_import
from __future__ import absolute_import, print_function

import logging
import logging.config
import optparse
import os
import platform
import sys
import traceback

from pip._internal.cli import cmdoptions
from pip._internal.cli.cmdoptions import make_search_scope
from pip._internal.cli.parser import (
ConfigOptionParser, UpdatingDefaultsHelpFormatter,
)
@@ -21,18 +24,24 @@
UninstallationError,
)
from pip._internal.index import PackageFinder
from pip._internal.locations import running_under_virtualenv
from pip._internal.models.selection_prefs import SelectionPreferences
from pip._internal.models.target_python import TargetPython
from pip._internal.req.constructors import (
install_req_from_editable, install_req_from_line,
)
from pip._internal.req.req_file import parse_requirements
from pip._internal.utils.logging import setup_logging
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
from pip._internal.utils.misc import get_prog, normalize_path
from pip._internal.utils.outdated import pip_version_check
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.utils.virtualenv import running_under_virtualenv

if MYPY_CHECK_RUNNING:
from typing import Optional # noqa: F401
from typing import Optional, List, Tuple, Any
from optparse import Values
from pip._internal.cache import WheelCache
from pip._internal.req.req_set import RequirementSet

__all__ = ['Command']

@@ -42,10 +51,10 @@
class Command(object):
name = None # type: Optional[str]
usage = None # type: Optional[str]
hidden = False # type: bool
ignore_require_venv = False # type: bool

def __init__(self, isolated=False):
# type: (bool) -> None
parser_kw = {
'usage': self.usage,
'prog': '%s %s' % (get_prog(), self.name),
@@ -69,14 +78,34 @@ def __init__(self, isolated=False):
)
self.parser.add_option_group(gen_opts)

def run(self, options, args):
# type: (Values, List[Any]) -> Any
raise NotImplementedError

@classmethod
def _get_index_urls(cls, options):
"""Return a list of index urls from user-provided options."""
index_urls = []
if not getattr(options, "no_index", False):
url = getattr(options, "index_url", None)
if url:
index_urls.append(url)
urls = getattr(options, "extra_index_urls", None)
if urls:
index_urls.extend(urls)
# Return None rather than an empty list
return index_urls or None

def _build_session(self, options, retries=None, timeout=None):
# type: (Values, Optional[int], Optional[int]) -> PipSession
session = PipSession(
cache=(
normalize_path(os.path.join(options.cache_dir, "http"))
if options.cache_dir else None
),
retries=retries if retries is not None else options.retries,
insecure_hosts=options.trusted_hosts,
index_urls=self._get_index_urls(options),
)

# Handle custom ca-bundles from the user
@@ -106,21 +135,37 @@ def _build_session(self, options, retries=None, timeout=None):
return session

def parse_args(self, args):
# type: (List[str]) -> Tuple
# factored out for testability
return self.parser.parse_args(args)

def main(self, args):
# type: (List[str]) -> int
options, args = self.parse_args(args)

# Set verbosity so that it can be used elsewhere.
self.verbosity = options.verbose - options.quiet

setup_logging(
level_number = setup_logging(
verbosity=self.verbosity,
no_color=options.no_color,
user_log_file=options.log,
)

if sys.version_info[:2] == (2, 7):
message = (
"A future version of pip will drop support for Python 2.7. "
"More details about Python 2 support in pip, can be found at "
"https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa
)
if platform.python_implementation() == "CPython":
message = (
"Python 2.7 will reach the end of its life on January "
"1st, 2020. Please upgrade your Python as Python 2.7 "
"won't be maintained after that date. "
) + message
deprecated(message, replacement=None, gone_in=None)

# TODO: Try to get these passing down from the command?
# without resorting to os.environ to hold these.
# This also affects isolated builds and it should.
@@ -156,9 +201,17 @@ def main(self, args):

return ERROR
except CommandError as exc:
logger.critical('ERROR: %s', exc)
logger.critical('%s', exc)
logger.debug('Exception information:', exc_info=True)

return ERROR
except BrokenStdoutLoggingError:
# Bypass our logger and write any remaining messages to stderr
# because stdout no longer works.
print('ERROR: Pipe to stdout was broken', file=sys.stderr)
if level_number <= logging.DEBUG:
traceback.print_exc(file=sys.stderr)

return ERROR
except KeyboardInterrupt:
logger.critical('Operation cancelled by user')
@@ -195,8 +248,15 @@ def main(self, args):
class RequirementCommand(Command):

@staticmethod
def populate_requirement_set(requirement_set, args, options, finder,
session, name, wheel_cache):
def populate_requirement_set(requirement_set, # type: RequirementSet
args, # type: List[str]
options, # type: Values
finder, # type: PackageFinder
session, # type: PipSession
name, # type: str
wheel_cache # type: Optional[WheelCache]
):
# type: (...) -> None
"""
Marshal cmd line args into a requirement set.
"""
@@ -214,6 +274,7 @@ def populate_requirement_set(requirement_set, args, options, finder,
for req in args:
req_to_add = install_req_from_line(
req, None, isolated=options.isolated_mode,
use_pep517=options.use_pep517,
wheel_cache=wheel_cache
)
req_to_add.is_direct = True
@@ -223,6 +284,7 @@ def populate_requirement_set(requirement_set, args, options, finder,
req_to_add = install_req_from_editable(
req,
isolated=options.isolated_mode,
use_pep517=options.use_pep517,
wheel_cache=wheel_cache
)
req_to_add.is_direct = True
@@ -232,7 +294,8 @@ def populate_requirement_set(requirement_set, args, options, finder,
for req_to_add in parse_requirements(
filename,
finder=finder, options=options, session=session,
wheel_cache=wheel_cache):
wheel_cache=wheel_cache,
use_pep517=options.use_pep517):
req_to_add.is_direct = True
requirement_set.add_requirement(req_to_add)
# If --require-hashes was a line in a requirements file, tell
@@ -251,28 +314,33 @@ def populate_requirement_set(requirement_set, args, options, finder,
'You must give at least one requirement to %(name)s '
'(see "pip help %(name)s")' % opts)

def _build_package_finder(self, options, session,
platform=None, python_versions=None,
abi=None, implementation=None):
def _build_package_finder(
self,
options, # type: Values
session, # type: PipSession
target_python=None, # type: Optional[TargetPython]
ignore_requires_python=None, # type: Optional[bool]
):
# type: (...) -> PackageFinder
"""
Create a package finder appropriate to this requirement command.
"""
index_urls = [options.index_url] + options.extra_index_urls
if options.no_index:
logger.debug('Ignoring indexes: %s', ','.join(index_urls))
index_urls = []
return PackageFinder(
find_links=options.find_links,
:param ignore_requires_python: Whether to ignore incompatible
"Requires-Python" values in links. Defaults to False.
"""
search_scope = make_search_scope(options)
selection_prefs = SelectionPreferences(
allow_yanked=True,
format_control=options.format_control,
index_urls=index_urls,
trusted_hosts=options.trusted_hosts,
allow_all_prereleases=options.pre,
process_dependency_links=options.process_dependency_links,
session=session,
platform=platform,
versions=python_versions,
abi=abi,
implementation=implementation,
prefer_binary=options.prefer_binary,
ignore_requires_python=ignore_requires_python,
)

return PackageFinder.create(
search_scope=search_scope,
selection_prefs=selection_prefs,
trusted_hosts=options.trusted_hosts,
session=session,
target_python=target_python,
)
345 changes: 280 additions & 65 deletions src/pip/_internal/cli/cmdoptions.py

Large diffs are not rendered by default.

22 changes: 12 additions & 10 deletions src/pip/_internal/cli/main_parser.py
Original file line number Diff line number Diff line change
@@ -4,7 +4,6 @@
import os
import sys

from pip import __version__
from pip._internal.cli import cmdoptions
from pip._internal.cli.parser import (
ConfigOptionParser, UpdatingDefaultsHelpFormatter,
@@ -13,12 +12,18 @@
commands_dict, get_similar_commands, get_summaries,
)
from pip._internal.exceptions import CommandError
from pip._internal.utils.misc import get_prog
from pip._internal.utils.misc import get_pip_version, get_prog
from pip._internal.utils.typing import MYPY_CHECK_RUNNING

if MYPY_CHECK_RUNNING:
from typing import Tuple, List


__all__ = ["create_main_parser", "parse_command"]


def create_main_parser():
# type: () -> ConfigOptionParser
"""Creates and returns the main parser for pip's CLI
"""

@@ -33,18 +38,14 @@ def create_main_parser():
parser = ConfigOptionParser(**parser_kw)
parser.disable_interspersed_args()

pip_pkg_dir = os.path.abspath(os.path.join(
os.path.dirname(__file__), "..", "..",
))
parser.version = 'pip %s from %s (python %s)' % (
__version__, pip_pkg_dir, sys.version[:3],
)
parser.version = get_pip_version()

# add the general options
gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
parser.add_option_group(gen_opts)

parser.main = True # so the help formatter knows
# so the help formatter knows
parser.main = True # type: ignore

# create command listing for description
command_summaries = get_summaries()
@@ -55,6 +56,7 @@ def create_main_parser():


def parse_command(args):
# type: (List[str]) -> Tuple[str, List[str]]
parser = create_main_parser()

# Note: parser calls disable_interspersed_args(), so the result of this
@@ -68,7 +70,7 @@ def parse_command(args):

# --version
if general_options.version:
sys.stdout.write(parser.version)
sys.stdout.write(parser.version) # type: ignore
sys.stdout.write(os.linesep)
sys.exit()

6 changes: 4 additions & 2 deletions src/pip/_internal/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@

from pip._internal.commands.completion import CompletionCommand
from pip._internal.commands.configuration import ConfigurationCommand
from pip._internal.commands.debug import DebugCommand
from pip._internal.commands.download import DownloadCommand
from pip._internal.commands.freeze import FreezeCommand
from pip._internal.commands.hash import HashCommand
@@ -20,8 +21,8 @@
from pip._internal.utils.typing import MYPY_CHECK_RUNNING

if MYPY_CHECK_RUNNING:
from typing import List, Type # noqa: F401
from pip._internal.cli.base_command import Command # noqa: F401
from typing import List, Type
from pip._internal.cli.base_command import Command

commands_order = [
InstallCommand,
@@ -36,6 +37,7 @@
WheelCommand,
HashCommand,
CompletionCommand,
DebugCommand,
HelpCommand,
] # type: List[Type[Command]]

4 changes: 2 additions & 2 deletions src/pip/_internal/commands/check.py
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ class CheckCommand(Command):
summary = 'Verify installed packages have compatible dependencies.'

def run(self, options, args):
package_set = create_package_set_from_installed()
package_set, parsing_probs = create_package_set_from_installed()
missing, conflicting = check_package_set(package_set)

for project_name in missing:
@@ -35,7 +35,7 @@ def run(self, options, args):
project_name, version, req, dep_name, dep_version,
)

if missing or conflicting:
if missing or conflicting or parsing_probs:
return 1
else:
logger.info("No broken requirements found.")
67 changes: 49 additions & 18 deletions src/pip/_internal/commands/configuration.py
Original file line number Diff line number Diff line change
@@ -4,10 +4,13 @@

from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.configuration import Configuration, kinds
from pip._internal.configuration import (
Configuration, get_configuration_files, kinds,
)
from pip._internal.exceptions import PipError
from pip._internal.locations import venv_config_file
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.misc import get_prog
from pip._internal.utils.virtualenv import running_under_virtualenv

logger = logging.getLogger(__name__)

@@ -23,7 +26,7 @@ class ConfigurationCommand(Command):
set: Set the name=value
unset: Unset the value associated with name
If none of --user, --global and --venv are passed, a virtual
If none of --user, --global and --site are passed, a virtual
environment configuration file is used if one is active and the file
exists. Otherwise, all modifications happen on the to the user file by
default.
@@ -73,12 +76,23 @@ def __init__(self, *args, **kwargs):
help='Use the user configuration file only'
)

self.cmd_opts.add_option(
'--site',
dest='site_file',
action='store_true',
default=False,
help='Use the current environment configuration file only'
)

self.cmd_opts.add_option(
'--venv',
dest='venv_file',
action='store_true',
default=False,
help='Use the virtualenv configuration file only'
help=(
'[Deprecated] Use the current environment configuration '
'file in a virtual environment only'
)
)

self.parser.insert_option_group(0, self.cmd_opts)
@@ -127,27 +141,44 @@ def run(self, options, args):
return SUCCESS

def _determine_file(self, options, need_value):
file_options = {
kinds.USER: options.user_file,
kinds.GLOBAL: options.global_file,
kinds.VENV: options.venv_file
}

if sum(file_options.values()) == 0:
# Convert legacy venv_file option to site_file or error
if options.venv_file and not options.site_file:
if running_under_virtualenv():
options.site_file = True
deprecated(
"The --venv option has been deprecated.",
replacement="--site",
gone_in="19.3",
)
else:
raise PipError(
"Legacy --venv option requires a virtual environment. "
"Use --site instead."
)

file_options = [key for key, value in (
(kinds.USER, options.user_file),
(kinds.GLOBAL, options.global_file),
(kinds.SITE, options.site_file),
) if value]

if not file_options:
if not need_value:
return None
# Default to user, unless there's a virtualenv file.
elif os.path.exists(venv_config_file):
return kinds.VENV
# Default to user, unless there's a site file.
elif any(
os.path.exists(site_config_file)
for site_config_file in get_configuration_files()[kinds.SITE]
):
return kinds.SITE
else:
return kinds.USER
elif sum(file_options.values()) == 1:
# There's probably a better expression for this.
return [key for key in file_options if file_options[key]][0]
elif len(file_options) == 1:
return file_options[0]

raise PipError(
"Need exactly one file to operate upon "
"(--user, --venv, --global) to perform."
"(--user, --site, --global) to perform."
)

def list_values(self, options, args):
114 changes: 114 additions & 0 deletions src/pip/_internal/commands/debug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from __future__ import absolute_import

import locale
import logging
import sys

from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import Command
from pip._internal.cli.cmdoptions import make_target_python
from pip._internal.cli.status_codes import SUCCESS
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import get_pip_version
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.wheel import format_tag

if MYPY_CHECK_RUNNING:
from typing import Any, List
from optparse import Values

logger = logging.getLogger(__name__)


def show_value(name, value):
# type: (str, str) -> None
logger.info('{}: {}'.format(name, value))


def show_sys_implementation():
# type: () -> None
logger.info('sys.implementation:')
if hasattr(sys, 'implementation'):
implementation = sys.implementation # type: ignore
implementation_name = implementation.name
else:
implementation_name = ''

with indent_log():
show_value('name', implementation_name)


def show_tags(options):
# type: (Values) -> None
tag_limit = 10

target_python = make_target_python(options)
tags = target_python.get_tags()

# Display the target options that were explicitly provided.
formatted_target = target_python.format_given()
suffix = ''
if formatted_target:
suffix = ' (target: {})'.format(formatted_target)

msg = 'Compatible tags: {}{}'.format(len(tags), suffix)
logger.info(msg)

if options.verbose < 1 and len(tags) > tag_limit:
tags_limited = True
tags = tags[:tag_limit]
else:
tags_limited = False

with indent_log():
for tag in tags:
logger.info(format_tag(tag))

if tags_limited:
msg = (
'...\n'
'[First {tag_limit} tags shown. Pass --verbose to show all.]'
).format(tag_limit=tag_limit)
logger.info(msg)


class DebugCommand(Command):
"""
Display debug information.
"""

name = 'debug'
usage = """
%prog <options>"""
summary = 'Show information useful for debugging.'
ignore_require_venv = True

def __init__(self, *args, **kw):
super(DebugCommand, self).__init__(*args, **kw)

cmd_opts = self.cmd_opts
cmdoptions.add_target_python_options(cmd_opts)
self.parser.insert_option_group(0, cmd_opts)

def run(self, options, args):
# type: (Values, List[Any]) -> int
logger.warning(
"This command is only meant for debugging. "
"Do not use this with automation for parsing and getting these "
"details, since the output and options of this command may "
"change without notice."
)
show_value('pip version', get_pip_version())
show_value('sys.version', sys.version)
show_value('sys.executable', sys.executable)
show_value('sys.getdefaultencoding', sys.getdefaultencoding())
show_value('sys.getfilesystemencoding', sys.getfilesystemencoding())
show_value(
'locale.getpreferredencoding', locale.getpreferredencoding(),
)
show_value('sys.platform', sys.platform)
show_sys_implementation()

show_tags(options)

return SUCCESS
22 changes: 8 additions & 14 deletions src/pip/_internal/commands/download.py
Original file line number Diff line number Diff line change
@@ -5,10 +5,11 @@

from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import RequirementCommand
from pip._internal.cli.cmdoptions import make_target_python
from pip._internal.legacy_resolve import Resolver
from pip._internal.operations.prepare import RequirementPreparer
from pip._internal.req import RequirementSet
from pip._internal.req.req_tracker import RequirementTracker
from pip._internal.resolve import Resolver
from pip._internal.utils.filesystem import check_path_owner
from pip._internal.utils.misc import ensure_dir, normalize_path
from pip._internal.utils.temp_dir import TempDirectory
@@ -58,6 +59,8 @@ def __init__(self, *args, **kw):
cmd_opts.add_option(cmdoptions.require_hashes())
cmd_opts.add_option(cmdoptions.progress_bar())
cmd_opts.add_option(cmdoptions.no_build_isolation())
cmd_opts.add_option(cmdoptions.use_pep517())
cmd_opts.add_option(cmdoptions.no_use_pep517())

cmd_opts.add_option(
'-d', '--dest', '--destination-dir', '--destination-directory',
@@ -67,10 +70,7 @@ def __init__(self, *args, **kw):
help=("Download packages into <dir>."),
)

cmd_opts.add_option(cmdoptions.platform())
cmd_opts.add_option(cmdoptions.python_version())
cmd_opts.add_option(cmdoptions.implementation())
cmd_opts.add_option(cmdoptions.abi())
cmdoptions.add_target_python_options(cmd_opts)

index_opts = cmdoptions.make_option_group(
cmdoptions.index_group,
@@ -86,11 +86,6 @@ def run(self, options, args):
# of the RequirementSet code require that property.
options.editables = []

if options.python_version:
python_versions = [options.python_version]
else:
python_versions = None

cmdoptions.check_dist_restriction(options)

options.src_dir = os.path.abspath(options.src_dir)
@@ -99,13 +94,11 @@ def run(self, options, args):
ensure_dir(options.download_dir)

with self._build_session(options) as session:
target_python = make_target_python(options)
finder = self._build_package_finder(
options=options,
session=session,
platform=options.platform,
python_versions=python_versions,
abi=options.abi,
implementation=options.implementation,
target_python=target_python,
)
build_delete = (not (options.no_clean or options.build_dir))
if options.cache_dir and not check_path_owner(options.cache_dir):
@@ -155,6 +148,7 @@ def run(self, options, args):
upgrade_strategy="to-satisfy-only",
force_reinstall=False,
ignore_dependencies=options.ignore_dependencies,
py_version_info=options.python_version,
ignore_requires_python=False,
ignore_installed=True,
isolated=options.isolated_mode,
5 changes: 5 additions & 0 deletions src/pip/_internal/commands/freeze.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
import sys

from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import Command
from pip._internal.models.format_control import FormatControl
from pip._internal.operations.freeze import freeze
@@ -56,6 +57,7 @@ def __init__(self, *args, **kw):
action='store_true',
default=False,
help='Only output packages installed in user-site.')
self.cmd_opts.add_option(cmdoptions.list_path())
self.cmd_opts.add_option(
'--all',
dest='freeze_all',
@@ -77,11 +79,14 @@ def run(self, options, args):
if not options.freeze_all:
skip.update(DEV_PKGS)

cmdoptions.check_list_path_option(options)

freeze_kwargs = dict(
requirement=options.requirements,
find_links=options.find_links,
local_only=options.local,
user_only=options.user,
paths=options.path,
skip_regex=options.skip_requirements_regex,
isolated=options.isolated_mode,
wheel_cache=wheel_cache,
117 changes: 81 additions & 36 deletions src/pip/_internal/commands/install.py
Original file line number Diff line number Diff line change
@@ -12,31 +12,64 @@
from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import RequirementCommand
from pip._internal.cli.cmdoptions import make_target_python
from pip._internal.cli.status_codes import ERROR
from pip._internal.exceptions import (
CommandError, InstallationError, PreviousBuildDirError,
)
from pip._internal.locations import distutils_scheme, virtualenv_no_global
from pip._internal.legacy_resolve import Resolver
from pip._internal.locations import distutils_scheme
from pip._internal.operations.check import check_install_conflicts
from pip._internal.operations.prepare import RequirementPreparer
from pip._internal.req import RequirementSet, install_given_reqs
from pip._internal.req.req_tracker import RequirementTracker
from pip._internal.resolve import Resolver
from pip._internal.utils.filesystem import check_path_owner
from pip._internal.utils.misc import (
ensure_dir, get_installed_version,
protect_pip_from_modification_on_windows,
)
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.utils.virtualenv import virtualenv_no_global
from pip._internal.wheel import WheelBuilder

try:
import wheel
except ImportError:
wheel = None
logger = logging.getLogger(__name__)


logger = logging.getLogger(__name__)
def is_wheel_installed():
"""
Return whether the wheel package is installed.
"""
try:
import wheel # noqa: F401
except ImportError:
return False

return True


def build_wheels(builder, pep517_requirements, legacy_requirements, session):
"""
Build wheels for requirements, depending on whether wheel is installed.
"""
# We don't build wheels for legacy requirements if wheel is not installed.
should_build_legacy = is_wheel_installed()

# Always build PEP 517 requirements
build_failures = builder.build(
pep517_requirements,
session=session, autobuilding=True
)

if should_build_legacy:
# We don't care about failures building legacy
# requirements, as we'll fall through to a direct
# install for those.
builder.build(
legacy_requirements,
session=session, autobuilding=True
)

return build_failures


class InstallCommand(RequirementCommand):
@@ -48,7 +81,7 @@ class InstallCommand(RequirementCommand):
- Local project directories.
- Local or remote source archives.
pip also supports installing from "requirements files", which provide
pip also supports installing from "requirements files," which provide
an easy way to specify a whole environment to be installed.
"""
name = 'install'
@@ -83,10 +116,7 @@ def __init__(self, *args, **kw):
'<dir>. Use --upgrade to replace existing packages in <dir> '
'with new versions.'
)
cmd_opts.add_option(cmdoptions.platform())
cmd_opts.add_option(cmdoptions.python_version())
cmd_opts.add_option(cmdoptions.implementation())
cmd_opts.add_option(cmdoptions.abi())
cmdoptions.add_target_python_options(cmd_opts)

cmd_opts.add_option(
'--user',
@@ -158,6 +188,8 @@ def __init__(self, *args, **kw):

cmd_opts.add_option(cmdoptions.ignore_requires_python())
cmd_opts.add_option(cmdoptions.no_build_isolation())
cmd_opts.add_option(cmdoptions.use_pep517())
cmd_opts.add_option(cmdoptions.no_use_pep517())

cmd_opts.add_option(cmdoptions.install_options())
cmd_opts.add_option(cmdoptions.global_options())
@@ -218,11 +250,6 @@ def run(self, options, args):

cmdoptions.check_dist_restriction(options, check_target=True)

if options.python_version:
python_versions = [options.python_version]
else:
python_versions = None

options.src_dir = os.path.abspath(options.src_dir)
install_options = options.install_options or []
if options.use_user_site:
@@ -257,13 +284,12 @@ def run(self, options, args):
global_options = options.global_options or []

with self._build_session(options) as session:
target_python = make_target_python(options)
finder = self._build_package_finder(
options=options,
session=session,
platform=options.platform,
python_versions=python_versions,
abi=options.abi,
implementation=options.implementation,
target_python=target_python,
ignore_requires_python=options.ignore_requires_python,
)
build_delete = (not (options.no_clean or options.build_dir))
wheel_cache = WheelCache(options.cache_dir, options.format_control)
@@ -314,27 +340,42 @@ def run(self, options, args):
ignore_requires_python=options.ignore_requires_python,
ignore_installed=options.ignore_installed,
isolated=options.isolated_mode,
use_pep517=options.use_pep517
)
resolver.resolve(requirement_set)

protect_pip_from_modification_on_windows(
modifying_pip=requirement_set.has_requirement("pip")
)

# If caching is disabled or wheel is not installed don't
# try to build wheels.
if wheel and options.cache_dir:
# build wheels before install.
wb = WheelBuilder(
finder, preparer, wheel_cache,
build_options=[], global_options=[],
)
# Ignore the result: a failed wheel will be
# installed from the sdist/vcs whatever.
wb.build(
requirement_set.requirements.values(),
session=session, autobuilding=True
)
# Consider legacy and PEP517-using requirements separately
legacy_requirements = []
pep517_requirements = []
for req in requirement_set.requirements.values():
if req.use_pep517:
pep517_requirements.append(req)
else:
legacy_requirements.append(req)

wheel_builder = WheelBuilder(
finder, preparer, wheel_cache,
build_options=[], global_options=[],
)

build_failures = build_wheels(
builder=wheel_builder,
pep517_requirements=pep517_requirements,
legacy_requirements=legacy_requirements,
session=session,
)

# If we're using PEP 517, we cannot do a direct install
# so we fail here.
if build_failures:
raise InstallationError(
"Could not build wheels for {} which use"
" PEP 517 and cannot be installed directly".format(
", ".join(r.name for r in build_failures)))

to_install = resolver.get_installation_order(
requirement_set
@@ -472,7 +513,11 @@ def _handle_target_dir(self, target_dir, target_temp_dir, upgrade):
)

def _warn_about_conflicts(self, to_install):
package_set, _dep_info = check_install_conflicts(to_install)
try:
package_set, _dep_info = check_install_conflicts(to_install)
except Exception:
logger.error("Error checking for conflicts.", exc_info=True)
return
missing, conflicting = _dep_info

# NOTE: There is some duplication here from pip check
Loading