mirror of
https://github.com/pypa/pip
synced 2023-12-13 21:30:23 +01:00
Merge branch 'main' into requires-python
This commit is contained in:
commit
2e5e9e54bc
3
.github/ISSUE_TEMPLATE.md
vendored
3
.github/ISSUE_TEMPLATE.md
vendored
|
@ -1,3 +0,0 @@
|
|||
* pip version:
|
||||
* Python version:
|
||||
* Operating system:
|
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
@ -6,3 +6,6 @@ contact_links:
|
|||
- name: "💬 IRC: #pypa"
|
||||
url: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
|
||||
about: Chat with devs
|
||||
- name: "(maintainers only) Blank issue"
|
||||
url: https://github.com/pypa/pip/issues/new
|
||||
about: For maintainers only.
|
||||
|
|
8
.github/lock.yml
vendored
8
.github/lock.yml
vendored
|
@ -1,8 +0,0 @@
|
|||
# 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
|
49
.github/workflows/ci.yml
vendored
49
.github/workflows/ci.yml
vendored
|
@ -11,7 +11,26 @@ on:
|
|||
schedule:
|
||||
- cron: 0 0 * * MON # Run every Monday at 00:00 UTC
|
||||
|
||||
env:
|
||||
# The "FORCE_COLOR" variable, when set to 1,
|
||||
# tells Nox to colorize itself.
|
||||
FORCE_COLOR: "1"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
docs:
|
||||
name: docs
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
- run: pip install nox
|
||||
- run: nox -s docs
|
||||
|
||||
determine-changes:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
|
@ -28,7 +47,7 @@ jobs:
|
|||
- "src/pip/_vendor/**"
|
||||
- "pyproject.toml"
|
||||
tests:
|
||||
# Anything that's touching testable stuff
|
||||
# Anything that's touching code-related stuff
|
||||
- ".github/workflows/ci.yml"
|
||||
- "src/**"
|
||||
- "tests/**"
|
||||
|
@ -74,8 +93,8 @@ jobs:
|
|||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-python@v2
|
||||
|
||||
- run: pip install vendoring
|
||||
- run: vendoring sync . --verbose
|
||||
- run: pip install nox
|
||||
- run: nox -s vendoring
|
||||
- run: git diff --exit-code
|
||||
|
||||
tests-unix:
|
||||
|
@ -92,11 +111,10 @@ jobs:
|
|||
matrix:
|
||||
os: [Ubuntu, MacOS]
|
||||
python:
|
||||
- 3.6
|
||||
- 3.7
|
||||
- 3.8
|
||||
- 3.9
|
||||
- "3.10.0-alpha - 3.10"
|
||||
- "3.10"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
|
@ -112,17 +130,17 @@ jobs:
|
|||
if: matrix.os == 'MacOS'
|
||||
run: brew install bzr
|
||||
|
||||
- run: pip install tox 'virtualenv<20'
|
||||
- run: pip install nox 'virtualenv<20' 'setuptools != 60.6.0'
|
||||
|
||||
# Main check
|
||||
- name: Run unit tests
|
||||
run: >-
|
||||
tox -e py --
|
||||
nox -s test-${{ matrix.python }} --
|
||||
-m unit
|
||||
--verbose --numprocesses auto --showlocals
|
||||
- name: Run integration tests
|
||||
run: >-
|
||||
tox -e py --
|
||||
nox -s test-${{ matrix.python }} --
|
||||
-m integration
|
||||
--verbose --numprocesses auto --showlocals
|
||||
--durations=5
|
||||
|
@ -141,12 +159,11 @@ jobs:
|
|||
matrix:
|
||||
os: [Windows]
|
||||
python:
|
||||
- 3.6
|
||||
- 3.7
|
||||
# Commented out, since Windows tests are expensively slow.
|
||||
# - 3.7
|
||||
# - 3.8
|
||||
- 3.9
|
||||
- "3.10.0-alpha - 3.10"
|
||||
# - 3.9
|
||||
- "3.10"
|
||||
group: [1, 2]
|
||||
|
||||
steps:
|
||||
|
@ -170,7 +187,7 @@ jobs:
|
|||
$acl.AddAccessRule($rule)
|
||||
Set-Acl "R:\Temp" $acl
|
||||
|
||||
- run: pip install tox 'virtualenv<20'
|
||||
- run: pip install nox 'virtualenv<20'
|
||||
env:
|
||||
TEMP: "R:\\Temp"
|
||||
|
||||
|
@ -178,7 +195,7 @@ jobs:
|
|||
- name: Run unit tests
|
||||
if: matrix.group == 1
|
||||
run: >-
|
||||
tox -e py --
|
||||
nox -s test-${{ matrix.python }} --
|
||||
-m unit
|
||||
--verbose --numprocesses auto --showlocals
|
||||
env:
|
||||
|
@ -187,7 +204,7 @@ jobs:
|
|||
- name: Run integration tests (group 1)
|
||||
if: matrix.group == 1
|
||||
run: >-
|
||||
tox -e py --
|
||||
nox -s test-${{ matrix.python }} --
|
||||
-m integration -k "not test_install"
|
||||
--verbose --numprocesses auto --showlocals
|
||||
env:
|
||||
|
@ -196,7 +213,7 @@ jobs:
|
|||
- name: Run integration tests (group 2)
|
||||
if: matrix.group == 2
|
||||
run: >-
|
||||
tox -e py --
|
||||
nox -s test-${{ matrix.python }} --
|
||||
-m integration -k "test_install"
|
||||
--verbose --numprocesses auto --showlocals
|
||||
env:
|
||||
|
|
23
.github/workflows/lock-threads.yml
vendored
Normal file
23
.github/workflows/lock-threads.yml
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
name: 'Lock Closed Threads'
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 7 * * *' # 7am UTC, daily
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
pull-requests: write
|
||||
|
||||
concurrency:
|
||||
group: lock
|
||||
|
||||
jobs:
|
||||
action:
|
||||
if: github.repository_owner == 'pypa'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/lock-threads@v3
|
||||
with:
|
||||
issue-inactive-days: '30'
|
||||
pr-inactive-days: '15'
|
2
.mailmap
2
.mailmap
|
@ -19,6 +19,7 @@ Dongweiming <dongweiming@admaster.com.cn> <ciici1234@hotmail.c
|
|||
Dustin Ingram <di@di.codes> <di@users.noreply.github.com>
|
||||
Endoh Takanao <djmchl@gmail.com>
|
||||
Erik M. Bray <embray@stsci.edu>
|
||||
Ee Durbin <ewdurbin@gmail.com>
|
||||
Gabriel de Perthuis <g2p.code@gmail.com>
|
||||
Hsiaoming Yang <lepture@me.com>
|
||||
Hugo van Kemenade <hugovk@users.noreply.github.com> Hugo <hugovk@users.noreply.github.com>
|
||||
|
@ -33,6 +34,7 @@ Ludovic Gasc <gmludo@gmail.com> <git@gmludo.eu>
|
|||
Markus Hametner <fin+github@xbhd.org>
|
||||
Masklinn <bitbucket.org@masklinn.net>
|
||||
Matthew Iversen <teh.ivo@gmail.com> <teh.ivo@gmail.com>
|
||||
Ofek Lev <ofekmeister@gmail.com>
|
||||
Pi Delport <pjdelport@gmail.com>
|
||||
<pnasrat@gmail.com> <pnasrat@googlemail.com>
|
||||
Pradyun Gedam <pradyunsg@gmail.com> <pradyunsg@users.noreply.github.com>
|
||||
|
|
|
@ -47,6 +47,7 @@ repos:
|
|||
additional_dependencies: [
|
||||
'keyring==23.0.1',
|
||||
'nox==2021.6.12',
|
||||
'pytest==6.2.5',
|
||||
'types-docutils==0.1.8',
|
||||
'types-setuptools==57.0.2',
|
||||
'types-six==0.1.9',
|
||||
|
|
32
AUTHORS.txt
32
AUTHORS.txt
|
@ -18,6 +18,7 @@ Alan Yee
|
|||
Albert Tugushev
|
||||
Albert-Guan
|
||||
albertg
|
||||
Alberto Sottile
|
||||
Aleks Bunin
|
||||
Alethea Flowers
|
||||
Alex Gaynor
|
||||
|
@ -77,6 +78,7 @@ Bastian Venthur
|
|||
Ben Bodenmiller
|
||||
Ben Darnell
|
||||
Ben Hoyt
|
||||
Ben Mares
|
||||
Ben Rosser
|
||||
Bence Nagy
|
||||
Benjamin Peterson
|
||||
|
@ -123,6 +125,7 @@ Chris Brinker
|
|||
Chris Hunt
|
||||
Chris Jerdonek
|
||||
Chris McDonough
|
||||
Chris Pawley
|
||||
Chris Wolfe
|
||||
Christian Clauss
|
||||
Christian Heimes
|
||||
|
@ -148,10 +151,13 @@ Cristina Muñoz
|
|||
Curtis Doty
|
||||
cytolentino
|
||||
Daan De Meyer
|
||||
Damian
|
||||
Damian Quiroga
|
||||
Damian Shaw
|
||||
Dan Black
|
||||
Dan Savilonis
|
||||
Dan Sully
|
||||
Dane Hillard
|
||||
daniel
|
||||
Daniel Collins
|
||||
Daniel Hahler
|
||||
|
@ -192,6 +198,7 @@ DiegoCaraballo
|
|||
Dimitri Merejkowsky
|
||||
Dirk Stolle
|
||||
Dmitry Gladkov
|
||||
Dmitry Volodin
|
||||
Domen Kožar
|
||||
Dominic Davis-Foster
|
||||
Donald Stufft
|
||||
|
@ -201,6 +208,7 @@ DrFeathers
|
|||
Dustin Ingram
|
||||
Dwayne Bailey
|
||||
Ed Morley
|
||||
Ee Durbin
|
||||
Eitan Adler
|
||||
ekristina
|
||||
elainechan
|
||||
|
@ -219,8 +227,6 @@ Eric Hanchrow
|
|||
Eric Hopper
|
||||
Erik M. Bray
|
||||
Erik Rose
|
||||
Ernest W Durbin III
|
||||
Ernest W. Durbin III
|
||||
Erwin Janssen
|
||||
Eugene Vereshchagin
|
||||
everdimension
|
||||
|
@ -246,6 +252,7 @@ gizmoguy1
|
|||
gkdoc
|
||||
Gopinath M
|
||||
GOTO Hayato
|
||||
gousaiyang
|
||||
gpiks
|
||||
Greg Roodt
|
||||
Greg Ward
|
||||
|
@ -288,6 +295,7 @@ Jakub Wilk
|
|||
James Cleveland
|
||||
James Curtin
|
||||
James Firth
|
||||
James Gerity
|
||||
James Polley
|
||||
Jan Pokorný
|
||||
Jannis Leidel
|
||||
|
@ -301,6 +309,7 @@ Jelmer Vernooij
|
|||
jenix21
|
||||
Jeremy Stanley
|
||||
Jeremy Zafran
|
||||
Jesse Rittner
|
||||
Jiashuo Li
|
||||
Jim Fisher
|
||||
Jim Garrison
|
||||
|
@ -355,6 +364,7 @@ Laurent Bristiel
|
|||
Laurent LAPORTE
|
||||
Laurie O
|
||||
Laurie Opperman
|
||||
layday
|
||||
Leon Sasson
|
||||
Lev Givon
|
||||
Lincoln de Sousa
|
||||
|
@ -362,6 +372,7 @@ Lipis
|
|||
Loren Carvalho
|
||||
Lucas Cimon
|
||||
Ludovic Gasc
|
||||
Lukas Juhrich
|
||||
Luke Macken
|
||||
Luo Jiebin
|
||||
luojiebin
|
||||
|
@ -374,6 +385,7 @@ Mariatta
|
|||
Mark Kohler
|
||||
Mark Williams
|
||||
Markus Hametner
|
||||
Martey Dodoo
|
||||
Martin Häcker
|
||||
Martin Pavlasek
|
||||
Masaki
|
||||
|
@ -381,6 +393,7 @@ Masklinn
|
|||
Matej Stuchlik
|
||||
Mathew Jennings
|
||||
Mathieu Bridon
|
||||
Matt Bacchi
|
||||
Matt Good
|
||||
Matt Maker
|
||||
Matt Robenolt
|
||||
|
@ -392,6 +405,7 @@ Matthew Trumbell
|
|||
Matthew Willson
|
||||
Matthias Bussonnier
|
||||
mattip
|
||||
Maurits van Rees
|
||||
Max W Chase
|
||||
Maxim Kurnikov
|
||||
Maxime Rouyrre
|
||||
|
@ -406,6 +420,7 @@ Michael E. Karpeles
|
|||
Michael Klich
|
||||
Michael Williamson
|
||||
michaelpacer
|
||||
Michał Górny
|
||||
Mickaël Schoentgen
|
||||
Miguel Araujo Perez
|
||||
Mihir Singh
|
||||
|
@ -417,7 +432,10 @@ Miro Hrončok
|
|||
Monica Baluna
|
||||
montefra
|
||||
Monty Taylor
|
||||
Nadav Wexler
|
||||
Nate Coraor
|
||||
Nate Prewitt
|
||||
Nathan Houghton
|
||||
Nathaniel J. Smith
|
||||
Nehal J Wani
|
||||
Neil Botelho
|
||||
|
@ -431,14 +449,16 @@ Nicole Harris
|
|||
Nikhil Benesch
|
||||
Nikita Chepanov
|
||||
Nikolay Korolev
|
||||
Nipunn Koorapati
|
||||
Nitesh Sharma
|
||||
Niyas Sait
|
||||
Noah
|
||||
Noah Gorny
|
||||
Nowell Strite
|
||||
NtaleGrey
|
||||
nvdv
|
||||
OBITORASU
|
||||
Ofekmeister
|
||||
Ofek Lev
|
||||
ofrinevo
|
||||
Oliver Jeeves
|
||||
Oliver Mannion
|
||||
|
@ -464,9 +484,12 @@ Paul Nasrat
|
|||
Paul Oswald
|
||||
Paul van der Linden
|
||||
Paulus Schoutsen
|
||||
Pavel Safronov
|
||||
Pavithra Eswaramoorthy
|
||||
Pawel Jasinski
|
||||
Paweł Szramowski
|
||||
Pekka Klärck
|
||||
Peter Gessler
|
||||
Peter Lisák
|
||||
Peter Waller
|
||||
petr-tik
|
||||
|
@ -491,6 +514,7 @@ Preet Thakkar
|
|||
Preston Holmes
|
||||
Przemek Wrzos
|
||||
Pulkit Goyal
|
||||
q0w
|
||||
Qiangning Hong
|
||||
Quentin Lee
|
||||
Quentin Pradet
|
||||
|
@ -595,6 +619,7 @@ toonarmycaptain
|
|||
Toshio Kuratomi
|
||||
toxinu
|
||||
Travis Swicegood
|
||||
Tushar Sadhwani
|
||||
Tzu-ping Chung
|
||||
Valentin Haenel
|
||||
Victor Stinner
|
||||
|
@ -629,6 +654,7 @@ Yu Jian
|
|||
Yuan Jing Vincent Yan
|
||||
Zearin
|
||||
Zhiping Deng
|
||||
ziebam
|
||||
Zvezdan Petkovic
|
||||
Łukasz Langa
|
||||
Семён Марьясин
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2008-2021 The pip developers (see AUTHORS.txt file)
|
||||
Copyright (c) 2008-present 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
|
||||
|
|
|
@ -6,6 +6,7 @@ include pyproject.toml
|
|||
|
||||
include src/pip/_vendor/README.rst
|
||||
include src/pip/_vendor/vendor.txt
|
||||
include src/pip/_vendor/pyparsing/diagram/template.jinja2
|
||||
recursive-include src/pip/_vendor *LICENSE*
|
||||
recursive-include src/pip/_vendor *COPYING*
|
||||
|
||||
|
|
216
NEWS.rst
216
NEWS.rst
|
@ -7,9 +7,223 @@
|
|||
To add a new change log entry, please see
|
||||
https://pip.pypa.io/en/latest/development/contributing/#news-entries
|
||||
|
||||
|
||||
.. towncrier release notes start
|
||||
|
||||
22.0.4 (2022-03-06)
|
||||
===================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Drop the doctype check, that presented a warning for index pages that use non-compliant HTML 5. (`#10903 <https://github.com/pypa/pip/issues/10903>`_)
|
||||
|
||||
Vendored Libraries
|
||||
------------------
|
||||
|
||||
- Downgrade distlib to 0.3.3.
|
||||
|
||||
|
||||
22.0.3 (2022-02-03)
|
||||
===================
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Print the exception via ``rich.traceback``, when running with ``--debug``. (`#10791 <https://github.com/pypa/pip/issues/10791>`_)
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Only calculate topological installation order, for packages that are going to be installed/upgraded.
|
||||
|
||||
This fixes an `AssertionError` that occured when determining installation order, for a very specific combination of upgrading-already-installed-package + change of dependencies + fetching some packages from a package index. This combination was especially common in Read the Docs' builds. (`#10851 <https://github.com/pypa/pip/issues/10851>`_)
|
||||
- Use ``html.parser`` by default, instead of falling back to ``html5lib`` when ``--use-deprecated=html5lib`` is not passed. (`#10869 <https://github.com/pypa/pip/issues/10869>`_)
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Clarify that using per-requirement overrides disables the usage of wheels. (`#9674 <https://github.com/pypa/pip/issues/9674>`_)
|
||||
|
||||
|
||||
22.0.2 (2022-01-30)
|
||||
===================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Instead of failing on index pages that use non-compliant HTML 5, print a deprecation warning and fall back to ``html5lib``-based parsing for now. This simplifies the migration for non-compliant index pages, by letting such indexes function with a warning. (`#10847 <https://github.com/pypa/pip/issues/10847>`_)
|
||||
|
||||
|
||||
22.0.1 (2022-01-30)
|
||||
===================
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Accept lowercase ``<!doctype html>`` on index pages. (`#10844 <https://github.com/pypa/pip/issues/10844>`_)
|
||||
- Properly handle links parsed by html5lib, when using ``--use-deprecated=html5lib``. (`#10846 <https://github.com/pypa/pip/issues/10846>`_)
|
||||
|
||||
|
||||
22.0 (2022-01-29)
|
||||
=================
|
||||
|
||||
Process
|
||||
-------
|
||||
|
||||
- Completely replace :pypi:`tox` in our development workflow, with :pypi:`nox`.
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Deprecate alternative progress bar styles, leaving only ``on`` and ``off`` as available choices. (`#10462 <https://github.com/pypa/pip/issues/10462>`_)
|
||||
- Drop support for Python 3.6. (`#10641 <https://github.com/pypa/pip/issues/10641>`_)
|
||||
- Disable location mismatch warnings on Python versions prior to 3.10.
|
||||
|
||||
These warnings were helping identify potential issues as part of the sysconfig -> distutils transition, and we no longer need to rely on reports from older Python versions for information on the transition. (`#10840 <https://github.com/pypa/pip/issues/10840>`_)
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Changed ``PackageFinder`` to parse HTML documents using the stdlib :class:`html.parser.HTMLParser` class instead of the ``html5lib`` package.
|
||||
|
||||
For now, the deprecated ``html5lib`` code remains and can be used with the ``--use-deprecated=html5lib`` command line option. However, it will be removed in a future pip release. (`#10291 <https://github.com/pypa/pip/issues/10291>`_)
|
||||
- Utilise ``rich`` for presenting pip's default download progress bar. (`#10462 <https://github.com/pypa/pip/issues/10462>`_)
|
||||
- Present a better error message when an invalid wheel file is encountered, providing more context where the invalid wheel file is. (`#10535 <https://github.com/pypa/pip/issues/10535>`_)
|
||||
- Documents the ``--require-virtualenv`` flag for ``pip install``. (`#10588 <https://github.com/pypa/pip/issues/10588>`_)
|
||||
- ``pip install <tab>`` autocompletes paths. (`#10646 <https://github.com/pypa/pip/issues/10646>`_)
|
||||
- Allow Python distributors to opt-out from or opt-in to the ``sysconfig`` installation scheme backend by setting ``sysconfig._PIP_USE_SYSCONFIG`` to ``True`` or ``False``. (`#10647 <https://github.com/pypa/pip/issues/10647>`_)
|
||||
- Make it possible to deselect tests requiring cryptography package on systems where it cannot be installed. (`#10686 <https://github.com/pypa/pip/issues/10686>`_)
|
||||
- Start using Rich for presenting error messages in a consistent format. (`#10703 <https://github.com/pypa/pip/issues/10703>`_)
|
||||
- Improve presentation of errors from subprocesses. (`#10705 <https://github.com/pypa/pip/issues/10705>`_)
|
||||
- Forward pip's verbosity configuration to VCS tools to control their output accordingly. (`#8819 <https://github.com/pypa/pip/issues/8819>`_)
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Optimize installation order calculation to improve performance when installing requirements that form a complex dependency graph with a large amount of edges. (`#10557 <https://github.com/pypa/pip/issues/10557>`_)
|
||||
- When a package is requested by the user for upgrade, correctly identify that the extra-ed variant of that same package depended by another user-requested package is requesting the same package, and upgrade it accordingly. (`#10613 <https://github.com/pypa/pip/issues/10613>`_)
|
||||
- Prevent pip from installing yanked releases unless explicitly pinned via the ``==`` or ``===`` operators. (`#10617 <https://github.com/pypa/pip/issues/10617>`_)
|
||||
- Stop backtracking on build failures, by instead surfacing them to the user and aborting immediately. This behaviour provides more immediate feedback when a package cannot be built due to missing build dependencies or platform incompatibility. (`#10655 <https://github.com/pypa/pip/issues/10655>`_)
|
||||
- Silence ``Value for <location> does not match`` warning caused by an erroneous patch in Slackware-distributed Python 3.9. (`#10668 <https://github.com/pypa/pip/issues/10668>`_)
|
||||
- Fix an issue where pip did not consider dependencies with and without extras to be equal (`#9644 <https://github.com/pypa/pip/issues/9644>`_)
|
||||
|
||||
Vendored Libraries
|
||||
------------------
|
||||
|
||||
- Upgrade CacheControl to 0.12.10
|
||||
- Upgrade certifi to 2021.10.8
|
||||
- Upgrade distlib to 0.3.4
|
||||
- Upgrade idna to 3.3
|
||||
- Upgrade msgpack to 1.0.3
|
||||
- Upgrade packaging to 21.3
|
||||
- Upgrade platformdirs to 2.4.1
|
||||
- Add pygments 2.11.2 as a vendored dependency.
|
||||
- Tree-trim unused portions of vendored pygments, to reduce the distribution size.
|
||||
- Upgrade pyparsing to 3.0.7
|
||||
- Upgrade Requests to 2.27.1
|
||||
- Upgrade resolvelib to 0.8.1
|
||||
- Add rich 11.0.0 as a vendored dependency.
|
||||
- Tree-trim unused portions of vendored rich, to reduce the distribution size.
|
||||
- Add typing_extensions 4.0.1 as a vendored dependency.
|
||||
- Upgrade urllib3 to 1.26.8
|
||||
|
||||
|
||||
21.3.1 (2021-10-22)
|
||||
===================
|
||||
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
|
||||
- Always refuse installing or building projects that have no ``pyproject.toml`` nor
|
||||
``setup.py``. (`#10531 <https://github.com/pypa/pip/issues/10531>`_)
|
||||
- Tweak running-as-root detection, to check ``os.getuid`` if it exists, on Unix-y and non-Linux/non-MacOS machines. (`#10565 <https://github.com/pypa/pip/issues/10565>`_)
|
||||
- When installing projects with a ``pyproject.toml`` in editable mode, and the build
|
||||
backend does not support :pep:`660`, prepare metadata using
|
||||
``prepare_metadata_for_build_wheel`` instead of ``setup.py egg_info``. Also, refuse
|
||||
installing projects that only have a ``setup.cfg`` and no ``setup.py`` nor
|
||||
``pyproject.toml``. These restore the pre-21.3 behaviour. (`#10573 <https://github.com/pypa/pip/issues/10573>`_)
|
||||
- Restore compatibility of where configuration files are loaded from on MacOS (back to ``Library/Application Support/pip``, instead of ``Preferences/pip``). (`#10585 <https://github.com/pypa/pip/issues/10585>`_)
|
||||
|
||||
Vendored Libraries
|
||||
------------------
|
||||
|
||||
|
||||
- Upgrade pep517 to 0.12.0
|
||||
|
||||
|
||||
21.3 (2021-10-11)
|
||||
=================
|
||||
|
||||
Deprecations and Removals
|
||||
-------------------------
|
||||
|
||||
- Improve deprecation warning regarding the copying of source trees when installing from a local directory. (`#10128 <https://github.com/pypa/pip/issues/10128>`_)
|
||||
- Suppress location mismatch warnings when pip is invoked from a Python source
|
||||
tree, so ``ensurepip`` does not emit warnings on CPython ``make install``. (`#10270 <https://github.com/pypa/pip/issues/10270>`_)
|
||||
- On Python 3.10 or later, the installation scheme backend has been changed to use
|
||||
``sysconfig``. This is to anticipate the deprecation of ``distutils`` in Python
|
||||
3.10, and its scheduled removal in 3.12. For compatibility considerations, pip
|
||||
installations running on Python 3.9 or lower will continue to use ``distutils``. (`#10358 <https://github.com/pypa/pip/issues/10358>`_)
|
||||
- Remove the ``--build-dir`` option and aliases, one last time. (`#10485 <https://github.com/pypa/pip/issues/10485>`_)
|
||||
- In-tree builds are now the default. ``--use-feature=in-tree-build`` is now
|
||||
ignored. ``--use-deprecated=out-of-tree-build`` may be used temporarily to ease
|
||||
the transition. (`#10495 <https://github.com/pypa/pip/issues/10495>`_)
|
||||
- Un-deprecate source distribution re-installation behaviour. (`#8711 <https://github.com/pypa/pip/issues/8711>`_)
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Replace vendored appdirs with platformdirs. (`#10202 <https://github.com/pypa/pip/issues/10202>`_)
|
||||
- Support `PEP 610 <https://www.python.org/dev/peps/pep-0610/>`_ to detect
|
||||
editable installs in ``pip freeze`` and ``pip list``. The ``pip list`` column output
|
||||
has a new ``Editable project location`` column, and the JSON output has a new
|
||||
``editable_project_location`` field. (`#10249 <https://github.com/pypa/pip/issues/10249>`_)
|
||||
- ``pip freeze`` will now always fallback to reporting the editable project
|
||||
location when it encounters a VCS error while analyzing an editable
|
||||
requirement. Before, it sometimes reported the requirement as non-editable. (`#10410 <https://github.com/pypa/pip/issues/10410>`_)
|
||||
- ``pip show`` now sorts ``Requires`` and ``Required-By`` alphabetically. (`#10422 <https://github.com/pypa/pip/issues/10422>`_)
|
||||
- Do not raise error when there are no files to remove with ``pip cache purge/remove``.
|
||||
Instead log a warning and continue (to log that we removed 0 files). (`#10459 <https://github.com/pypa/pip/issues/10459>`_)
|
||||
- When backtracking during dependency resolution, prefer the dependencies which are involved in the most recent conflict. This can significantly reduce the amount of backtracking required. (`#10479 <https://github.com/pypa/pip/issues/10479>`_)
|
||||
- Cache requirement objects, to improve performance reducing reparses of requirement strings. (`#10550 <https://github.com/pypa/pip/issues/10550>`_)
|
||||
- Support editable installs for projects that have a ``pyproject.toml`` and use a
|
||||
build backend that supports :pep:`660`. (`#8212 <https://github.com/pypa/pip/issues/8212>`_)
|
||||
- When a revision is specified in a Git URL, use git's partial clone feature to speed up source retrieval. (`#9086 <https://github.com/pypa/pip/issues/9086>`_)
|
||||
- Add a ``--debug`` flag, to enable a mode that doesn't log errors and propagates them to the top level instead. This is primarily to aid with debugging pip's crashes. (`#9349 <https://github.com/pypa/pip/issues/9349>`_)
|
||||
- If a host is explicitly specified as trusted by the user (via the --trusted-host option), cache HTTP responses from it in addition to HTTPS ones. (`#9498 <https://github.com/pypa/pip/issues/9498>`_)
|
||||
|
||||
Bug Fixes
|
||||
---------
|
||||
|
||||
- Present a better error message, when a ``file:`` URL is not found. (`#10263 <https://github.com/pypa/pip/issues/10263>`_)
|
||||
- Fix the auth credential cache to allow for the case in which
|
||||
the index url contains the username, but the password comes
|
||||
from an external source, such as keyring. (`#10269 <https://github.com/pypa/pip/issues/10269>`_)
|
||||
- Fix double unescape of HTML ``data-requires-python`` and ``data-yanked`` attributes. (`#10378 <https://github.com/pypa/pip/issues/10378>`_)
|
||||
- New resolver: Fixes depth ordering of packages during resolution, e.g. a dependency 2 levels deep will be ordered before a dependency 3 levels deep. (`#10482 <https://github.com/pypa/pip/issues/10482>`_)
|
||||
- Correctly indent metadata preparation messages in pip output. (`#10524 <https://github.com/pypa/pip/issues/10524>`_)
|
||||
|
||||
Vendored Libraries
|
||||
------------------
|
||||
|
||||
- Remove appdirs as a vendored dependency.
|
||||
- Upgrade distlib to 0.3.3
|
||||
- Upgrade distro to 1.6.0
|
||||
- Patch pkg_resources to use platformdirs rather than appdirs.
|
||||
- Add platformdirs as a vendored dependency.
|
||||
- Upgrade progress to 1.6
|
||||
- Upgrade resolvelib to 0.8.0
|
||||
- Upgrade urllib3 to 1.26.7
|
||||
|
||||
Improved Documentation
|
||||
----------------------
|
||||
|
||||
- Update links of setuptools as setuptools moved these documents. The Simple Repository link now points to PyPUG as that is the canonical place of packaging specification, and setuptools's ``easy_install`` is deprecated. (`#10430 <https://github.com/pypa/pip/issues/10430>`_)
|
||||
- Create a "Build System Interface" reference section, for documenting how pip interacts with build systems. (`#10497 <https://github.com/pypa/pip/issues/10497>`_)
|
||||
|
||||
|
||||
21.2.4 (2021-08-12)
|
||||
===================
|
||||
|
||||
|
|
|
@ -74,178 +74,11 @@ when decision is needed.
|
|||
*(a)abort*
|
||||
Abort pip and return non-zero exit status.
|
||||
|
||||
.. _`build-interface`:
|
||||
|
||||
|
||||
Build System Interface
|
||||
======================
|
||||
|
||||
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``
|
||||
command line that will be run to invoke the required action.
|
||||
|
||||
Setuptools Injection
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Any output produced by the build system will be read by pip (for display to the
|
||||
user if requested). In order to correctly read the build system output, pip
|
||||
requires that the output is written in a well-defined encoding, specifically
|
||||
the encoding the user has configured for text output (which can be obtained in
|
||||
Python using ``locale.getpreferredencoding``). If the configured encoding is
|
||||
ASCII, pip assumes UTF-8 (to account for the behaviour of some Unix systems).
|
||||
|
||||
Build systems should ensure that any tools they invoke (compilers, etc) produce
|
||||
output in the correct encoding. In practice - and in particular on Windows,
|
||||
where tools are inconsistent in their use of the "OEM" and "ANSI" codepages -
|
||||
this may not always be possible. pip will therefore attempt to recover cleanly
|
||||
if presented with incorrectly encoded build tool output, by translating
|
||||
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).
|
||||
|
||||
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 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
|
||||
``site-packages``, but rather installs them in a temporary directory which it
|
||||
adds to the user's ``sys.path`` for the duration of the build. This ensures
|
||||
that build requirements are handled independently of the user's runtime
|
||||
environment. For example, a project that needs a recent version of setuptools
|
||||
to build can still be installed, even if the user has an older version
|
||||
installed (and without silently replacing that version).
|
||||
|
||||
In certain cases, projects (or redistributors) may have workflows that
|
||||
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 (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:
|
||||
|
||||
**Historical Limitations**:
|
||||
|
||||
* ``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
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
:pep:`426` notes that the intention is to add hooks to project metadata in
|
||||
version 2.1 of the metadata spec, to explicitly define how to build a project
|
||||
from its source. Once this version of the metadata spec is final, pip will
|
||||
migrate to using that interface. At that point, the ``setup.py`` interface
|
||||
documented here will be retained solely for legacy purposes, until projects
|
||||
have migrated.
|
||||
|
||||
Specifically, applications should *not* expect to rely on there being any form
|
||||
of backward compatibility guarantees around the ``setup.py`` interface.
|
||||
|
||||
|
||||
Build Options
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The ``--global-option`` and ``--build-option`` arguments to the ``pip install``
|
||||
and ``pip wheel`` inject additional arguments into the ``setup.py`` command
|
||||
(``--build-option`` is only available in ``pip wheel``). These arguments are
|
||||
included in the command as follows:
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
python setup.py <global_options> BUILD COMMAND <build_options>
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py setup.py <global_options> BUILD COMMAND <build_options>
|
||||
|
||||
The options are passed unmodified, and presently offer direct access to the
|
||||
distutils command line. Use of ``--global-option`` and ``--build-option``
|
||||
should be considered as build system dependent, and may not be supported in the
|
||||
current form if support for alternative build systems is added to pip.
|
||||
|
||||
This is now covered in :doc:`../reference/build-system/index`.
|
||||
|
||||
.. _`General Options`:
|
||||
|
||||
|
|
|
@ -154,88 +154,15 @@ Requirements File Format
|
|||
|
||||
This section has been moved to :doc:`../reference/requirements-file-format`.
|
||||
|
||||
.. _`Requirement Specifiers`:
|
||||
|
||||
Requirement Specifiers
|
||||
----------------------
|
||||
|
||||
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. Since version 18.1 pip supports the
|
||||
``url_req``-form specification.
|
||||
|
||||
Some examples:
|
||||
|
||||
::
|
||||
|
||||
SomeProject
|
||||
SomeProject == 1.3
|
||||
SomeProject >=1.2,<2.0
|
||||
SomeProject[foo, bar]
|
||||
SomeProject~=1.4.2
|
||||
|
||||
Since version 6.0, pip also supports specifiers containing `environment markers
|
||||
<https://www.python.org/dev/peps/pep-0508/#environment-markers>`__ like so:
|
||||
|
||||
::
|
||||
|
||||
SomeProject ==5.4 ; python_version < '3.8'
|
||||
SomeProject; sys_platform == 'win32'
|
||||
|
||||
Since version 19.1, pip also supports `direct references
|
||||
<https://www.python.org/dev/peps/pep-0440/#direct-references>`__ like so:
|
||||
|
||||
::
|
||||
|
||||
SomeProject @ file:///somewhere/...
|
||||
|
||||
Environment markers are supported in the command line and in requirements files.
|
||||
|
||||
.. note::
|
||||
|
||||
Use quotes around specifiers in the shell when using ``>``, ``<``, or when
|
||||
using environment markers. Don't use quotes in requirement files. [1]_
|
||||
|
||||
|
||||
.. _`Per-requirement Overrides`:
|
||||
This section has been moved to :doc:`../reference/requirement-specifiers`.
|
||||
|
||||
Per-requirement Overrides
|
||||
-------------------------
|
||||
|
||||
Since version 7.0 pip supports controlling the command line options given to
|
||||
``setup.py`` via requirements files. This disables the use of wheels (cached or
|
||||
otherwise) for that package, as ``setup.py`` does not exist for wheels.
|
||||
|
||||
The ``--global-option`` and ``--install-option`` options are used to pass
|
||||
options to ``setup.py``. For example:
|
||||
|
||||
::
|
||||
|
||||
FooProject >= 1.2 --global-option="--no-user-cfg" \
|
||||
--install-option="--prefix='/usr/local'" \
|
||||
--install-option="--no-compile"
|
||||
|
||||
The above translates roughly into running FooProject's ``setup.py``
|
||||
script as:
|
||||
|
||||
::
|
||||
|
||||
python setup.py --no-user-cfg install --prefix='/usr/local' --no-compile
|
||||
|
||||
Note that the only way of giving more than one option to ``setup.py``
|
||||
is through multiple ``--global-option`` and ``--install-option``
|
||||
options, as shown in the example above. The value of each option is
|
||||
passed as a single argument to the ``setup.py`` script. Therefore, a
|
||||
line such as the following is invalid and would result in an
|
||||
installation error.
|
||||
|
||||
::
|
||||
|
||||
# Invalid. Please use '--install-option' twice as shown above.
|
||||
FooProject >= 1.2 --install-option="--prefix=/usr/local --no-compile"
|
||||
|
||||
This is now covered in :doc:`../reference/requirements-file-format`.
|
||||
|
||||
.. _`Pre Release Versions`:
|
||||
|
||||
|
@ -312,308 +239,25 @@ Wheel Cache
|
|||
|
||||
This is now covered in :doc:`../topics/caching`.
|
||||
|
||||
.. _`hash-checking mode`:
|
||||
|
||||
Hash-Checking Mode
|
||||
Hash checking mode
|
||||
------------------
|
||||
|
||||
Since version 8.0, pip can check downloaded package archives against local
|
||||
hashes to protect against remote tampering. To verify a package against one or
|
||||
more hashes, add them to the end of the line::
|
||||
This is now covered in :doc:`../topics/secure-installs`.
|
||||
|
||||
FooProject == 1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 \
|
||||
--hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7
|
||||
|
||||
(The ability to use multiple hashes is important when a package has both
|
||||
binary and source distributions or when it offers binary distributions for a
|
||||
variety of platforms.)
|
||||
|
||||
The recommended hash algorithm at the moment is sha256, but stronger ones are
|
||||
allowed, including all those supported by ``hashlib``. However, weaker ones
|
||||
such as md5, sha1, and sha224 are excluded to avoid giving a false sense of
|
||||
security.
|
||||
|
||||
Hash verification is an all-or-nothing proposition. Specifying a ``--hash``
|
||||
against any requirement not only checks that hash but also activates a global
|
||||
*hash-checking mode*, which imposes several other security restrictions:
|
||||
|
||||
* Hashes are required for all requirements. This is because a partially-hashed
|
||||
requirements file is of little use and thus likely an error: a malicious
|
||||
actor could slip bad code into the installation via one of the unhashed
|
||||
requirements. Note that hashes embedded in URL-style requirements via the
|
||||
``#md5=...`` syntax suffice to satisfy this rule (regardless of hash
|
||||
strength, for legacy reasons), though you should use a stronger
|
||||
hash like sha256 whenever possible.
|
||||
* Hashes are required for all dependencies. An error results if there is a
|
||||
dependency that is not spelled out and hashed in the requirements file.
|
||||
* Requirements that take the form of project names (rather than URLs or local
|
||||
filesystem paths) must be pinned to a specific version using ``==``. This
|
||||
prevents a surprising hash mismatch upon the release of a new version
|
||||
that matches the requirement specifier.
|
||||
* ``--egg`` is disallowed, because it delegates installation of dependencies
|
||||
to setuptools, giving up pip's ability to enforce any of the above.
|
||||
|
||||
.. _`--require-hashes`:
|
||||
|
||||
Hash-checking mode can be forced on with the ``--require-hashes`` command-line
|
||||
option:
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python -m pip install --require-hashes -r requirements.txt
|
||||
...
|
||||
Hashes are required in --require-hashes mode (implicitly on when a hash is
|
||||
specified for any package). These requirements were missing hashes,
|
||||
leaving them open to tampering. These are the hashes the downloaded
|
||||
archives actually had. You can add lines like these to your requirements
|
||||
files to prevent tampering.
|
||||
pyelasticsearch==1.0 --hash=sha256:44ddfb1225054d7d6b1d02e9338e7d4809be94edbe9929a2ec0807d38df993fa
|
||||
more-itertools==2.2 --hash=sha256:93e62e05c7ad3da1a233def6731e8285156701e3419a5fe279017c429ec67ce0
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
C:\> py -m pip install --require-hashes -r requirements.txt
|
||||
...
|
||||
Hashes are required in --require-hashes mode (implicitly on when a hash is
|
||||
specified for any package). These requirements were missing hashes,
|
||||
leaving them open to tampering. These are the hashes the downloaded
|
||||
archives actually had. You can add lines like these to your requirements
|
||||
files to prevent tampering.
|
||||
pyelasticsearch==1.0 --hash=sha256:44ddfb1225054d7d6b1d02e9338e7d4809be94edbe9929a2ec0807d38df993fa
|
||||
more-itertools==2.2 --hash=sha256:93e62e05c7ad3da1a233def6731e8285156701e3419a5fe279017c429ec67ce0
|
||||
|
||||
|
||||
This can be useful in deploy scripts, to ensure that the author of the
|
||||
requirements file provided hashes. It is also a convenient way to bootstrap
|
||||
your list of hashes, since it shows the hashes of the packages it fetched. It
|
||||
fetches only the preferred archive for each package, so you may still need to
|
||||
add hashes for alternatives archives using :ref:`pip hash`: for instance if
|
||||
there is both a binary and a source distribution.
|
||||
|
||||
The :ref:`wheel cache <Wheel cache>` is disabled in hash-checking mode to
|
||||
prevent spurious hash mismatch errors. These would otherwise occur while
|
||||
installing sdists that had already been automatically built into cached wheels:
|
||||
those wheels would be selected for installation, but their hashes would not
|
||||
match the sdist ones from the requirements file. A further complication is that
|
||||
locally built wheels are nondeterministic: contemporary modification times make
|
||||
their way into the archive, making hashes unpredictable across machines and
|
||||
cache flushes. Compilation of C code adds further nondeterminism, as many
|
||||
compilers include random-seeded values in their output. However, wheels fetched
|
||||
from index servers are the same every time. They land in pip's HTTP cache, not
|
||||
its wheel cache, and are used normally in hash-checking mode. The only downside
|
||||
of having the wheel cache disabled is thus extra build time for sdists, and
|
||||
this can be solved by making sure pre-built wheels are available from the index
|
||||
server.
|
||||
|
||||
Hash-checking mode also works with :ref:`pip download` and :ref:`pip wheel`.
|
||||
See :doc:`../topics/repeatable-installs` for a comparison of hash-checking mode
|
||||
with other repeatability strategies.
|
||||
|
||||
.. warning::
|
||||
|
||||
Beware of the ``setup_requires`` keyword arg in :file:`setup.py`. The
|
||||
(rare) packages that use it will cause those dependencies to be downloaded
|
||||
by setuptools directly, skipping pip's hash-checking. If you need to use
|
||||
such a package, see :ref:`Controlling
|
||||
setup_requires<controlling-setup-requires>`.
|
||||
|
||||
.. warning::
|
||||
|
||||
Be careful not to nullify all your security work when you install your
|
||||
actual project by using setuptools directly: for example, by calling
|
||||
``python setup.py install``, ``python setup.py develop``, or
|
||||
``easy_install``. Setuptools will happily go out and download, unchecked,
|
||||
anything you missed in your requirements file—and it’s easy to miss things
|
||||
as your project evolves. To be safe, install your project using pip and
|
||||
:ref:`--no-deps <install_--no-deps>`.
|
||||
|
||||
Instead of ``python setup.py develop``, use...
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install --no-deps -e .
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py -m pip install --no-deps -e .
|
||||
|
||||
|
||||
Instead of ``python setup.py install``, use...
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install --no-deps .
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py -m pip install --no-deps .
|
||||
|
||||
Hashes from PyPI
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
PyPI provides an MD5 hash in the fragment portion of each package download URL,
|
||||
like ``#md5=123...``, which pip checks as a protection against download
|
||||
corruption. Other hash algorithms that have guaranteed support from ``hashlib``
|
||||
are also supported here: sha1, sha224, sha384, sha256, and sha512. Since this
|
||||
hash originates remotely, it is not a useful guard against tampering and thus
|
||||
does not satisfy the ``--require-hashes`` demand that every package have a
|
||||
local hash.
|
||||
|
||||
|
||||
Local project installs
|
||||
Local Project Installs
|
||||
----------------------
|
||||
|
||||
pip supports installing local project in both regular mode and editable mode.
|
||||
You can install local projects by specifying the project path to pip:
|
||||
This is now covered in :doc:`../topics/local-project-installs`.
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install path/to/SomeProject
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py -m pip install path/to/SomeProject
|
||||
|
||||
During regular installation, pip will copy the entire project directory to a
|
||||
temporary location and install from there. The exception is that pip will
|
||||
exclude .tox and .nox directories present in the top level of the project from
|
||||
being copied. This approach is the cause of several performance and correctness
|
||||
issues, so it is planned that pip 21.3 will change to install directly from the
|
||||
local project directory. Depending on the build backend used by the project,
|
||||
this may generate secondary build artifacts in the project directory, such as
|
||||
the ``.egg-info`` and ``build`` directories in the case of the setuptools
|
||||
backend.
|
||||
|
||||
To opt in to the future behavior, specify the ``--use-feature=in-tree-build``
|
||||
option in pip's command line.
|
||||
|
||||
|
||||
.. _`editable-installs`:
|
||||
|
||||
"Editable" Installs
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
"Editable" installs are fundamentally `"setuptools develop mode"
|
||||
<https://setuptools.readthedocs.io/en/latest/userguide/development_mode.html>`_
|
||||
installs.
|
||||
|
||||
You can install local projects or VCS projects in "editable" mode:
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip install -e path/to/SomeProject
|
||||
python -m pip install -e git+http://repo/my_project.git#egg=SomeProject
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py -m pip install -e path/to/SomeProject
|
||||
py -m pip install -e git+http://repo/my_project.git#egg=SomeProject
|
||||
|
||||
|
||||
(See the :doc:`../topics/vcs-support` section above for more information on VCS-related syntax.)
|
||||
|
||||
For local projects, the "SomeProject.egg-info" directory is created relative to
|
||||
the project path. This is one advantage over just using ``setup.py develop``,
|
||||
which creates the "egg-info" directly relative the current working directory.
|
||||
|
||||
|
||||
.. _`controlling-setup-requires`:
|
||||
|
||||
Controlling setup_requires
|
||||
--------------------------
|
||||
|
||||
Setuptools offers the ``setup_requires`` `setup() keyword
|
||||
<https://setuptools.readthedocs.io/en/latest/userguide/keywords.html>`_
|
||||
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.
|
||||
|
||||
The solution is to configure a "system" or "personal" `Distutils configuration
|
||||
file
|
||||
<https://docs.python.org/3/install/index.html#distutils-configuration-files>`_ to
|
||||
manage the fulfillment.
|
||||
|
||||
For example, to have the dependency located at an alternate index, add this:
|
||||
|
||||
::
|
||||
|
||||
[easy_install]
|
||||
index_url = https://my.index-mirror.com
|
||||
|
||||
To have the dependency located from a local directory and not crawl PyPI, add this:
|
||||
|
||||
::
|
||||
|
||||
[easy_install]
|
||||
allow_hosts = ''
|
||||
find_links = file:///path/to/local/archives/
|
||||
Editable installs
|
||||
-----------------
|
||||
|
||||
This is now covered in :doc:`../topics/local-project-installs`.
|
||||
|
||||
Build System Interface
|
||||
----------------------
|
||||
|
||||
In order for pip to install a package from source, ``setup.py`` must implement
|
||||
the following commands::
|
||||
|
||||
setup.py egg_info [--egg-base XXX]
|
||||
setup.py install --record XXX [--single-version-externally-managed] [--root XXX] [--compile|--no-compile] [--install-headers XXX]
|
||||
|
||||
The ``egg_info`` command should create egg metadata for the package, as
|
||||
described in the setuptools documentation at
|
||||
https://setuptools.readthedocs.io/en/latest/userguide/commands.html#egg-info-create-egg-metadata-and-set-build-tags
|
||||
|
||||
The ``install`` command should implement the complete process of installing the
|
||||
package to the target directory XXX.
|
||||
|
||||
To install a package in "editable" mode (``pip install -e``), ``setup.py`` must
|
||||
implement the following command::
|
||||
|
||||
setup.py develop --no-deps
|
||||
|
||||
This should implement the complete process of installing the package in
|
||||
"editable" mode.
|
||||
|
||||
All packages will be attempted to built into wheels::
|
||||
|
||||
setup.py bdist_wheel -d XXX
|
||||
|
||||
One further ``setup.py`` command is invoked by ``pip install``::
|
||||
|
||||
setup.py clean
|
||||
|
||||
This command is invoked to clean up temporary commands from the build. (TODO:
|
||||
Investigate in more detail when this command is required).
|
||||
|
||||
No other build system commands are invoked by the ``pip install`` command.
|
||||
|
||||
Installing a package from a wheel does not invoke the build system at all.
|
||||
|
||||
.. _PyPI: https://pypi.org/
|
||||
.. _setuptools extras: https://setuptools.readthedocs.io/en/latest/userguide/dependency_management.html#optional-dependencies
|
||||
|
||||
This is now covered in :doc:`../reference/build-system/index`.
|
||||
|
||||
|
||||
.. _`pip install Options`:
|
||||
|
@ -743,7 +387,7 @@ Examples
|
|||
py -m pip install -e git+https://git.repo/some_pkg.git@feature#egg=SomePackage # from 'feature' branch
|
||||
py -m pip install -e "git+https://git.repo/some_repo.git#egg=subdir&subdirectory=subdir_path" # install a python package from a repo subdirectory
|
||||
|
||||
#. Install a package with `setuptools extras`_.
|
||||
#. Install a package with `extras`_.
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
|
@ -902,7 +546,5 @@ Examples
|
|||
|
||||
py -m pip install SomePackage1 SomePackage2 --no-binary SomePackage1
|
||||
|
||||
----
|
||||
|
||||
.. [1] This is true with the exception that pip v7.0 and v7.0.1 required quotes
|
||||
around specifiers containing environment markers in requirement files.
|
||||
.. _extras: https://www.python.org/dev/peps/pep-0508/#extras
|
||||
.. _PyPI: https://pypi.org/
|
||||
|
|
|
@ -139,3 +139,93 @@ Examples
|
|||
docopt==0.6.2
|
||||
idlex==1.13
|
||||
jedi==0.9.0
|
||||
|
||||
#. List packages installed in editable mode
|
||||
|
||||
When some packages are installed in editable mode, ``pip list`` outputs an
|
||||
additional column that shows the directory where the editable project is
|
||||
located (i.e. the directory that contains the ``pyproject.toml`` or
|
||||
``setup.py`` file).
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python -m pip list
|
||||
Package Version Editable project location
|
||||
---------------- -------- -------------------------------------
|
||||
pip 21.2.4
|
||||
pip-test-package 0.1.1 /home/you/.venv/src/pip-test-package
|
||||
setuptools 57.4.0
|
||||
wheel 0.36.2
|
||||
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
C:\> py -m pip list
|
||||
Package Version Editable project location
|
||||
---------------- -------- ----------------------------------------
|
||||
pip 21.2.4
|
||||
pip-test-package 0.1.1 C:\Users\You\.venv\src\pip-test-package
|
||||
setuptools 57.4.0
|
||||
wheel 0.36.2
|
||||
|
||||
The json format outputs an additional ``editable_project_location`` field.
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python -m pip list --format=json | python -m json.tool
|
||||
[
|
||||
{
|
||||
"name": "pip",
|
||||
"version": "21.2.4",
|
||||
},
|
||||
{
|
||||
"name": "pip-test-package",
|
||||
"version": "0.1.1",
|
||||
"editable_project_location": "/home/you/.venv/src/pip-test-package"
|
||||
},
|
||||
{
|
||||
"name": "setuptools",
|
||||
"version": "57.4.0"
|
||||
},
|
||||
{
|
||||
"name": "wheel",
|
||||
"version": "0.36.2"
|
||||
}
|
||||
]
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
C:\> py -m pip list --format=json | py -m json.tool
|
||||
[
|
||||
{
|
||||
"name": "pip",
|
||||
"version": "21.2.4",
|
||||
},
|
||||
{
|
||||
"name": "pip-test-package",
|
||||
"version": "0.1.1",
|
||||
"editable_project_location": "C:\Users\You\.venv\src\pip-test-package"
|
||||
},
|
||||
{
|
||||
"name": "setuptools",
|
||||
"version": "57.4.0"
|
||||
},
|
||||
{
|
||||
"name": "wheel",
|
||||
"version": "0.36.2"
|
||||
}
|
||||
]
|
||||
|
||||
.. note::
|
||||
|
||||
Contrary to the ``freeze`` command, ``pip list --format=freeze`` will not
|
||||
report editable install information, but the version of the package at the
|
||||
time it was installed.
|
||||
|
|
|
@ -28,60 +28,7 @@ Description
|
|||
Build System Interface
|
||||
----------------------
|
||||
|
||||
In order for pip to build a wheel, ``setup.py`` must implement the
|
||||
``bdist_wheel`` command with the following syntax:
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python setup.py bdist_wheel -d TARGET
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py setup.py bdist_wheel -d TARGET
|
||||
|
||||
|
||||
This command must create a wheel compatible with the invoking Python
|
||||
interpreter, and save that wheel in the directory TARGET.
|
||||
|
||||
No other build system commands are invoked by the ``pip wheel`` command.
|
||||
|
||||
Customising the build
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
It is possible using ``--global-option`` to include additional build commands
|
||||
with their arguments in the ``setup.py`` command. This is currently the only
|
||||
way to influence the building of C extensions from the command line. For
|
||||
example:
|
||||
|
||||
.. tab:: Unix/macOS
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
|
||||
|
||||
.. tab:: Windows
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
py -m pip wheel --global-option bdist_ext --global-option -DFOO wheel
|
||||
|
||||
|
||||
will result in a build command of
|
||||
|
||||
::
|
||||
|
||||
setup.py bdist_ext -DFOO bdist_wheel -d TARGET
|
||||
|
||||
which passes a preprocessor symbol to the extension build.
|
||||
|
||||
Such usage is considered highly build-system specific and more an accident of
|
||||
the current implementation than a supported interface.
|
||||
|
||||
|
||||
This is now covered in :doc:`../reference/build-system/index`.
|
||||
|
||||
Options
|
||||
=======
|
||||
|
|
|
@ -55,6 +55,7 @@ print("pip release:", release)
|
|||
# -- Options for myst-parser ----------------------------------------------------------
|
||||
|
||||
myst_enable_extensions = ["deflist"]
|
||||
myst_heading_anchors = 3
|
||||
|
||||
# -- Options for smartquotes ----------------------------------------------------------
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ The ``README``, license, ``pyproject.toml``, ``setup.py``, and so on are in the
|
|||
|
||||
* ``__init__.py``
|
||||
* ``conftest.py``
|
||||
* ``data/`` *[test data for running tests -- pesudo package index in it! Lots of small packages that are invalid or are valid. Test fixtures. Used by functional tests]*
|
||||
* ``data/`` *[test data for running tests -- pseudo package index in it! Lots of small packages that are invalid or are valid. Test fixtures. Used by functional tests]*
|
||||
* ``functional/`` *[functional tests of pip’s CLI -- end-to-end, invoke pip in subprocess & check results of execution against desired result. This also is what makes test suite slow]*
|
||||
* ``lib/`` *[helpers for tests]*
|
||||
* ``unit/`` *[unit tests -- fast and small and nice!]*
|
||||
|
|
|
@ -18,17 +18,17 @@ Supported interpreters
|
|||
|
||||
pip support a variety of Python interpreters:
|
||||
|
||||
- CPython 3.6
|
||||
- CPython 3.7
|
||||
- CPython 3.8
|
||||
- CPython 3.9
|
||||
- CPython 3.10
|
||||
- Latest PyPy3
|
||||
|
||||
on different operating systems:
|
||||
|
||||
- Linux
|
||||
- Windows
|
||||
- MacOS
|
||||
- macOS
|
||||
|
||||
and on different architectures:
|
||||
|
||||
|
@ -77,9 +77,9 @@ Developer tasks
|
|||
======== =============== ================ ================== =============
|
||||
OS docs lint vendoring packaging
|
||||
======== =============== ================ ================== =============
|
||||
Linux Github Github Github Github
|
||||
Windows Github Github Github Github
|
||||
MacOS Github Github Github Github
|
||||
Linux GitHub GitHub GitHub GitHub
|
||||
Windows GitHub GitHub GitHub GitHub
|
||||
macOS GitHub GitHub GitHub GitHub
|
||||
======== =============== ================ ================== =============
|
||||
|
||||
Actual testing
|
||||
|
@ -88,28 +88,26 @@ Actual testing
|
|||
+------------------------------+---------------+-----------------+
|
||||
| **interpreter** | **unit** | **integration** |
|
||||
+-----------+----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x86 | CP3.7 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.9 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.10| | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
| Windows +----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | Github | Github |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x64 | CP3.7 | | |
|
||||
| | x64 | CP3.7 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.9 | Github | Github |
|
||||
| | | CP3.9 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.10| GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
+-----------+----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x86 | CP3.7 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | | |
|
||||
|
@ -118,33 +116,33 @@ Actual testing
|
|||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
| Linux +----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | Github | Github |
|
||||
| | x64 | CP3.7 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x64 | CP3.7 | Github | Github |
|
||||
| | | CP3.8 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | Github | Github |
|
||||
| | | CP3.9 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.9 | Github | Github |
|
||||
| | | CP3.10| GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
+-----------+----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x86 | CP3.7 | | |
|
||||
| | arm64 | CP3.7 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.9 | | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.10| | |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
| MacOS +----------+-------+---------------+-----------------+
|
||||
| | | CP3.6 | Github | Github |
|
||||
| macOS +----------+-------+---------------+-----------------+
|
||||
| | x64 | CP3.7 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | x64 | CP3.7 | Github | Github |
|
||||
| | | CP3.8 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.8 | Github | Github |
|
||||
| | | CP3.9 | GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | CP3.9 | Github | Github |
|
||||
| | | CP3.10| GitHub | GitHub |
|
||||
| | +-------+---------------+-----------------+
|
||||
| | | PyPy3 | | |
|
||||
+-----------+----------+-------+---------------+-----------------+
|
||||
|
|
|
@ -27,8 +27,8 @@ Development Environment
|
|||
pip is a command line application written in Python. For developing pip,
|
||||
you should `install Python`_ on your computer.
|
||||
|
||||
For developing pip, you need to install :pypi:`tox`. Often, you can run
|
||||
``python -m pip install tox`` to install and use it.
|
||||
For developing pip, you need to install :pypi:`nox`. Often, you can run
|
||||
``python -m pip install nox`` to install and use it.
|
||||
|
||||
|
||||
Running pip From Source Tree
|
||||
|
@ -42,8 +42,8 @@ You can then invoke your local source tree pip normally.
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
virtualenv venv # You can also use "python -m venv venv" from python3.3+
|
||||
source venv/bin/activate
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
python -m pip install -e .
|
||||
python -m pip --version
|
||||
|
||||
|
@ -51,8 +51,8 @@ You can then invoke your local source tree pip normally.
|
|||
|
||||
.. code-block:: shell
|
||||
|
||||
virtualenv venv # You can also use "py -m venv venv" from python3.3+
|
||||
venv\Scripts\activate
|
||||
py -m venv .venv
|
||||
.venv\Scripts\activate
|
||||
py -m pip install -e .
|
||||
py -m pip --version
|
||||
|
||||
|
@ -60,7 +60,7 @@ Running Tests
|
|||
=============
|
||||
|
||||
pip's tests are written using the :pypi:`pytest` test framework and
|
||||
:mod:`unittest.mock`. :pypi:`tox` is used to automate the setup and execution
|
||||
:mod:`unittest.mock`. :pypi:`nox` is used to automate the setup and execution
|
||||
of pip's tests.
|
||||
|
||||
It is preferable to run the tests in parallel for better experience during development,
|
||||
|
@ -70,38 +70,39 @@ To run tests:
|
|||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e py36 -- -n auto
|
||||
$ nox -s test-3.10 -- -n auto
|
||||
|
||||
To run tests without parallelization, run:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e py36
|
||||
$ nox -s test-3.10
|
||||
|
||||
The example above runs tests against Python 3.6. You can also use other
|
||||
versions like ``py39`` and ``pypy3``.
|
||||
The example above runs tests against Python 3.10. You can also use other
|
||||
versions like ``3.9`` and ``pypy3``.
|
||||
|
||||
``tox`` has been configured to forward any additional arguments it is given to
|
||||
``nox`` has been configured to forward any additional arguments it is given to
|
||||
``pytest``. This enables the use of pytest's `rich CLI`_. As an example, you
|
||||
can select tests using the various ways that pytest provides:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ # Using file name
|
||||
$ tox -e py36 -- tests/functional/test_install.py
|
||||
$ nox -s test-3.10 -- tests/functional/test_install.py
|
||||
$ # Using markers
|
||||
$ tox -e py36 -- -m unit
|
||||
$ nox -s test-3.10 -- -m unit
|
||||
$ # Using keywords
|
||||
$ tox -e py36 -- -k "install and not wheel"
|
||||
$ nox -s test-3.10 -- -k "install and not wheel"
|
||||
|
||||
Running pip's test suite requires supported version control tools (subversion,
|
||||
bazaar, git, and mercurial) to be installed. If you are missing one of the VCS
|
||||
tools, you can tell pip to skip those tests:
|
||||
Running pip's entire test suite requires supported version control tools
|
||||
(subversion, bazaar, git, and mercurial) to be installed. If you are missing
|
||||
any of these VCS, those tests should be skipped automatically. You can also
|
||||
explicitly tell pytest to skip those tests:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e py36 -- -k "not svn"
|
||||
$ tox -e py36 -- -k "not (svn or git)"
|
||||
$ nox -s test-3.10 -- -k "not svn"
|
||||
$ nox -s test-3.10 -- -k "not (svn or git)"
|
||||
|
||||
|
||||
Running Linters
|
||||
|
@ -115,7 +116,7 @@ To use linters locally, run:
|
|||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e lint
|
||||
$ nox -s lint
|
||||
|
||||
.. note::
|
||||
|
||||
|
@ -125,6 +126,25 @@ To use linters locally, run:
|
|||
readability problems.
|
||||
|
||||
|
||||
Running pip under a debugger
|
||||
============================
|
||||
|
||||
In order to debug pip's behavior, you can run it under a debugger like so:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ python -m pdb -m pip --debug ...
|
||||
|
||||
|
||||
Replace the ``...`` with arguments you'd like to run pip with. Give PDB the
|
||||
``c`` ("continue") command afterwards, to run the process.
|
||||
|
||||
The ``--debug`` flag disables pip's exception handler, which would normally
|
||||
catch all unhandled exceptions. With this flag, pip will let these exceptions
|
||||
propagate outside of its main subroutine, letting them get caught by the
|
||||
debugger. This way you'll be able to debug an exception post-mortem via PDB.
|
||||
|
||||
|
||||
Building Documentation
|
||||
======================
|
||||
|
||||
|
@ -135,7 +155,7 @@ To build it locally, run:
|
|||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox -e docs
|
||||
$ nox -s docs
|
||||
|
||||
The built documentation can be found in the ``docs/build`` folder.
|
||||
|
||||
|
|
|
@ -137,7 +137,7 @@ The lifecycle of an issue (bug or support) generally looks like:
|
|||
#. waiting for triage (marked with label ``triage``)
|
||||
#. confirming issue - some discussion with the user, gathering
|
||||
details, trying to reproduce the issue (may be marked with a specific
|
||||
category, ``S: awaiting-respose``, ``S: discussion-needed``, or
|
||||
category, ``S: awaiting-response``, ``S: discussion-needed``, or
|
||||
``S: need-repro``)
|
||||
#. confirmed - the issue is pretty consistently reproducible in a
|
||||
straightforward way, or a mechanism that could be causing the issue has been
|
||||
|
|
|
@ -14,7 +14,7 @@ If your Python environment does not have pip installed, there are 2 mechanisms
|
|||
to install pip supported directly by pip's maintainers:
|
||||
|
||||
- [`ensurepip`](#ensurepip)
|
||||
- [`get-pip.py`](#get-pip-py)
|
||||
- [`get-pip.py`](#get-pippy)
|
||||
|
||||
### `ensurepip`
|
||||
|
||||
|
@ -75,14 +75,15 @@ $ pip install --upgrade pip
|
|||
The current version of pip works on:
|
||||
|
||||
- Windows, Linux and MacOS.
|
||||
- CPython 3.6, 3.7, 3.8, 3.9, 3.10 and latest PyPy3.
|
||||
- CPython 3.7, 3.8, 3.9, 3.10 and latest PyPy3.
|
||||
|
||||
pip is tested to work on the latest patch version of the Python interpreter,
|
||||
for each of the minor versions listed above. Previous patch versions are
|
||||
supported on a best effort approach.
|
||||
|
||||
pip's maintainers do not provide support for users on older versions of Python,
|
||||
and these users should request for support from the relevant provider
|
||||
(eg: Linux distro community, cloud provider support channels, etc).
|
||||
Other operating systems and Python versions are not supported by pip's
|
||||
maintainers.
|
||||
|
||||
Users who are on unsupported platforms should be aware that if they hit issues, they may have to resolve them for themselves. If they received pip from a source which provides support for their platform, they should request pip support from that source.
|
||||
|
||||
[^python]: The `ensurepip` module was added to the Python standard library in Python 3.4.
|
||||
|
|
|
@ -7,6 +7,6 @@ Changelog
|
|||
Major and minor releases of pip also include changes listed within
|
||||
prior beta releases.
|
||||
|
||||
.. towncrier-draft-entries:: |release|, unreleased as on
|
||||
.. towncrier-draft-entries:: Not yet released
|
||||
|
||||
.. pip-news-include:: ../../NEWS.rst
|
||||
|
|
127
docs/html/reference/build-system/index.md
Normal file
127
docs/html/reference/build-system/index.md
Normal file
|
@ -0,0 +1,127 @@
|
|||
(build-interface)=
|
||||
|
||||
# Build System Interface
|
||||
|
||||
When dealing with installable source distributions of a package, pip does not
|
||||
directly handle the build process for the package. This responsibility is
|
||||
delegated to "build backends" -- also known as "build systems". This means
|
||||
that pip needs an interface, to interact with these build backends.
|
||||
|
||||
There are two main interfaces that pip uses for these interactions:
|
||||
|
||||
```{toctree}
|
||||
:hidden:
|
||||
|
||||
pyproject-toml
|
||||
setup-py
|
||||
```
|
||||
|
||||
<!-- prettier-ignore-start -->
|
||||
[`pyproject.toml` based](pyproject-toml)
|
||||
: Standards-backed interface, that has explicit declaration and management of
|
||||
build dependencies.
|
||||
|
||||
[`setup.py` based](setup-py)
|
||||
: Legacy interface, that we're working to migrate users away from. Has no good
|
||||
mechanisms to declare build dependencies.
|
||||
<!-- prettier-ignore-end -->
|
||||
|
||||
Details on the individual interfaces can be found on their dedicated pages,
|
||||
linked above. This document covers the nuances around which build system
|
||||
interface pip will use for a project, as well as details that apply to all
|
||||
the build system interfaces that pip may use.
|
||||
|
||||
## Determining which build system interface is used
|
||||
|
||||
Currently, pip uses the `pyproject.toml` based build system interface, if a
|
||||
`pyproject.toml` file exists. If not, the legacy build system interface is used.
|
||||
The intention is to switch to using the `pyproject.toml` build system interface
|
||||
unconditionally and to drop support for the legacy build system interface at
|
||||
some point in the future.
|
||||
|
||||
When performing a build, pip will mention which build system interface it is
|
||||
using. Typically, this will take the form of a message like:
|
||||
|
||||
```none
|
||||
Building wheel for pip (pyproject.toml)... done
|
||||
```
|
||||
|
||||
```none
|
||||
Building wheel for pip (setup.py)... done
|
||||
```
|
||||
|
||||
The content in the brackets, refers to which build system interface is being
|
||||
used.
|
||||
|
||||
```{versionchanged} 21.3
|
||||
The output uses "pyproject.toml" instead of "PEP 517" to refer to be
|
||||
`pyproject.toml` based build system interface.
|
||||
```
|
||||
|
||||
## Controlling which build system interface is used
|
||||
|
||||
The [`--use-pep517`](install_--use-pep517) flag (and corresponding environment
|
||||
variable: `PIP_USE_PEP517`) can be used to force all packages to build using
|
||||
the `pyproject.toml` based build system interface. There is no way to force
|
||||
the use of the legacy build system interface.
|
||||
|
||||
(controlling-setup_requires)=
|
||||
|
||||
## Controlling `setup_requires`
|
||||
|
||||
```{hint}
|
||||
This is only relevant for projects that use setuptools as the build backend,
|
||||
and use the `setup_requires` keyword argument in their setup.py file.
|
||||
```
|
||||
|
||||
The `setup_requires` argument in `setup.py` is used to specify build-time
|
||||
dependencies for a package. This has been superseded by the
|
||||
`build-system.requires` key in `pyproject.toml` files (per {pep}`518`).
|
||||
However, there are situations where you might encounter a package that uses
|
||||
`setup_requires` (eg: the package has not been updated to use the newer
|
||||
approach yet!).
|
||||
|
||||
If you control the package, consider adding a `pyproject.toml` file to utilise
|
||||
the modern build system interface. That avoids invoking the problematic
|
||||
behaviour by deferring to pip for the installations.
|
||||
|
||||
For the end users, the best solution for dealing with packages with
|
||||
`setup_requires` is to install the packages listed in `setup_requires`
|
||||
beforehand, using a prior `pip install` command. This is because there is no
|
||||
way to control how these dependencies are located by `easy_install`, or how
|
||||
setuptools will invoke `pip` using pip's command line options -- which makes it
|
||||
tricky to get things working appropriately.
|
||||
|
||||
If you wish to ensure that `easy_install` invocations do not reach out to PyPI,
|
||||
you will need to configure its behaviour using a
|
||||
[`distutils` configuration file][distutils-config]. Here are some examples:
|
||||
|
||||
- To have the dependency located at an alternate index with `easy_install`
|
||||
|
||||
```ini
|
||||
[easy_install]
|
||||
index_url = https://my.index-mirror.com
|
||||
```
|
||||
|
||||
- To have the dependency located from a local directory and not crawl PyPI, add this:
|
||||
|
||||
```ini
|
||||
[easy_install]
|
||||
allow_hosts = ''
|
||||
find_links = file:///path/to/local/archives/
|
||||
```
|
||||
|
||||
```{admonition} Historical context
|
||||
`setuptools < 52.0` will use `easy_install` to try to fulfill `setup_requires`
|
||||
dependencies, which can result in weird failures -- `easy_install` does not
|
||||
understand many of the modern Python packaging standards, and will usually
|
||||
attempt to install incompatible package versions or to build packages
|
||||
incorrectly. It also generates improper script wrappers, which don't do the
|
||||
right thing in many situations.
|
||||
|
||||
Newer versions of `setuptools` will use `pip` for these installations, but have
|
||||
limited ability to pass through any command line arguments. This can also result
|
||||
in weird failures and subtly-incorrect behaviour.
|
||||
```
|
||||
|
||||
[distutils-config]: https://docs.python.org/3/install/index.html#distutils-configuration-files
|
146
docs/html/reference/build-system/pyproject-toml.md
Normal file
146
docs/html/reference/build-system/pyproject-toml.md
Normal file
|
@ -0,0 +1,146 @@
|
|||
# `pyproject.toml`
|
||||
|
||||
```{versionadded} 10.0
|
||||
|
||||
```
|
||||
|
||||
Modern Python packages can contain a `pyproject.toml` file, first introduced in
|
||||
{pep}`518` and later expanded in {pep}`517`, {pep}`621` and {pep}`660`.
|
||||
This file contains build system requirements and information, which are used by
|
||||
pip to build the package.
|
||||
|
||||
## Build process
|
||||
|
||||
The overall process for building a package is:
|
||||
|
||||
- Create an isolated build environment.
|
||||
- Populate the build environment with build dependencies.
|
||||
- Generate the package's metadata, if necessary and possible.
|
||||
- Generate a wheel for the package.
|
||||
|
||||
The wheel can then be used to perform an installation, if necessary.
|
||||
|
||||
### Build Isolation
|
||||
|
||||
For building packages using this interface, pip uses an _isolated environment_.
|
||||
That is, pip will install build-time Python dependencies in a temporary
|
||||
directory which will be added to `sys.path` for the build commands. This ensures
|
||||
that build requirements are handled independently of the user's runtime
|
||||
environment.
|
||||
|
||||
For example, a project that needs an older version of setuptools to build can
|
||||
still be installed, even if the user has an newer version installed (and
|
||||
without silently replacing that version).
|
||||
|
||||
### Build-time dependencies
|
||||
|
||||
Introduced in {pep}`518`, the `build-system.requires` key in the
|
||||
`pyproject.toml` file is a list of requirement specifiers for build-time
|
||||
dependencies of a package.
|
||||
|
||||
```toml
|
||||
[build-system]
|
||||
requires = ["setuptools ~= 58.0", "cython ~= 0.29.0"]
|
||||
```
|
||||
|
||||
It is also possible for a build backend to provide dynamically calculated
|
||||
build dependencies, using {pep}`517`'s `get_requires_for_build_wheel` hook. This
|
||||
hook will be called by pip, and dependencies it describes will also be installed
|
||||
in the build environment. For example, newer versions of setuptools expose the
|
||||
contents of `setup_requires` to pip via this hook.
|
||||
|
||||
### Metadata Generation
|
||||
|
||||
```{versionadded} 19.0
|
||||
|
||||
```
|
||||
|
||||
Once the build environment has been created and populated with build-time
|
||||
dependencies, `pip` will usually need metadata about a package (name, version,
|
||||
dependencies, and more).
|
||||
|
||||
If {pep}`517`'s `prepare_metadata_for_build_wheel` hook is provided by the
|
||||
build backend, that will be used to generate the packages' metadata. Otherwise,
|
||||
a wheel will be generated (as described below) and the metadata contained
|
||||
within such a wheel will be used.
|
||||
|
||||
### Wheel Generation
|
||||
|
||||
```{versionadded} 19.0
|
||||
|
||||
```
|
||||
|
||||
For generating a wheel, pip uses the {pep}`517` `build_wheel` hook that has
|
||||
to be provided by the build backend. The build backend will generate a wheel,
|
||||
which may involve compiling extension code written in C/C++ (or other
|
||||
languages).
|
||||
|
||||
Wheels generated using this mechanism can be [cached](wheel-caching) for reuse,
|
||||
to speed up future installations.
|
||||
|
||||
### Editable Installation
|
||||
|
||||
```{versionadded} 21.3
|
||||
|
||||
```
|
||||
|
||||
For performing editable installs, pip will use {pep}`660`
|
||||
`build_wheel_for_editable` hook that has to be provided by the build backend.
|
||||
The wheels generated using this mechanism are not cached.
|
||||
|
||||
```{admonition} Compatibility fallback
|
||||
If this hook is missing on the build backend _and_ there's a `setup.py` file
|
||||
in the project, pip will fallback to the legacy setup.py-based editable
|
||||
installation.
|
||||
|
||||
This is considered a stopgap solution until setuptools adds support for
|
||||
{pep}`660`, at which point this functionality will be removed; following pip's
|
||||
regular {ref}`deprecation policy <Deprecation Policy>`.
|
||||
```
|
||||
|
||||
## Build output
|
||||
|
||||
It is the responsibility of the build backend to ensure that the output is
|
||||
in the correct encoding, as described in {pep}`517`. This likely involves
|
||||
dealing with [the same challenges as pip has for legacy builds](build-output).
|
||||
|
||||
## Fallback Behaviour
|
||||
|
||||
If a project does not have a `pyproject.toml` file containing a `build-system`
|
||||
section, it will be assumed to have the following backend settings:
|
||||
|
||||
```toml
|
||||
[build-system]
|
||||
requires = ["setuptools>=40.8.0", "wheel"]
|
||||
build-backend = "setuptools.build_meta:__legacy__"
|
||||
```
|
||||
|
||||
If a project has a `build-system` section but no `build-backend`, then:
|
||||
|
||||
- It is expected to include `setuptools` and `wheel` as build requirements. An
|
||||
error is reported if the available version of `setuptools` is not recent
|
||||
enough.
|
||||
|
||||
- The `setuptools.build_meta:__legacy__` build backend will be used.
|
||||
|
||||
## Disabling build isolation
|
||||
|
||||
This can be disabled using the `--no-build-isolation` flag -- users supplying
|
||||
this flag are responsible for ensuring the build environment is managed
|
||||
appropriately, including ensuring that all required build-time dependencies are
|
||||
installed, since pip does not manage build-time dependencies when this flag is
|
||||
passed.
|
||||
|
||||
## Historical notes
|
||||
|
||||
As this feature was incrementally rolled out, there have been various notable
|
||||
changes and improvements in it.
|
||||
|
||||
- setuptools 40.8.0 is the first version of setuptools that offers a
|
||||
{pep}`517` backend that closely mimics directly executing `setup.py`.
|
||||
- Prior to pip 18.0, pip only supports installing build requirements from
|
||||
wheels, and does not support the use of environment markers and extras (only
|
||||
version specifiers are respected).
|
||||
- Prior to 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.
|
133
docs/html/reference/build-system/setup-py.md
Normal file
133
docs/html/reference/build-system/setup-py.md
Normal file
|
@ -0,0 +1,133 @@
|
|||
# `setup.py` (legacy)
|
||||
|
||||
Prior to the introduction of pyproject.toml-based builds (in {pep}`517` and
|
||||
{pep}`518`), pip had only supported installing packages using `setup.py` files
|
||||
that were built using {pypi}`setuptools`.
|
||||
|
||||
The interface documented here is retained currently solely for legacy purposes,
|
||||
until the migration to `pyproject.toml`-based builds can be completed.
|
||||
|
||||
```{caution}
|
||||
The arguments and syntax of the various invocations of `setup.py` made by
|
||||
pip, are considered an implementation detail that is strongly coupled with
|
||||
{pypi}`setuptools`. This build system interface is not meant to be used by any
|
||||
other build backend, which should be based on the {doc}`pyproject-toml` build
|
||||
system interface instead.
|
||||
|
||||
Further, projects should _not_ expect to rely on there being any form of
|
||||
backward compatibility guarantees around the `setup.py` interface.
|
||||
```
|
||||
|
||||
## Build process
|
||||
|
||||
The overall process for building a package is:
|
||||
|
||||
- Generate the package's metadata.
|
||||
- Generate a wheel for the package.
|
||||
- If this fails and we're trying to install the package, attempt a direct
|
||||
installation.
|
||||
|
||||
The wheel can then be used to perform an installation, if necessary.
|
||||
|
||||
### Metadata Generation
|
||||
|
||||
As a first step, `pip` needs to get metadata about a package (name, version,
|
||||
dependencies, and more). It collects this by calling `setup.py egg_info`.
|
||||
|
||||
The `egg_info` command generates the metadata for the package, which pip can
|
||||
then consume and proceed to gather all the dependencies of the package. Once
|
||||
the dependency resolution process is complete, pip will proceed to the next
|
||||
stage of the build process for these packages.
|
||||
|
||||
### Wheel Generation
|
||||
|
||||
When provided with a {term}`pypug:source distribution (or "sdist")` for a
|
||||
package, pip will attempt to build a {term}`pypug:wheel`. Since wheel
|
||||
distributions can be [cached](wheel-caching), this can greatly speed up future
|
||||
installations for the package.
|
||||
|
||||
This is done by calling `setup.py bdist_wheel` which requires the {pypi}`wheel`
|
||||
package to be installed.
|
||||
|
||||
If this wheel generation is successful (this can include compiling C/C++ code,
|
||||
depending on the package), the generated wheel is added to pip's wheel cache
|
||||
and will be used for this installation. The built wheel is cached locally
|
||||
by pip to avoid repeated identical builds.
|
||||
|
||||
If this wheel generation fails, pip runs `setup.py clean` to clean up any build
|
||||
artifacts that may have been generated. After that, pip will attempt a direct
|
||||
installation.
|
||||
|
||||
### Direct Installation
|
||||
|
||||
When all else fails, pip will invoke `setup.py install` to install a package
|
||||
using setuptools' mechanisms to perform the installation. This is currently the
|
||||
last-resort fallback for projects that cannot be built into wheels, and may not
|
||||
be supported in the future.
|
||||
|
||||
### Editable Installation
|
||||
|
||||
For installing packages in "editable" mode
|
||||
({ref}`pip install --editable <install_--editable>`), pip will invoke
|
||||
`setup.py develop`, which will use setuptools' mechanisms to perform an
|
||||
editable/development installation.
|
||||
|
||||
## Setuptools Injection
|
||||
|
||||
To support projects that directly use `distutils`, pip injects `setuptools` into
|
||||
`sys.modules` before invoking `setup.py`. This injection should be transparent
|
||||
to `distutils`-based projects.
|
||||
|
||||
## Customising the build
|
||||
|
||||
The `--global-option` and `--build-option` arguments to the `pip install`
|
||||
and `pip wheel` inject additional arguments into the `setup.py` command
|
||||
(`--build-option` is only available in `pip wheel`).
|
||||
|
||||
```{attention}
|
||||
The use of `--global-option` and `--build-option` is highly setuptools
|
||||
specific, and is considered more an accident of the current implementation than
|
||||
a supported interface. It is documented here for completeness. These flags will
|
||||
not be supported, once this build system interface is dropped.
|
||||
```
|
||||
|
||||
These arguments are included in the command as follows:
|
||||
|
||||
```
|
||||
python setup.py <global_options> BUILD COMMAND <build_options>
|
||||
```
|
||||
|
||||
The options are passed unmodified, and presently offer direct access to the
|
||||
distutils command line. For example:
|
||||
|
||||
```{pip-cli}
|
||||
$ pip wheel --global-option bdist_ext --global-option -DFOO wheel
|
||||
```
|
||||
|
||||
will result in pip invoking:
|
||||
|
||||
```
|
||||
setup.py bdist_ext -DFOO bdist_wheel -d TARGET
|
||||
```
|
||||
|
||||
This passes a preprocessor symbol to the extension build.
|
||||
|
||||
(build-output)=
|
||||
|
||||
## Build Output
|
||||
|
||||
Any output produced by the build system will be read by pip (for display to the
|
||||
user if requested). In order to correctly read the build system output, pip
|
||||
requires that the output is written in a well-defined encoding, specifically
|
||||
the encoding the user has configured for text output (which can be obtained in
|
||||
Python using `locale.getpreferredencoding`). If the configured encoding is
|
||||
ASCII, pip assumes UTF-8 (to account for the behaviour of some Unix systems).
|
||||
|
||||
Build systems should ensure that any tools they invoke (compilers, etc) produce
|
||||
output in the correct encoding. In practice - and in particular on Windows,
|
||||
where tools are inconsistent in their use of the "OEM" and "ANSI" codepages -
|
||||
this may not always be possible. pip will therefore attempt to recover cleanly
|
||||
if presented with incorrectly encoded build tool output, by translating
|
||||
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).
|
|
@ -6,5 +6,7 @@ interoperability standards that pip utilises/implements.
|
|||
```{toctree}
|
||||
:titlesonly:
|
||||
|
||||
build-system/index
|
||||
requirement-specifiers
|
||||
requirements-file-format
|
||||
```
|
||||
|
|
61
docs/html/reference/requirement-specifiers.md
Normal file
61
docs/html/reference/requirement-specifiers.md
Normal file
|
@ -0,0 +1,61 @@
|
|||
(Requirement Specifiers)=
|
||||
|
||||
# Requirement Specifiers
|
||||
|
||||
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.
|
||||
|
||||
```{versionadded} 6.0
|
||||
Support for environment markers.
|
||||
```
|
||||
|
||||
```{versionadded} 19.1
|
||||
Support for the direct URL reference form.
|
||||
```
|
||||
|
||||
## Overview
|
||||
|
||||
A requirement specifier comes in two forms:
|
||||
|
||||
- name-based, which is composed of:
|
||||
|
||||
- a package name (eg: `requests`)
|
||||
- optionally, a set of "extras" that serve to install optional dependencies (eg: `security`)
|
||||
- optionally, constraints to apply on the version of the package
|
||||
- optionally, environment markers
|
||||
|
||||
- URL-based, which is composed of:
|
||||
|
||||
- a package name (eg: `requests`)
|
||||
- optionally, a set of "extras" that serve to install optional dependencies (eg: `security`)
|
||||
- a URL for the package
|
||||
- optionally, environment markers
|
||||
|
||||
## Examples
|
||||
|
||||
A few example name-based requirement specifiers:
|
||||
|
||||
```
|
||||
SomeProject
|
||||
SomeProject == 1.3
|
||||
SomeProject >= 1.2, < 2.0
|
||||
SomeProject[foo, bar]
|
||||
SomeProject ~= 1.4.2
|
||||
SomeProject == 5.4 ; python_version < '3.8'
|
||||
SomeProject ; sys_platform == 'win32'
|
||||
requests [security] >= 2.8.1, == 2.8.* ; python_version < "2.7"
|
||||
```
|
||||
|
||||
```{note}
|
||||
Use quotes around specifiers in the shell when using `>`, `<`, or when using environment markers.
|
||||
|
||||
Do _not_ use quotes in requirement files. There is only one exception: pip v7.0 and v7.0.1 (from May 2015) required quotes around specifiers containing environment markers in requirement files.
|
||||
```
|
||||
|
||||
A few example URL-based requirement specifiers:
|
||||
|
||||
```none
|
||||
pip @ https://github.com/pypa/pip/archive/22.0.2.zip
|
||||
requests [security] @ https://github.com/psf/requests/archive/refs/heads/main.zip ; python_version >= "3.11"
|
||||
```
|
|
@ -1,3 +1,5 @@
|
|||
(requirements-file-format)=
|
||||
|
||||
# Requirements File Format
|
||||
|
||||
Requirements files serve as a list of items to be installed by pip, when
|
||||
|
@ -13,13 +15,38 @@ consumption by pip, and other tools should take that into account before using
|
|||
it for their own purposes.
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
# This is a comment, to show how #-prefixed lines are ignored.
|
||||
# It is possible to specify requirements as plain names.
|
||||
pytest
|
||||
pytest-cov
|
||||
beautifulsoup4
|
||||
|
||||
# The syntax supported here is the same as that of requirement specifiers.
|
||||
docopt == 0.6.1
|
||||
requests [security] >= 2.8.1, == 2.8.* ; python_version < "2.7"
|
||||
urllib3 @ https://github.com/urllib3/urllib3/archive/refs/tags/1.26.8.zip
|
||||
|
||||
# It is possible to refer to other requirement files or constraints files.
|
||||
-r other-requirements.txt
|
||||
-c constraints.txt
|
||||
|
||||
# It is possible to refer to specific local distribution paths.
|
||||
./downloads/numpy-1.9.2-cp34-none-win32.whl
|
||||
|
||||
# It is possible to refer to URLs.
|
||||
http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl
|
||||
```
|
||||
|
||||
## Structure
|
||||
|
||||
Each line of the requirements file indicates something to be installed,
|
||||
or arguments to {ref}`pip install`. The following forms are supported:
|
||||
|
||||
- `[[--option]...]`
|
||||
- `<requirement specifier> [; markers] [[--option]...]`
|
||||
- `<requirement specifier>`
|
||||
- `<archive url/path>`
|
||||
- `[-e] <local project path>`
|
||||
- `[-e] <vcs project url>`
|
||||
|
@ -72,13 +99,21 @@ and two {ref}`--find-links <install_--find-links>` locations:
|
|||
```
|
||||
````
|
||||
|
||||
(per-requirement-options)=
|
||||
|
||||
### Per-requirement options
|
||||
|
||||
```{versionadded} 7.0
|
||||
|
||||
```
|
||||
|
||||
The options which can be applied to individual requirements are:
|
||||
|
||||
- {ref}`--install-option <install_--install-option>`
|
||||
- {ref}`--global-option <install_--global-option>`
|
||||
- `--hash` (for {ref}`Hash-Checking mode`)
|
||||
- `--hash` (for {ref}`Hash-checking mode`)
|
||||
|
||||
## Referring to other requirements files
|
||||
|
||||
If you wish, you can refer to other requirements files, like this:
|
||||
|
||||
|
@ -116,30 +151,34 @@ and only specify the variable name for your requirements, letting pip lookup
|
|||
the value at runtime. This approach aligns with the commonly used
|
||||
[12-factor configuration pattern](https://12factor.net/config).
|
||||
|
||||
## Example
|
||||
|
||||
## Influencing the build system
|
||||
|
||||
```{danger}
|
||||
This disables the use of wheels (cached or otherwise). This could mean that builds will be slower, less deterministic, less reliable and may not behave correctly upon installation.
|
||||
|
||||
This mechanism is only preserved for backwards compatibility and should be considered deprecated. A future release of pip may drop these options.
|
||||
```
|
||||
###### Requirements without Version Specifiers ######
|
||||
pytest
|
||||
pytest-cov
|
||||
beautifulsoup4
|
||||
|
||||
###### Requirements with Version Specifiers ######
|
||||
# See https://www.python.org/dev/peps/pep-0440/#version-specifiers
|
||||
docopt == 0.6.1 # Version Matching. Must be version 0.6.1
|
||||
keyring >= 4.1.1 # Minimum version 4.1.1
|
||||
coverage != 3.5 # Version Exclusion. Anything except version 3.5
|
||||
Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.*
|
||||
The `--global-option` and `--install-option` options are used to pass options to `setup.py`.
|
||||
|
||||
###### Refer to other requirements files ######
|
||||
-r other-requirements.txt
|
||||
```{attention}
|
||||
These options are highly coupled with how pip invokes setuptools using the {doc}`../reference/build-system/setup-py` build system interface. It is not compatible with newer {doc}`../reference/build-system/pyproject-toml` build system interface.
|
||||
|
||||
###### A particular file ######
|
||||
./downloads/numpy-1.9.2-cp34-none-win32.whl
|
||||
http://wxpython.org/Phoenix/snapshot-builds/wxPython_Phoenix-3.0.3.dev1820+49a8884-cp34-none-win_amd64.whl
|
||||
|
||||
###### Additional Requirements without Version Specifiers ######
|
||||
# Same as 1st section, just here to show that you can put things in any order.
|
||||
rejected
|
||||
green
|
||||
This is will not work with other build-backends or newer setup.cfg-only projects.
|
||||
```
|
||||
|
||||
If you have a declaration like:
|
||||
|
||||
FooProject >= 1.2 --global-option="--no-user-cfg" \
|
||||
--install-option="--prefix='/usr/local'" \
|
||||
--install-option="--no-compile"
|
||||
|
||||
The above translates roughly into running FooProject's `setup.py` script as:
|
||||
|
||||
python setup.py --no-user-cfg install --prefix='/usr/local' --no-compile
|
||||
|
||||
Note that the only way of giving more than one option to `setup.py` is through multiple `--global-option` and `--install-option` options, as shown in the example above. The value of each option is passed as a single argument to the `setup.py` script. Therefore, a line such as the following is invalid and would result in an installation error.
|
||||
|
||||
# Invalid. Please use '--install-option' twice as shown above.
|
||||
FooProject >= 1.2 --install-option="--prefix=/usr/local --no-compile"
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Caching
|
||||
|
||||
```{versionadded} 6.0
|
||||
|
||||
```
|
||||
|
||||
pip provides an on-by-default caching, designed to reduce the amount of time
|
||||
|
@ -26,6 +27,8 @@ While this cache attempts to minimize network activity, it does not prevent
|
|||
network access altogether. If you want a local install solution that
|
||||
circumvents accessing PyPI, see {ref}`Installing from local packages`.
|
||||
|
||||
(wheel-caching)=
|
||||
|
||||
### Locally built wheels
|
||||
|
||||
pip attempts to use wheels from its local wheel cache whenever possible.
|
||||
|
@ -38,6 +41,10 @@ wheel using the package's build system. If the build is successful, this wheel
|
|||
is added to the cache and used in subsequent installs for the same package
|
||||
version.
|
||||
|
||||
Wheels built from source distributions provided to pip as a direct path (such
|
||||
as `pip install .`) are not cached across runs, though they may be reused within
|
||||
the same `pip` execution.
|
||||
|
||||
```{versionchanged} 20.0
|
||||
pip now caches wheels when building from an immutable Git reference
|
||||
(i.e. a commit hash).
|
||||
|
@ -79,7 +86,7 @@ implementation detail and may change between any two versions of pip.
|
|||
|
||||
## Disabling caching
|
||||
|
||||
pip's caching behaviour is disabled by passing the ``--no-cache-dir`` option.
|
||||
pip's caching behaviour is disabled by passing the `--no-cache-dir` option.
|
||||
|
||||
It is, however, recommended to **NOT** disable pip's caching. Doing so can
|
||||
significantly slow down pip (due to repeated operations and package builds)
|
||||
|
|
|
@ -29,11 +29,10 @@ complexity for backwards compatibility reasons.
|
|||
```{tab} Unix
|
||||
|
||||
Global
|
||||
: {file}`/etc/pip.conf`
|
||||
: In a "pip" subdirectory of any of the paths set in the environment variable
|
||||
`XDG_CONFIG_DIRS` (if it exists), for example {file}`/etc/xdg/pip/pip.conf`.
|
||||
|
||||
Alternatively, it may be in a "pip" subdirectory of any of the paths set
|
||||
in the environment variable `XDG_CONFIG_DIRS` (if it exists), for
|
||||
example {file}`/etc/xdg/pip/pip.conf`.
|
||||
This will be followed by loading {file}`/etc/pip.conf`.
|
||||
|
||||
User
|
||||
: {file}`$HOME/.config/pip/pip.conf`, which respects the `XDG_CONFIG_HOME` environment variable.
|
||||
|
|
|
@ -156,7 +156,7 @@ how to inspect:
|
|||
|
||||
During deployment, you can create a lockfile stating the exact package and
|
||||
version number for for each dependency of that package. You can create this
|
||||
with `pip-tools <https://github.com/jazzband/pip-tools/>`\_\_.
|
||||
with [pip-tools](https://github.com/jazzband/pip-tools/).
|
||||
|
||||
This means the "work" is done once during development process, and thus
|
||||
will avoid performing dependency resolution during deployment.
|
||||
|
@ -277,10 +277,10 @@ your _dependency_ by:
|
|||
- Requesting that the package maintainers loosen _their_ dependencies
|
||||
- Forking the package and loosening the dependencies yourself
|
||||
|
||||
:::{warning}
|
||||
```{warning}
|
||||
If you choose to fork the package yourself, you are _opting out_ of
|
||||
any support provided by the package maintainers. Proceed at your own risk!
|
||||
:::
|
||||
```
|
||||
|
||||
#### All requirements are appropriate, but a solution does not exist
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ authentication
|
|||
caching
|
||||
configuration
|
||||
dependency-resolution
|
||||
local-project-installs
|
||||
repeatable-installs
|
||||
secure-installs
|
||||
vcs-support
|
||||
```
|
||||
|
|
65
docs/html/topics/local-project-installs.md
Normal file
65
docs/html/topics/local-project-installs.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Local project installs
|
||||
|
||||
It is extremely common to have a project, available in a folder/directory on your computer [^1] that you wish to install.
|
||||
|
||||
With pip, depending on your usecase, there are two ways to do this:
|
||||
|
||||
- A regular install
|
||||
- An editable install
|
||||
|
||||
## Regular installs
|
||||
|
||||
You can install local projects by specifying the project path to pip:
|
||||
|
||||
```{pip-cli}
|
||||
$ pip install path/to/SomeProject
|
||||
```
|
||||
|
||||
This will install the project into the Python that pip is associated with, in a manner similar to how it would actually be installed.
|
||||
|
||||
This is what should be used in CI system and for deployments, since it most closely mirrors how a package would get installed if you build a distribution and installed from it (because that's _exactly_ what it does).
|
||||
|
||||
(editable-installs)=
|
||||
|
||||
## Editable installs
|
||||
|
||||
You can install local projects in "editable" mode:
|
||||
|
||||
```{pip-cli}
|
||||
$ pip install -e path/to/SomeProject
|
||||
```
|
||||
|
||||
Editable installs allow you to install your project without copying any files. Instead, the files in the development directory are added to Python's import path. This approach is well suited for development and is also known as a "development installation".
|
||||
|
||||
With an editable install, you only need to perform a re-installation if you change the project metadata (eg: version, what scripts need to be generated etc). You will still need to run build commands when you need to perform a compilation for non-Python code in the project (eg: C extensions).
|
||||
|
||||
```{caution}
|
||||
It is possible to see behaviour differences between regular installs vs editable installs. In case you distribute the project as a "distribution package", users will see the behaviour of regular installs -- thus, it is important to ensure that regular installs work correctly.
|
||||
```
|
||||
|
||||
```{note}
|
||||
This is functionally the same as [setuptools' develop mode], and that's precisely the mechanism used for setuptools-based projects.
|
||||
|
||||
There are two advantages over using `setup.py develop` directly:
|
||||
|
||||
- This works with non-setuptools build-backends as well.
|
||||
- The ".egg-info" directory is created relative to the project path, when using pip. This is generally a better location than setuptools, which dumps it in the current working directory.
|
||||
```
|
||||
|
||||
[setuptools' develop mode]: https://setuptools.readthedocs.io/en/latest/userguide/development_mode.html
|
||||
|
||||
## Build artifacts
|
||||
|
||||
```{versionchanged} 21.3
|
||||
The project being installed is no longer copied to a temporary directory before invoking the build system.
|
||||
```
|
||||
|
||||
This behaviour change has several consequences:
|
||||
|
||||
- Local project builds will now be significantly faster, for certain kinds of projects and on systems with slow I/O (eg: via network attached storage or overly aggressive antivirus software).
|
||||
- Certain build backends (eg: `setuptools`) will litter the project directory with secondary build artifacts (eg: `.egg-info` directories).
|
||||
- Certain build backends (eg: `setuptools`) may not be able to perform with parallel builds anymore, since they previously relied on the fact that pip invoked them in a separate directory for each build.
|
||||
|
||||
A `--use-deprecated=out-of-tree-build` option is available, until pip 22.1, as a mechanism to aid users with transitioning to the newer model of in-tree-builds.
|
||||
|
||||
[^1]: Specifically, the current machine's filesystem.
|
|
@ -94,5 +94,5 @@ identical packages.
|
|||
Beware of the `setup_requires` keyword arg in {file}`setup.py`. The (rare)
|
||||
packages that use it will cause those dependencies to be downloaded by
|
||||
setuptools directly, skipping pip's protections. If you need to use such a
|
||||
package, see {ref}`Controlling setup_requires <controlling-setup-requires>`.
|
||||
package, see {ref}`Controlling setup_requires <controlling-setup_requires>`.
|
||||
```
|
||||
|
|
100
docs/html/topics/secure-installs.md
Normal file
100
docs/html/topics/secure-installs.md
Normal file
|
@ -0,0 +1,100 @@
|
|||
# Secure installs
|
||||
|
||||
By default, pip does not perform any checks to protect against remote tampering and involves running arbitrary code from distributions. It is, however, possible to use pip in a manner that changes these behaviours, to provide a more secure installation mechanism.
|
||||
|
||||
This can be achieved by doing the following:
|
||||
|
||||
- Enable {ref}`Hash-checking mode`, by passing {any}`--require-hashes`
|
||||
- Disallow source distributions, by passing {any}`--only-binary :all: <--only-binary>`
|
||||
|
||||
(Hash-checking mode)=
|
||||
|
||||
## Hash-checking Mode
|
||||
|
||||
```{versionadded} 8.0
|
||||
|
||||
```
|
||||
|
||||
This mode uses local hashes, embedded in a requirements.txt file, to protect against remote tampering and network issues. These hashes are specified using a `--hash` [per requirement option](per-requirement-options).
|
||||
|
||||
Note that hash-checking is an all-or-nothing proposition. Specifying `--hash` against _any_ requirement will activate this mode globally.
|
||||
|
||||
To add hashes for a package, add them to line as follows:
|
||||
|
||||
```
|
||||
FooProject == 1.2 \
|
||||
--hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 \
|
||||
--hash=sha256:486ea46224d1bb4fb680f34f7c9ad96a8f24ec88be73ea8e5a6c65260e9cb8a7
|
||||
```
|
||||
|
||||
### Additional restrictions
|
||||
|
||||
- Hashes are required for _all_ requirements.
|
||||
|
||||
This is because a partially-hashed requirements file is of little use and thus likely an error: a malicious actor could slip bad code into the installation via one of the unhashed requirements.
|
||||
|
||||
Note that hashes embedded in URL-style requirements via the `#md5=...` syntax suffice to satisfy this rule (regardless of hash strength, for legacy reasons), though you should use a stronger hash like sha256 whenever possible.
|
||||
|
||||
- Hashes are required for _all_ dependencies.
|
||||
|
||||
If there is a dependency that is not spelled out and hashed in the requirements file, it will result in an error.
|
||||
|
||||
- Requirements must be pinned (either to a URL, filesystem path or using `==`).
|
||||
|
||||
This prevents a surprising hash mismatch upon the release of a new version that matches the requirement specifier.
|
||||
|
||||
### Forcing Hash-checking mode
|
||||
|
||||
It is possible to force the hash checking mode to be enabled, by passing `--require-hashes` command-line option.
|
||||
|
||||
This can be useful in deploy scripts, to ensure that the author of the requirements file provided hashes. It is also a convenient way to bootstrap your list of hashes, since it shows the hashes of the packages it fetched. It fetches only the preferred archive for each package, so you may still need to add hashes for alternatives archives using {ref}`pip hash`: for instance if there is both a binary and a source distribution.
|
||||
|
||||
### Hash algorithms
|
||||
|
||||
The recommended hash algorithm at the moment is sha256, but stronger ones are allowed, including all those supported by `hashlib`. However, weaker ones such as md5, sha1, and sha224 are excluded to avoid giving a false sense of security.
|
||||
|
||||
### Multiple hashes per package
|
||||
|
||||
It is possible to use multiple hashes for each package. This is important when a package offers binary distributions for a variety of platforms or when it is important to allow both binary and source distributions.
|
||||
|
||||
### Interaction with caching
|
||||
|
||||
The {ref}`locally-built wheel cache <wheel-caching>` is disabled in hash-checking mode to prevent spurious hash mismatch errors.
|
||||
|
||||
These would otherwise occur while installing sdists that had already been automatically built into cached wheels: those wheels would be selected for installation, but their hashes would not match the sdist ones from the requirements file.
|
||||
|
||||
A further complication is that locally built wheels are nondeterministic: contemporary modification times make their way into the archive, making hashes unpredictable across machines and cache flushes. Compilation of C code adds further nondeterminism, as many compilers include random-seeded values in their output.
|
||||
|
||||
However, wheels fetched from index servers are required to be the same every time. They land in pip's HTTP cache, not its wheel cache, and are used normally in hash-checking mode. The only downside of having the wheel cache disabled is thus extra build time for sdists, and this can be solved by making sure pre-built wheels are available from the index server.
|
||||
|
||||
### Using hashes from PyPI (or other index servers)
|
||||
|
||||
PyPI (and certain other index servers) provides a hash for the distribution, in the fragment portion of each download URL, like `#sha256=123...`, which pip checks as a protection against download corruption.
|
||||
|
||||
Other hash algorithms that have guaranteed support from `hashlib` are also supported here: sha1, sha224, sha384, sha256, and sha512. Since this hash originates remotely, it is not a useful guard against tampering and thus does not satisfy the `--require-hashes` demand that every package have a local hash.
|
||||
|
||||
## Repeatable installs
|
||||
|
||||
Hash-checking mode also works with {ref}`pip download` and {ref}`pip wheel`. See {doc}`../topics/repeatable-installs` for a comparison of hash-checking mode with other repeatability strategies.
|
||||
|
||||
```{warning}
|
||||
Beware of the `setup_requires` keyword arg in {file}`setup.py`. The (rare) packages that use it will cause those dependencies to be downloaded by setuptools directly, skipping pip's hash-checking. If you need to use such a package, see {ref}`controlling setup_requires <controlling-setup_requires>`.
|
||||
```
|
||||
|
||||
## Do not use setuptools directly
|
||||
|
||||
Be careful not to nullify all your security work by installing your actual project by using setuptools' deprecated interfaces directly: for example, by calling `python setup.py install`, `python setup.py develop`, or `easy_install`.
|
||||
|
||||
These will happily go out and download, unchecked, anything you missed in your requirements file and it’s easy to miss things as your project evolves. To be safe, install your project using pip and {any}`--no-deps`.
|
||||
|
||||
Instead of `python setup.py install`, use:
|
||||
|
||||
```{pip-cli}
|
||||
$ pip install --no-deps .
|
||||
```
|
||||
|
||||
Instead of `python setup.py develop`, use:
|
||||
|
||||
```{pip-cli}
|
||||
$ pip install --no-deps -e .
|
||||
```
|
|
@ -17,9 +17,9 @@ The supported schemes are `git+file`, `git+https`, `git+ssh`, `git+http`,
|
|||
`git+git` and `git`. Here are some of the supported forms:
|
||||
|
||||
```none
|
||||
git+ssh://git.example.com/MyProject#egg=MyProject
|
||||
git+file:///home/user/projects/MyProject#egg=MyProject
|
||||
git+https://git.example.com/MyProject#egg=MyProject
|
||||
MyProject @ git+ssh://git.example.com/MyProject
|
||||
MyProject @ git+file:///home/user/projects/MyProject
|
||||
MyProject @ git+https://git.example.com/MyProject
|
||||
```
|
||||
|
||||
```{warning}
|
||||
|
@ -34,10 +34,10 @@ It is also possible to specify a "git ref" such as branch name, a commit hash or
|
|||
a tag name:
|
||||
|
||||
```none
|
||||
git+https://git.example.com/MyProject.git@master#egg=MyProject
|
||||
git+https://git.example.com/MyProject.git@v1.0#egg=MyProject
|
||||
git+https://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject
|
||||
git+https://git.example.com/MyProject.git@refs/pull/123/head#egg=MyProject
|
||||
MyProject @ git+https://git.example.com/MyProject.git@master
|
||||
MyProject @ git+https://git.example.com/MyProject.git@v1.0
|
||||
MyProject @ git+https://git.example.com/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709
|
||||
MyProject @ git+https://git.example.com/MyProject.git@refs/pull/123/head
|
||||
```
|
||||
|
||||
When passing a commit hash, specifying a full hash is preferable to a partial
|
||||
|
@ -50,20 +50,20 @@ The supported schemes are `hg+file`, `hg+http`, `hg+https`, `hg+ssh`
|
|||
and `hg+static-http`. Here are some of the supported forms:
|
||||
|
||||
```
|
||||
hg+http://hg.myproject.org/MyProject#egg=MyProject
|
||||
hg+https://hg.myproject.org/MyProject#egg=MyProject
|
||||
hg+ssh://hg.myproject.org/MyProject#egg=MyProject
|
||||
hg+file:///home/user/projects/MyProject#egg=MyProject
|
||||
MyProject @ hg+http://hg.myproject.org/MyProject
|
||||
MyProject @ hg+https://hg.myproject.org/MyProject
|
||||
MyProject @ hg+ssh://hg.myproject.org/MyProject
|
||||
MyProject @ hg+file:///home/user/projects/MyProject
|
||||
```
|
||||
|
||||
It is also possible to specify a revision number, a revision hash, a tag name
|
||||
or a local branch name:
|
||||
|
||||
```none
|
||||
hg+http://hg.example.com/MyProject@da39a3ee5e6b#egg=MyProject
|
||||
hg+http://hg.example.com/MyProject@2019#egg=MyProject
|
||||
hg+http://hg.example.com/MyProject@v1.0#egg=MyProject
|
||||
hg+http://hg.example.com/MyProject@special_feature#egg=MyProject
|
||||
MyProject @ hg+http://hg.example.com/MyProject@da39a3ee5e6b
|
||||
MyProject @ hg+http://hg.example.com/MyProject@2019
|
||||
MyProject @ hg+http://hg.example.com/MyProject@v1.0
|
||||
MyProject @ hg+http://hg.example.com/MyProject@special_feature
|
||||
```
|
||||
|
||||
### Subversion
|
||||
|
@ -72,16 +72,16 @@ The supported schemes are `svn`, `svn+svn`, `svn+http`, `svn+https` and
|
|||
`svn+ssh`. Here are some of the supported forms:
|
||||
|
||||
```none
|
||||
svn+https://svn.example.com/MyProject#egg=MyProject
|
||||
svn+ssh://svn.example.com/MyProject#egg=MyProject
|
||||
svn+ssh://user@svn.example.com/MyProject#egg=MyProject
|
||||
MyProject @svn+https://svn.example.com/MyProject
|
||||
MyProject @svn+ssh://svn.example.com/MyProject
|
||||
MyProject @svn+ssh://user@svn.example.com/MyProject
|
||||
```
|
||||
|
||||
You can also give specific revisions to an SVN URL, like so:
|
||||
|
||||
```none
|
||||
-e svn+http://svn.example.com/svn/MyProject/trunk@2019#egg=MyProject
|
||||
-e svn+http://svn.example.com/svn/MyProject/trunk@{20080101}#egg=MyProject
|
||||
MyProject @ -e svn+http://svn.example.com/svn/MyProject/trunk@2019
|
||||
MyProject @ -e svn+http://svn.example.com/svn/MyProject/trunk@{20080101}
|
||||
```
|
||||
|
||||
Note that you need to use [Editable VCS installs](#editable-vcs-installs) for
|
||||
|
@ -93,18 +93,18 @@ The supported schemes are `bzr+http`, `bzr+https`, `bzr+ssh`, `bzr+sftp`,
|
|||
`bzr+ftp` and `bzr+lp`. Here are the supported forms:
|
||||
|
||||
```none
|
||||
bzr+http://bzr.example.com/MyProject/trunk#egg=MyProject
|
||||
bzr+sftp://user@example.com/MyProject/trunk#egg=MyProject
|
||||
bzr+ssh://user@example.com/MyProject/trunk#egg=MyProject
|
||||
bzr+ftp://user@example.com/MyProject/trunk#egg=MyProject
|
||||
bzr+lp:MyProject#egg=MyProject
|
||||
MyProject @ bzr+http://bzr.example.com/MyProject/trunk
|
||||
MyProject @ bzr+sftp://user@example.com/MyProject/trunk
|
||||
MyProject @ bzr+ssh://user@example.com/MyProject/trunk
|
||||
MyProject @ bzr+ftp://user@example.com/MyProject/trunk
|
||||
MyProject @ bzr+lp:MyProject
|
||||
```
|
||||
|
||||
Tags or revisions can be installed like so:
|
||||
|
||||
```none
|
||||
bzr+https://bzr.example.com/MyProject/trunk@2019#egg=MyProject
|
||||
bzr+http://bzr.example.com/MyProject/trunk@v1.0#egg=MyProject
|
||||
MyProject @ bzr+https://bzr.example.com/MyProject/trunk@2019
|
||||
MyProject @ bzr+http://bzr.example.com/MyProject/trunk@v1.0
|
||||
```
|
||||
|
||||
(editable-vcs-installs)=
|
||||
|
|
|
@ -113,7 +113,7 @@ installed using :ref:`pip install` like so:
|
|||
|
||||
py -m pip install -r requirements.txt
|
||||
|
||||
Details on the format of the files are here: :ref:`Requirements File Format`.
|
||||
Details on the format of the files are here: :ref:`requirements-file-format`.
|
||||
|
||||
Logically, a Requirements file is just a list of :ref:`pip install` arguments
|
||||
placed in a file. Note that you should not rely on the items in the file being
|
||||
|
@ -185,7 +185,7 @@ not by discovering ``requirements.txt`` files embedded in projects.
|
|||
|
||||
See also:
|
||||
|
||||
* :ref:`Requirements File Format`
|
||||
* :ref:`requirements-file-format`
|
||||
* :ref:`pip freeze`
|
||||
* `"setup.py vs requirements.txt" (an article by Donald Stufft)
|
||||
<https://caremad.io/2013/07/setup-vs-requirement/>`_
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
sphinx ~= 4.1.0
|
||||
sphinx ~= 4.2, != 4.4.0
|
||||
towncrier
|
||||
furo
|
||||
myst_parser
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Improve deprecation warning regarding the copying of source trees when installing from a local directory.
|
|
@ -1,4 +0,0 @@
|
|||
Add a ``feature_flag`` optional kwarg to the ``deprecated()`` function
|
||||
``pip._internal.utils.deprecation:deprecated``. Also formulate a corresponding canned
|
||||
message which suggests using the ``--use-feature={feature_flag}`` to test upcoming
|
||||
behavior.
|
|
@ -1,4 +0,0 @@
|
|||
On Python 3.10 or later, the installation scheme backend has been changed to use
|
||||
``sysconfig``. This is to anticipate the deprecation of ``distutils`` in Python
|
||||
3.10, and its scheduled removal in 3.12. For compatibility considerations, pip
|
||||
installations running on Python 3.9 or lower will continue to use ``distutils``.
|
|
@ -1 +0,0 @@
|
|||
Fix double unescape of HTML ``data-requires-python`` and ``data-yanked`` attributes.
|
|
@ -1 +0,0 @@
|
|||
Update links of setuptools as setuptools moved these documents. The Simple Repository link now points to PyPUG as that is the canonical place of packaging specification, and setuptools's ``easy_install`` is deprecated.
|
1
news/10696.bugfix.rst
Normal file
1
news/10696.bugfix.rst
Normal file
|
@ -0,0 +1 @@
|
|||
Fix uninstall editable from Windows junction link.
|
2
news/10812.feature.rst
Normal file
2
news/10812.feature.rst
Normal file
|
@ -0,0 +1,2 @@
|
|||
Improve error message when ``pip config edit`` is provided an editor that
|
||||
doesn't exist.
|
1
news/10899.doc.rst
Normal file
1
news/10899.doc.rst
Normal file
|
@ -0,0 +1 @@
|
|||
Add more dedicated topic and reference pages to the documentation.
|
|
@ -1 +0,0 @@
|
|||
When a revision is specified in a Git URL, use git's partial clone feature to speed up source retrieval.
|
1
news/9794.feature.rst
Normal file
1
news/9794.feature.rst
Normal file
|
@ -0,0 +1 @@
|
|||
Validate build dependencies when using ``--no-build-isolation``.
|
|
@ -1 +0,0 @@
|
|||
Upgrade distro to 1.6.0.
|
33
noxfile.py
33
noxfile.py
|
@ -65,11 +65,8 @@ def should_update_common_wheels() -> bool:
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Development Commands
|
||||
# These are currently prototypes to evaluate whether we want to switch over
|
||||
# completely to nox for all our automation. Contributors should prefer using
|
||||
# `tox -e ...` until this note is removed.
|
||||
# -----------------------------------------------------------------------------
|
||||
@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "pypy3"])
|
||||
@nox.session(python=["3.7", "3.8", "3.9", "3.10", "pypy3"])
|
||||
def test(session: nox.Session) -> None:
|
||||
# Get the common wheels.
|
||||
if should_update_common_wheels():
|
||||
|
@ -113,7 +110,14 @@ def test(session: nox.Session) -> None:
|
|||
# Run the tests
|
||||
# LC_CTYPE is set to get UTF-8 output inside of the subprocesses that our
|
||||
# tests use.
|
||||
session.run("pytest", *arguments, env={"LC_CTYPE": "en_US.UTF-8"})
|
||||
session.run(
|
||||
"pytest",
|
||||
*arguments,
|
||||
env={
|
||||
"LC_CTYPE": "en_US.UTF-8",
|
||||
"SETUPTOOLS_USE_DISTUTILS": "stdlib",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@nox.session
|
||||
|
@ -171,10 +175,10 @@ def lint(session: nox.Session) -> None:
|
|||
|
||||
@nox.session
|
||||
def vendoring(session: nox.Session) -> None:
|
||||
session.install("vendoring~=1.0.0")
|
||||
session.install("vendoring~=1.2.0")
|
||||
|
||||
if "--upgrade" not in session.posargs:
|
||||
session.run("vendoring", "sync", ".", "-v")
|
||||
session.run("vendoring", "sync", "-v")
|
||||
return
|
||||
|
||||
def pinned_requirements(path: Path) -> Iterator[Tuple[str, str]]:
|
||||
|
@ -223,6 +227,21 @@ def vendoring(session: nox.Session) -> None:
|
|||
release.commit_file(session, ".", message=message)
|
||||
|
||||
|
||||
@nox.session
|
||||
def coverage(session: nox.Session) -> None:
|
||||
if not os.path.exists("./.coverage-output"):
|
||||
os.mkdir("./.coverage-output")
|
||||
session.run(
|
||||
"pytest",
|
||||
"--cov=pip",
|
||||
"--cov-config=./setup.cfg",
|
||||
env={
|
||||
"COVERAGE_OUTPUT_DIR": "./.coverage-output",
|
||||
"COVERAGE_PROCESS_START": "./setup.cfg",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Release Commands
|
||||
# -----------------------------------------------------------------------------
|
||||
|
|
|
@ -3,13 +3,19 @@ requires = ["setuptools", "wheel"]
|
|||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[tool.towncrier]
|
||||
# For finding the __version__
|
||||
package = "pip"
|
||||
package_dir = "src"
|
||||
# For writing into the correct file
|
||||
filename = "NEWS.rst"
|
||||
# For finding the news fragments
|
||||
directory = "news/"
|
||||
title_format = "{version} ({project_date})"
|
||||
|
||||
# For rendering properly for this project
|
||||
issue_format = "`#{issue} <https://github.com/pypa/pip/issues/{issue}>`_"
|
||||
template = "tools/news/template.rst"
|
||||
|
||||
# Grouping of entries, within our changelog
|
||||
type = [
|
||||
{ name = "Process", directory = "process", showcontent = true },
|
||||
{ name = "Deprecations and Removals", directory = "removal", showcontent = true },
|
||||
|
@ -33,6 +39,7 @@ substitute = [
|
|||
# pkg_resource's vendored packages are directly vendored in pip.
|
||||
{ match='pkg_resources\.extern', replace="pip._vendor" },
|
||||
{ match='from \.extern', replace="from pip._vendor" },
|
||||
{ match='''\('pygments\.lexers\.''', replace="('pip._vendor.pygments.lexers." },
|
||||
]
|
||||
drop = [
|
||||
# contains unnecessary scripts
|
||||
|
@ -44,15 +51,21 @@ drop = [
|
|||
"setuptools",
|
||||
"pkg_resources/_vendor/",
|
||||
"pkg_resources/extern/",
|
||||
# trim vendored pygments styles and lexers
|
||||
"pygments/styles/[!_]*.py",
|
||||
'^pygments/lexers/(?!python|__init__|_mapping).*\.py$',
|
||||
# trim rich's markdown support
|
||||
"rich/markdown.py",
|
||||
]
|
||||
|
||||
[tool.vendoring.typing-stubs]
|
||||
six = ["six.__init__", "six.moves.__init__", "six.moves.configparser"]
|
||||
appdirs = []
|
||||
distro = []
|
||||
|
||||
[tool.vendoring.license.directories]
|
||||
setuptools = "pkg_resources"
|
||||
|
||||
[tool.vendoring.license.fallback-urls]
|
||||
CacheControl = "https://raw.githubusercontent.com/ionrock/cachecontrol/v0.12.6/LICENSE.txt"
|
||||
distlib = "https://bitbucket.org/pypa/distlib/raw/master/LICENSE.txt"
|
||||
webencodings = "https://github.com/SimonSapin/python-webencodings/raw/master/LICENSE"
|
||||
|
|
|
@ -51,12 +51,9 @@ follow_imports = skip
|
|||
[mypy-pip._vendor.requests.*]
|
||||
follow_imports = skip
|
||||
|
||||
[mypy-tests.*]
|
||||
# TODO: The following option should be removed at some point in the future.
|
||||
allow_untyped_defs = True
|
||||
|
||||
[tool:pytest]
|
||||
addopts = --ignore src/pip/_vendor --ignore tests/tests_cache -r aR --color=yes
|
||||
xfail_strict = True
|
||||
markers =
|
||||
network: tests that need network
|
||||
incompatible_with_sysconfig
|
||||
|
@ -106,8 +103,6 @@ exclude_lines =
|
|||
pragma: no cover
|
||||
# This excludes typing-specific code, which will be validated by mypy anyway.
|
||||
if TYPE_CHECKING
|
||||
# Can be set to exclude e.g. `if PY2:` on Python 3
|
||||
${PIP_CI_COVERAGE_EXCLUDES}
|
||||
|
||||
[metadata]
|
||||
license_file = LICENSE.txt
|
||||
|
|
12
setup.py
12
setup.py
|
@ -37,7 +37,6 @@ setup(
|
|||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.6",
|
||||
"Programming Language :: Python :: 3.7",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
|
@ -64,7 +63,14 @@ setup(
|
|||
"pip._vendor.certifi": ["*.pem"],
|
||||
"pip._vendor.requests": ["*.pem"],
|
||||
"pip._vendor.distlib._backport": ["sysconfig.cfg"],
|
||||
"pip._vendor.distlib": ["t32.exe", "t64.exe", "w32.exe", "w64.exe"],
|
||||
"pip._vendor.distlib": [
|
||||
"t32.exe",
|
||||
"t64.exe",
|
||||
"t64-arm.exe",
|
||||
"w32.exe",
|
||||
"w64.exe",
|
||||
"w64-arm.exe",
|
||||
],
|
||||
},
|
||||
entry_points={
|
||||
"console_scripts": [
|
||||
|
@ -74,5 +80,5 @@ setup(
|
|||
],
|
||||
},
|
||||
zip_safe=False,
|
||||
python_requires=">=3.6",
|
||||
python_requires=">=3.7",
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from typing import List, Optional
|
||||
|
||||
__version__ = "21.3.dev0"
|
||||
__version__ = "22.1.dev0"
|
||||
|
||||
|
||||
def main(args: Optional[List[str]] = None) -> int:
|
||||
|
|
|
@ -20,7 +20,7 @@ from pip._vendor.packaging.version import Version
|
|||
from pip import __file__ as pip_location
|
||||
from pip._internal.cli.spinners import open_spinner
|
||||
from pip._internal.locations import get_platlib, get_prefixed_libs, get_purelib
|
||||
from pip._internal.metadata import get_environment
|
||||
from pip._internal.metadata import get_default_environment, get_environment
|
||||
from pip._internal.utils.subprocess import call_subprocess
|
||||
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
|
||||
|
||||
|
@ -93,7 +93,9 @@ class BuildEnvironment:
|
|||
self._site_dir = os.path.join(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:
|
||||
with open(
|
||||
os.path.join(self._site_dir, "sitecustomize.py"), "w", encoding="utf-8"
|
||||
) as fp:
|
||||
fp.write(
|
||||
textwrap.dedent(
|
||||
"""
|
||||
|
@ -166,7 +168,11 @@ class BuildEnvironment:
|
|||
missing = set()
|
||||
conflicting = set()
|
||||
if reqs:
|
||||
env = get_environment(self._lib_dirs)
|
||||
env = (
|
||||
get_environment(self._lib_dirs)
|
||||
if hasattr(self, "_lib_dirs")
|
||||
else get_default_environment()
|
||||
)
|
||||
for req_str in reqs:
|
||||
req = Requirement(req_str)
|
||||
dist = env.get_distribution(req.name)
|
||||
|
@ -187,7 +193,8 @@ class BuildEnvironment:
|
|||
finder: "PackageFinder",
|
||||
requirements: Iterable[str],
|
||||
prefix_as_string: str,
|
||||
message: str,
|
||||
*,
|
||||
kind: str,
|
||||
) -> None:
|
||||
prefix = self._prefixes[prefix_as_string]
|
||||
assert not prefix.setup
|
||||
|
@ -195,20 +202,13 @@ class BuildEnvironment:
|
|||
if not requirements:
|
||||
return
|
||||
with contextlib.ExitStack() as ctx:
|
||||
# TODO: Remove this block when dropping 3.6 support. Python 3.6
|
||||
# lacks importlib.resources and pep517 has issues loading files in
|
||||
# a zip, so we fallback to the "old" method by adding the current
|
||||
# pip directory to the child process's sys.path.
|
||||
if sys.version_info < (3, 7):
|
||||
pip_runnable = os.path.dirname(pip_location)
|
||||
else:
|
||||
pip_runnable = ctx.enter_context(_create_standalone_pip())
|
||||
pip_runnable = ctx.enter_context(_create_standalone_pip())
|
||||
self._install_requirements(
|
||||
pip_runnable,
|
||||
finder,
|
||||
requirements,
|
||||
prefix,
|
||||
message,
|
||||
kind=kind,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
@ -217,7 +217,8 @@ class BuildEnvironment:
|
|||
finder: "PackageFinder",
|
||||
requirements: Iterable[str],
|
||||
prefix: _Prefix,
|
||||
message: str,
|
||||
*,
|
||||
kind: str,
|
||||
) -> None:
|
||||
args: List[str] = [
|
||||
sys.executable,
|
||||
|
@ -259,8 +260,13 @@ class BuildEnvironment:
|
|||
args.append("--")
|
||||
args.extend(requirements)
|
||||
extra_environ = {"_PIP_STANDALONE_CERT": where()}
|
||||
with open_spinner(message) as spinner:
|
||||
call_subprocess(args, spinner=spinner, extra_environ=extra_environ)
|
||||
with open_spinner(f"Installing {kind}") as spinner:
|
||||
call_subprocess(
|
||||
args,
|
||||
command_desc=f"pip subprocess to install {kind}",
|
||||
spinner=spinner,
|
||||
extra_environ=extra_environ,
|
||||
)
|
||||
|
||||
|
||||
class NoOpBuildEnvironment(BuildEnvironment):
|
||||
|
@ -288,6 +294,7 @@ class NoOpBuildEnvironment(BuildEnvironment):
|
|||
finder: "PackageFinder",
|
||||
requirements: Iterable[str],
|
||||
prefix_as_string: str,
|
||||
message: str,
|
||||
*,
|
||||
kind: str,
|
||||
) -> None:
|
||||
raise NotImplementedError()
|
||||
|
|
|
@ -59,6 +59,14 @@ def autocomplete() -> None:
|
|||
print(dist)
|
||||
sys.exit(1)
|
||||
|
||||
should_list_installables = (
|
||||
not current.startswith("-") and subcommand_name == "install"
|
||||
)
|
||||
if should_list_installables:
|
||||
for path in auto_complete_paths(current, "path"):
|
||||
print(path)
|
||||
sys.exit(1)
|
||||
|
||||
subcommand = create_command(subcommand_name)
|
||||
|
||||
for opt in subcommand.parser.option_list_all:
|
||||
|
@ -138,7 +146,7 @@ def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]:
|
|||
starting with ``current``.
|
||||
|
||||
:param current: The word to be completed
|
||||
:param completion_type: path completion type(`file`, `path` or `dir`)i
|
||||
:param completion_type: path completion type(``file``, ``path`` or ``dir``)
|
||||
:return: A generator of regular files and/or directories
|
||||
"""
|
||||
directory, filename = os.path.split(current)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
"""Base Command class, and related routines"""
|
||||
|
||||
import functools
|
||||
import logging
|
||||
import logging.config
|
||||
import optparse
|
||||
|
@ -7,7 +8,9 @@ import os
|
|||
import sys
|
||||
import traceback
|
||||
from optparse import Values
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import Any, Callable, List, Optional, Tuple
|
||||
|
||||
from pip._vendor.rich import traceback as rich_traceback
|
||||
|
||||
from pip._internal.cli import cmdoptions
|
||||
from pip._internal.cli.command_context import CommandContextMixIn
|
||||
|
@ -21,12 +24,12 @@ from pip._internal.cli.status_codes import (
|
|||
from pip._internal.exceptions import (
|
||||
BadCommand,
|
||||
CommandError,
|
||||
DiagnosticPipError,
|
||||
InstallationError,
|
||||
NetworkConnectionError,
|
||||
PreviousBuildDirError,
|
||||
UninstallationError,
|
||||
)
|
||||
from pip._internal.utils.deprecation import deprecated
|
||||
from pip._internal.utils.filesystem import check_path_owner
|
||||
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
|
||||
from pip._internal.utils.misc import get_prog, normalize_path
|
||||
|
@ -148,20 +151,6 @@ class Command(CommandContextMixIn):
|
|||
)
|
||||
options.cache_dir = None
|
||||
|
||||
if getattr(options, "build_dir", None):
|
||||
deprecated(
|
||||
reason=(
|
||||
"The -b/--build/--build-dir/--build-directory "
|
||||
"option is deprecated and has no effect anymore."
|
||||
),
|
||||
replacement=(
|
||||
"use the TMPDIR/TEMP/TMP environment variable, "
|
||||
"possibly combined with --no-clean"
|
||||
),
|
||||
gone_in="21.3",
|
||||
issue=8333,
|
||||
)
|
||||
|
||||
if "2020-resolver" in options.features_enabled:
|
||||
logger.warning(
|
||||
"--use-feature=2020-resolver no longer has any effect, "
|
||||
|
@ -169,46 +158,66 @@ class Command(CommandContextMixIn):
|
|||
"This will become an error in pip 21.0."
|
||||
)
|
||||
|
||||
def intercepts_unhandled_exc(
|
||||
run_func: Callable[..., int]
|
||||
) -> Callable[..., int]:
|
||||
@functools.wraps(run_func)
|
||||
def exc_logging_wrapper(*args: Any) -> int:
|
||||
try:
|
||||
status = run_func(*args)
|
||||
assert isinstance(status, int)
|
||||
return status
|
||||
except DiagnosticPipError as exc:
|
||||
logger.error("[present-diagnostic] %s", exc)
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except PreviousBuildDirError as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return PREVIOUS_BUILD_DIR_ERROR
|
||||
except (
|
||||
InstallationError,
|
||||
UninstallationError,
|
||||
BadCommand,
|
||||
NetworkConnectionError,
|
||||
) as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except CommandError as 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")
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except BaseException:
|
||||
logger.critical("Exception:", exc_info=True)
|
||||
|
||||
return UNKNOWN_ERROR
|
||||
|
||||
return exc_logging_wrapper
|
||||
|
||||
try:
|
||||
status = self.run(options, args)
|
||||
assert isinstance(status, int)
|
||||
return status
|
||||
except PreviousBuildDirError as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return PREVIOUS_BUILD_DIR_ERROR
|
||||
except (
|
||||
InstallationError,
|
||||
UninstallationError,
|
||||
BadCommand,
|
||||
NetworkConnectionError,
|
||||
) as exc:
|
||||
logger.critical(str(exc))
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except CommandError as 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")
|
||||
logger.debug("Exception information:", exc_info=True)
|
||||
|
||||
return ERROR
|
||||
except BaseException:
|
||||
logger.critical("Exception:", exc_info=True)
|
||||
|
||||
return UNKNOWN_ERROR
|
||||
if not options.debug_mode:
|
||||
run = intercepts_unhandled_exc(self.run)
|
||||
else:
|
||||
run = self.run
|
||||
rich_traceback.install(show_locals=True)
|
||||
return run(options, args)
|
||||
finally:
|
||||
self.handle_pip_version_check(options)
|
||||
|
|
|
@ -10,9 +10,9 @@ pass on state. To be consistent, all options will follow this design.
|
|||
# The following comment should be removed at some point in the future.
|
||||
# mypy: strict-optional=False
|
||||
|
||||
import logging
|
||||
import os
|
||||
import textwrap
|
||||
import warnings
|
||||
from functools import partial
|
||||
from optparse import SUPPRESS_HELP, Option, OptionGroup, OptionParser, Values
|
||||
from textwrap import dedent
|
||||
|
@ -30,6 +30,8 @@ from pip._internal.models.target_python import TargetPython
|
|||
from pip._internal.utils.hashes import STRONG_HASHES
|
||||
from pip._internal.utils.misc import strtobool
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def raise_option_error(parser: OptionParser, option: Option, msg: str) -> None:
|
||||
"""
|
||||
|
@ -76,10 +78,9 @@ def check_install_build_global(
|
|||
if any(map(getname, names)):
|
||||
control = options.format_control
|
||||
control.disallow_binaries()
|
||||
warnings.warn(
|
||||
logger.warning(
|
||||
"Disabling all use of wheels due to the use of --build-option "
|
||||
"/ --global-option / --install-option.",
|
||||
stacklevel=2,
|
||||
)
|
||||
|
||||
|
||||
|
@ -151,6 +152,18 @@ help_: Callable[..., Option] = partial(
|
|||
help="Show help.",
|
||||
)
|
||||
|
||||
debug_mode: Callable[..., Option] = partial(
|
||||
Option,
|
||||
"--debug",
|
||||
dest="debug_mode",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=(
|
||||
"Let unhandled exceptions propagate outside the main subroutine, "
|
||||
"instead of logging them to stderr."
|
||||
),
|
||||
)
|
||||
|
||||
isolated_mode: Callable[..., Option] = partial(
|
||||
Option,
|
||||
"--isolated",
|
||||
|
@ -165,13 +178,15 @@ isolated_mode: Callable[..., Option] = partial(
|
|||
|
||||
require_virtualenv: Callable[..., Option] = partial(
|
||||
Option,
|
||||
# Run only if inside a virtualenv, bail if not.
|
||||
"--require-virtualenv",
|
||||
"--require-venv",
|
||||
dest="require_venv",
|
||||
action="store_true",
|
||||
default=False,
|
||||
help=SUPPRESS_HELP,
|
||||
help=(
|
||||
"Allow pip to only run in a virtual environment; "
|
||||
"exit with an error otherwise."
|
||||
),
|
||||
)
|
||||
|
||||
verbose: Callable[..., Option] = partial(
|
||||
|
@ -719,18 +734,6 @@ no_deps: Callable[..., Option] = partial(
|
|||
help="Don't install package dependencies.",
|
||||
)
|
||||
|
||||
build_dir: Callable[..., Option] = partial(
|
||||
PipOption,
|
||||
"-b",
|
||||
"--build",
|
||||
"--build-dir",
|
||||
"--build-directory",
|
||||
dest="build_dir",
|
||||
type="path",
|
||||
metavar="dir",
|
||||
help=SUPPRESS_HELP,
|
||||
)
|
||||
|
||||
ignore_requires_python: Callable[..., Option] = partial(
|
||||
Option,
|
||||
"--ignore-requires-python",
|
||||
|
@ -961,7 +964,12 @@ use_deprecated_feature: Callable[..., Option] = partial(
|
|||
metavar="feature",
|
||||
action="append",
|
||||
default=[],
|
||||
choices=["legacy-resolver"],
|
||||
choices=[
|
||||
"legacy-resolver",
|
||||
"out-of-tree-build",
|
||||
"backtrack-on-build-failures",
|
||||
"html5lib",
|
||||
],
|
||||
help=("Enable deprecated functionality, that will be removed in the future."),
|
||||
)
|
||||
|
||||
|
@ -974,6 +982,7 @@ general_group: Dict[str, Any] = {
|
|||
"name": "General Options",
|
||||
"options": [
|
||||
help_,
|
||||
debug_mode,
|
||||
isolated_mode,
|
||||
require_virtualenv,
|
||||
verbose,
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
import functools
|
||||
import itertools
|
||||
import sys
|
||||
from signal import SIGINT, default_int_handler, signal
|
||||
from typing import Any
|
||||
from typing import Any, Callable, Iterator, Optional, Tuple
|
||||
|
||||
from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar
|
||||
from pip._vendor.progress.spinner import Spinner
|
||||
from pip._vendor.rich.progress import (
|
||||
BarColumn,
|
||||
DownloadColumn,
|
||||
FileSizeColumn,
|
||||
Progress,
|
||||
ProgressColumn,
|
||||
SpinnerColumn,
|
||||
TextColumn,
|
||||
TimeElapsedColumn,
|
||||
TimeRemainingColumn,
|
||||
TransferSpeedColumn,
|
||||
)
|
||||
|
||||
from pip._internal.utils.compat import WINDOWS
|
||||
from pip._internal.utils.logging import get_indentation
|
||||
|
@ -17,6 +30,8 @@ try:
|
|||
except Exception:
|
||||
colorama = None
|
||||
|
||||
DownloadProgressRenderer = Callable[[Iterator[bytes]], Iterator[bytes]]
|
||||
|
||||
|
||||
def _select_progress_class(preferred: Bar, fallback: Bar) -> Bar:
|
||||
encoding = getattr(preferred.file, "encoding", None)
|
||||
|
@ -243,8 +258,64 @@ BAR_TYPES = {
|
|||
}
|
||||
|
||||
|
||||
def DownloadProgressProvider(progress_bar, max=None): # type: ignore
|
||||
def _legacy_progress_bar(
|
||||
progress_bar: str, max: Optional[int]
|
||||
) -> DownloadProgressRenderer:
|
||||
if max is None or max == 0:
|
||||
return BAR_TYPES[progress_bar][1]().iter
|
||||
return BAR_TYPES[progress_bar][1]().iter # type: ignore
|
||||
else:
|
||||
return BAR_TYPES[progress_bar][0](max=max).iter
|
||||
|
||||
|
||||
#
|
||||
# Modern replacement, for our legacy progress bars.
|
||||
#
|
||||
def _rich_progress_bar(
|
||||
iterable: Iterator[bytes],
|
||||
*,
|
||||
bar_type: str,
|
||||
size: int,
|
||||
) -> Iterator[bytes]:
|
||||
assert bar_type == "on", "This should only be used in the default mode."
|
||||
|
||||
if not size:
|
||||
total = float("inf")
|
||||
columns: Tuple[ProgressColumn, ...] = (
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
SpinnerColumn("line", speed=1.5),
|
||||
FileSizeColumn(),
|
||||
TransferSpeedColumn(),
|
||||
TimeElapsedColumn(),
|
||||
)
|
||||
else:
|
||||
total = size
|
||||
columns = (
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
BarColumn(),
|
||||
DownloadColumn(),
|
||||
TransferSpeedColumn(),
|
||||
TextColumn("eta"),
|
||||
TimeRemainingColumn(),
|
||||
)
|
||||
|
||||
progress = Progress(*columns, refresh_per_second=30)
|
||||
task_id = progress.add_task(" " * (get_indentation() + 2), total=total)
|
||||
with progress:
|
||||
for chunk in iterable:
|
||||
yield chunk
|
||||
progress.update(task_id, advance=len(chunk))
|
||||
|
||||
|
||||
def get_download_progress_renderer(
|
||||
*, bar_type: str, size: Optional[int] = None
|
||||
) -> DownloadProgressRenderer:
|
||||
"""Get an object that can be used to render the download progress.
|
||||
|
||||
Returns a callable, that takes an iterable to "wrap".
|
||||
"""
|
||||
if bar_type == "on":
|
||||
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
|
||||
elif bar_type == "off":
|
||||
return iter # no-op, when passed an iterator
|
||||
else:
|
||||
return _legacy_progress_bar(bar_type, size)
|
||||
|
|
|
@ -34,6 +34,7 @@ from pip._internal.req.req_install import InstallRequirement
|
|||
from pip._internal.req.req_tracker import RequirementTracker
|
||||
from pip._internal.resolution.base import BaseResolver
|
||||
from pip._internal.self_outdated_check import pip_self_version_check
|
||||
from pip._internal.utils.deprecation import deprecated
|
||||
from pip._internal.utils.temp_dir import (
|
||||
TempDirectory,
|
||||
TempDirectoryTypeRegistry,
|
||||
|
@ -172,9 +173,10 @@ def warn_if_run_as_root() -> None:
|
|||
# checks: https://mypy.readthedocs.io/en/stable/common_issues.html
|
||||
if sys.platform == "win32" or sys.platform == "cygwin":
|
||||
return
|
||||
if sys.platform == "darwin" or sys.platform == "linux":
|
||||
if os.getuid() != 0:
|
||||
return
|
||||
|
||||
if os.getuid() != 0:
|
||||
return
|
||||
|
||||
logger.warning(
|
||||
"Running pip as the 'root' user can result in broken permissions and "
|
||||
"conflicting behaviour with the system package manager. "
|
||||
|
@ -225,6 +227,31 @@ class RequirementCommand(IndexGroupCommand):
|
|||
|
||||
return "2020-resolver"
|
||||
|
||||
@staticmethod
|
||||
def determine_build_failure_suppression(options: Values) -> bool:
|
||||
"""Determines whether build failures should be suppressed and backtracked on."""
|
||||
if "backtrack-on-build-failures" not in options.deprecated_features_enabled:
|
||||
return False
|
||||
|
||||
if "legacy-resolver" in options.deprecated_features_enabled:
|
||||
raise CommandError("Cannot backtrack with legacy resolver.")
|
||||
|
||||
deprecated(
|
||||
reason=(
|
||||
"Backtracking on build failures can mask issues related to how "
|
||||
"a package generates metadata or builds a wheel. This flag will "
|
||||
"be removed in pip 22.2."
|
||||
),
|
||||
gone_in=None,
|
||||
replacement=(
|
||||
"avoiding known-bad versions by explicitly telling pip to ignore them "
|
||||
"(either directly as requirements, or via a constraints file)"
|
||||
),
|
||||
feature_flag=None,
|
||||
issue=10655,
|
||||
)
|
||||
return True
|
||||
|
||||
@classmethod
|
||||
def make_requirement_preparer(
|
||||
cls,
|
||||
|
@ -235,6 +262,7 @@ class RequirementCommand(IndexGroupCommand):
|
|||
finder: PackageFinder,
|
||||
use_user_site: bool,
|
||||
download_dir: Optional[str] = None,
|
||||
verbosity: int = 0,
|
||||
) -> RequirementPreparer:
|
||||
"""
|
||||
Create a RequirementPreparer instance for the given parameters.
|
||||
|
@ -260,6 +288,27 @@ class RequirementCommand(IndexGroupCommand):
|
|||
"fast-deps has no effect when used with the legacy resolver."
|
||||
)
|
||||
|
||||
in_tree_build = "out-of-tree-build" not in options.deprecated_features_enabled
|
||||
if "in-tree-build" in options.features_enabled:
|
||||
deprecated(
|
||||
reason="In-tree builds are now the default.",
|
||||
replacement="to remove the --use-feature=in-tree-build flag",
|
||||
gone_in="22.1",
|
||||
)
|
||||
if "out-of-tree-build" in options.deprecated_features_enabled:
|
||||
deprecated(
|
||||
reason="Out-of-tree builds are deprecated.",
|
||||
replacement=None,
|
||||
gone_in="22.1",
|
||||
)
|
||||
|
||||
if options.progress_bar not in {"on", "off"}:
|
||||
deprecated(
|
||||
reason="Custom progress bar styles are deprecated",
|
||||
replacement="to use the default progress bar style.",
|
||||
gone_in="22.1",
|
||||
)
|
||||
|
||||
return RequirementPreparer(
|
||||
build_dir=temp_build_dir_path,
|
||||
src_dir=options.src_dir,
|
||||
|
@ -272,7 +321,8 @@ class RequirementCommand(IndexGroupCommand):
|
|||
require_hashes=options.require_hashes,
|
||||
use_user_site=use_user_site,
|
||||
lazy_wheel=lazy_wheel,
|
||||
in_tree_build="in-tree-build" in options.features_enabled,
|
||||
verbosity=verbosity,
|
||||
in_tree_build=in_tree_build,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
|
@ -298,6 +348,7 @@ class RequirementCommand(IndexGroupCommand):
|
|||
isolated=options.isolated_mode,
|
||||
use_pep517=use_pep517,
|
||||
)
|
||||
suppress_build_failures = cls.determine_build_failure_suppression(options)
|
||||
resolver_variant = cls.determine_resolver_variant(options)
|
||||
# The long import name and duplicated invocation is needed to convince
|
||||
# Mypy into correctly typechecking. Otherwise it would complain the
|
||||
|
@ -317,6 +368,7 @@ class RequirementCommand(IndexGroupCommand):
|
|||
force_reinstall=force_reinstall,
|
||||
upgrade_strategy=upgrade_strategy,
|
||||
py_version_info=py_version_info,
|
||||
suppress_build_failures=suppress_build_failures,
|
||||
)
|
||||
import pip._internal.resolution.legacy.resolver
|
||||
|
||||
|
@ -450,4 +502,5 @@ class RequirementCommand(IndexGroupCommand):
|
|||
link_collector=link_collector,
|
||||
selection_prefs=selection_prefs,
|
||||
target_python=target_python,
|
||||
use_deprecated_html5lib="html5lib" in options.deprecated_features_enabled,
|
||||
)
|
||||
|
|
|
@ -170,12 +170,16 @@ class CacheCommand(Command):
|
|||
|
||||
files = self._find_wheels(options, args[0])
|
||||
|
||||
# Only fetch http files if no specific pattern given
|
||||
no_matching_msg = "No matching packages"
|
||||
if args[0] == "*":
|
||||
# Only fetch http files if no specific pattern given
|
||||
files += self._find_http_files(options)
|
||||
else:
|
||||
# Add the pattern to the log message
|
||||
no_matching_msg += ' for pattern "{}"'.format(args[0])
|
||||
|
||||
if not files:
|
||||
raise CommandError("No matching packages")
|
||||
logger.warning(no_matching_msg)
|
||||
|
||||
for filename in files:
|
||||
os.unlink(filename)
|
||||
|
|
|
@ -225,6 +225,10 @@ class ConfigurationCommand(Command):
|
|||
|
||||
try:
|
||||
subprocess.check_call([editor, fname])
|
||||
except FileNotFoundError as e:
|
||||
if not e.filename:
|
||||
e.filename = editor
|
||||
raise
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise PipError(
|
||||
"Editor Subprocess exited with exit code {}".format(e.returncode)
|
||||
|
|
|
@ -37,7 +37,6 @@ class DownloadCommand(RequirementCommand):
|
|||
def add_options(self) -> None:
|
||||
self.cmd_opts.add_option(cmdoptions.constraints())
|
||||
self.cmd_opts.add_option(cmdoptions.requirements())
|
||||
self.cmd_opts.add_option(cmdoptions.build_dir())
|
||||
self.cmd_opts.add_option(cmdoptions.no_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.global_options())
|
||||
self.cmd_opts.add_option(cmdoptions.no_binary())
|
||||
|
@ -114,6 +113,7 @@ class DownloadCommand(RequirementCommand):
|
|||
finder=finder,
|
||||
download_dir=options.download_dir,
|
||||
use_user_site=False,
|
||||
verbosity=self.verbosity,
|
||||
)
|
||||
|
||||
resolver = self.make_resolver(
|
||||
|
|
|
@ -97,6 +97,7 @@ class IndexCommand(IndexGroupCommand):
|
|||
link_collector=link_collector,
|
||||
selection_prefs=selection_prefs,
|
||||
target_python=target_python,
|
||||
use_deprecated_html5lib="html5lib" in options.deprecated_features_enabled,
|
||||
)
|
||||
|
||||
def get_available_package_versions(self, options: Values, args: List[Any]) -> None:
|
||||
|
|
|
@ -135,8 +135,6 @@ class InstallCommand(RequirementCommand):
|
|||
),
|
||||
)
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.build_dir())
|
||||
|
||||
self.cmd_opts.add_option(cmdoptions.src())
|
||||
|
||||
self.cmd_opts.add_option(
|
||||
|
@ -306,6 +304,12 @@ class InstallCommand(RequirementCommand):
|
|||
try:
|
||||
reqs = self.get_requirements(args, options, finder, session)
|
||||
|
||||
# Only when installing is it permitted to use PEP 660.
|
||||
# In other circumstances (pip wheel, pip download) we generate
|
||||
# regular (i.e. non editable) metadata and wheels.
|
||||
for req in reqs:
|
||||
req.permit_editable_wheels = True
|
||||
|
||||
reject_location_related_install_options(reqs, options.install_options)
|
||||
|
||||
preparer = self.make_requirement_preparer(
|
||||
|
@ -315,6 +319,7 @@ class InstallCommand(RequirementCommand):
|
|||
session=session,
|
||||
finder=finder,
|
||||
use_user_site=options.use_user_site,
|
||||
verbosity=self.verbosity,
|
||||
)
|
||||
resolver = self.make_resolver(
|
||||
preparer=preparer,
|
||||
|
@ -361,22 +366,22 @@ class InstallCommand(RequirementCommand):
|
|||
global_options=[],
|
||||
)
|
||||
|
||||
# If we're using PEP 517, we cannot do a direct install
|
||||
# If we're using PEP 517, we cannot do a legacy setup.py install
|
||||
# so we fail here.
|
||||
pep517_build_failure_names: List[str] = [
|
||||
r.name for r in build_failures if r.use_pep517 # type: ignore
|
||||
]
|
||||
if pep517_build_failure_names:
|
||||
raise InstallationError(
|
||||
"Could not build wheels for {} which use"
|
||||
" PEP 517 and cannot be installed directly".format(
|
||||
"Could not build wheels for {}, which is required to "
|
||||
"install pyproject.toml-based projects".format(
|
||||
", ".join(pep517_build_failure_names)
|
||||
)
|
||||
)
|
||||
|
||||
# For now, we just warn about failures building legacy
|
||||
# requirements, as we'll fall through to a direct
|
||||
# install for those.
|
||||
# requirements, as we'll fall through to a setup.py install for
|
||||
# those.
|
||||
for r in build_failures:
|
||||
if not r.use_pep517:
|
||||
r.legacy_install_reason = 8368
|
||||
|
|
|
@ -14,8 +14,8 @@ from pip._internal.index.package_finder import PackageFinder
|
|||
from pip._internal.metadata import BaseDistribution, get_environment
|
||||
from pip._internal.models.selection_prefs import SelectionPreferences
|
||||
from pip._internal.network.session import PipSession
|
||||
from pip._internal.utils.misc import stdlib_pkgs, tabulate, write_output
|
||||
from pip._internal.utils.parallel import map_multithread
|
||||
from pip._internal.utils.compat import stdlib_pkgs
|
||||
from pip._internal.utils.misc import tabulate, write_output
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from pip._internal.metadata.base import DistributionVersion
|
||||
|
@ -149,6 +149,7 @@ class ListCommand(IndexGroupCommand):
|
|||
return PackageFinder.create(
|
||||
link_collector=link_collector,
|
||||
selection_prefs=selection_prefs,
|
||||
use_deprecated_html5lib="html5lib" in options.deprecated_features_enabled,
|
||||
)
|
||||
|
||||
def run(self, options: Values, args: List[str]) -> int:
|
||||
|
@ -253,7 +254,7 @@ class ListCommand(IndexGroupCommand):
|
|||
dist.latest_filetype = typ
|
||||
return dist
|
||||
|
||||
for dist in map_multithread(latest_info, packages):
|
||||
for dist in map(latest_info, packages):
|
||||
if dist is not None:
|
||||
yield dist
|
||||
|
||||
|
@ -302,19 +303,22 @@ def format_for_columns(
|
|||
Convert the package data into something usable
|
||||
by output_package_listing_columns.
|
||||
"""
|
||||
running_outdated = options.outdated
|
||||
# Adjust the header for the `pip list --outdated` case.
|
||||
if running_outdated:
|
||||
header = ["Package", "Version", "Latest", "Type"]
|
||||
else:
|
||||
header = ["Package", "Version"]
|
||||
header = ["Package", "Version"]
|
||||
|
||||
data = []
|
||||
if options.verbose >= 1 or any(x.editable for x in pkgs):
|
||||
running_outdated = options.outdated
|
||||
if running_outdated:
|
||||
header.extend(["Latest", "Type"])
|
||||
|
||||
has_editables = any(x.editable for x in pkgs)
|
||||
if has_editables:
|
||||
header.append("Editable project location")
|
||||
|
||||
if options.verbose >= 1:
|
||||
header.append("Location")
|
||||
if options.verbose >= 1:
|
||||
header.append("Installer")
|
||||
|
||||
data = []
|
||||
for proj in pkgs:
|
||||
# if we're working on the 'outdated' list, separate out the
|
||||
# latest_version and type
|
||||
|
@ -324,7 +328,10 @@ def format_for_columns(
|
|||
row.append(str(proj.latest_version))
|
||||
row.append(proj.latest_filetype)
|
||||
|
||||
if options.verbose >= 1 or proj.editable:
|
||||
if has_editables:
|
||||
row.append(proj.editable_project_location or "")
|
||||
|
||||
if options.verbose >= 1:
|
||||
row.append(proj.location or "")
|
||||
if options.verbose >= 1:
|
||||
row.append(proj.installer)
|
||||
|
@ -347,5 +354,8 @@ def format_for_json(packages: "_ProcessedDists", options: Values) -> str:
|
|||
if options.outdated:
|
||||
info["latest_version"] = str(dist.latest_version)
|
||||
info["latest_filetype"] = dist.latest_filetype
|
||||
editable_project_location = dist.editable_project_location
|
||||
if editable_project_location:
|
||||
info["editable_project_location"] = editable_project_location
|
||||
data.append(info)
|
||||
return json.dumps(data)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
import csv
|
||||
import logging
|
||||
import pathlib
|
||||
from optparse import Values
|
||||
from typing import Iterator, List, NamedTuple, Optional, Tuple
|
||||
from typing import Iterator, List, NamedTuple, Optional
|
||||
|
||||
from pip._vendor.packaging.utils import canonicalize_name
|
||||
|
||||
|
@ -69,33 +67,6 @@ class _PackageInfo(NamedTuple):
|
|||
files: Optional[List[str]]
|
||||
|
||||
|
||||
def _convert_legacy_entry(entry: Tuple[str, ...], info: Tuple[str, ...]) -> str:
|
||||
"""Convert a legacy installed-files.txt path into modern RECORD path.
|
||||
|
||||
The legacy format stores paths relative to the info directory, while the
|
||||
modern format stores paths relative to the package root, e.g. the
|
||||
site-packages directory.
|
||||
|
||||
:param entry: Path parts of the installed-files.txt entry.
|
||||
:param info: Path parts of the egg-info directory relative to package root.
|
||||
:returns: The converted entry.
|
||||
|
||||
For best compatibility with symlinks, this does not use ``abspath()`` or
|
||||
``Path.resolve()``, but tries to work with path parts:
|
||||
|
||||
1. While ``entry`` starts with ``..``, remove the equal amounts of parts
|
||||
from ``info``; if ``info`` is empty, start appending ``..`` instead.
|
||||
2. Join the two directly.
|
||||
"""
|
||||
while entry and entry[0] == "..":
|
||||
if not info or info[-1] == "..":
|
||||
info += ("..",)
|
||||
else:
|
||||
info = info[:-1]
|
||||
entry = entry[1:]
|
||||
return str(pathlib.Path(*info, *entry))
|
||||
|
||||
|
||||
def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
|
||||
"""
|
||||
Gather details from installed distributions. Print distribution name,
|
||||
|
@ -113,40 +84,12 @@ def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
|
|||
if missing:
|
||||
logger.warning("Package(s) not found: %s", ", ".join(missing))
|
||||
|
||||
def _get_requiring_packages(current_dist: BaseDistribution) -> List[str]:
|
||||
return [
|
||||
def _get_requiring_packages(current_dist: BaseDistribution) -> Iterator[str]:
|
||||
return (
|
||||
dist.metadata["Name"] or "UNKNOWN"
|
||||
for dist in installed.values()
|
||||
if current_dist.canonical_name
|
||||
in {canonicalize_name(d.name) for d in dist.iter_dependencies()}
|
||||
]
|
||||
|
||||
def _files_from_record(dist: BaseDistribution) -> Optional[Iterator[str]]:
|
||||
try:
|
||||
text = dist.read_text("RECORD")
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
# This extra Path-str cast normalizes entries.
|
||||
return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines()))
|
||||
|
||||
def _files_from_legacy(dist: BaseDistribution) -> Optional[Iterator[str]]:
|
||||
try:
|
||||
text = dist.read_text("installed-files.txt")
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
paths = (p for p in text.splitlines(keepends=False) if p)
|
||||
root = dist.location
|
||||
info = dist.info_directory
|
||||
if root is None or info is None:
|
||||
return paths
|
||||
try:
|
||||
info_rel = pathlib.Path(info).relative_to(root)
|
||||
except ValueError: # info is not relative to root.
|
||||
return paths
|
||||
if not info_rel.parts: # info *is* root.
|
||||
return paths
|
||||
return (
|
||||
_convert_legacy_entry(pathlib.Path(p).parts, info_rel.parts) for p in paths
|
||||
)
|
||||
|
||||
for query_name in query_names:
|
||||
|
@ -155,13 +98,16 @@ def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
|
|||
except KeyError:
|
||||
continue
|
||||
|
||||
requires = sorted((req.name for req in dist.iter_dependencies()), key=str.lower)
|
||||
required_by = sorted(_get_requiring_packages(dist), key=str.lower)
|
||||
|
||||
try:
|
||||
entry_points_text = dist.read_text("entry_points.txt")
|
||||
entry_points = entry_points_text.splitlines(keepends=False)
|
||||
except FileNotFoundError:
|
||||
entry_points = []
|
||||
|
||||
files_iter = _files_from_record(dist) or _files_from_legacy(dist)
|
||||
files_iter = dist.iter_declared_entries()
|
||||
if files_iter is None:
|
||||
files: Optional[List[str]] = None
|
||||
else:
|
||||
|
@ -173,8 +119,8 @@ def search_packages_info(query: List[str]) -> Iterator[_PackageInfo]:
|
|||
name=dist.raw_name,
|
||||
version=str(dist.version),
|
||||
location=dist.location or "",
|
||||
requires=[req.name for req in dist.iter_dependencies()],
|
||||
required_by=_get_requiring_packages(dist),
|
||||
requires=requires,
|
||||
required_by=required_by,
|
||||
installer=dist.installer,
|
||||
metadata_version=dist.metadata_version or "",
|
||||
classifiers=metadata.get_all("Classifier", []),
|
||||
|
|
|
@ -65,7 +65,6 @@ class WheelCommand(RequirementCommand):
|
|||
self.cmd_opts.add_option(cmdoptions.src())
|
||||
self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
|
||||
self.cmd_opts.add_option(cmdoptions.no_deps())
|
||||
self.cmd_opts.add_option(cmdoptions.build_dir())
|
||||
self.cmd_opts.add_option(cmdoptions.progress_bar())
|
||||
|
||||
self.cmd_opts.add_option(
|
||||
|
@ -129,6 +128,7 @@ class WheelCommand(RequirementCommand):
|
|||
finder=finder,
|
||||
download_dir=options.wheel_dir,
|
||||
use_user_site=False,
|
||||
verbosity=self.verbosity,
|
||||
)
|
||||
|
||||
resolver = self.make_resolver(
|
||||
|
|
|
@ -13,7 +13,6 @@ Some terminology:
|
|||
|
||||
import configparser
|
||||
import locale
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple
|
||||
|
@ -24,6 +23,7 @@ from pip._internal.exceptions import (
|
|||
)
|
||||
from pip._internal.utils import appdirs
|
||||
from pip._internal.utils.compat import WINDOWS
|
||||
from pip._internal.utils.logging import getLogger
|
||||
from pip._internal.utils.misc import ensure_dir, enum
|
||||
|
||||
RawConfigParser = configparser.RawConfigParser # Shorthand
|
||||
|
@ -43,7 +43,7 @@ kinds = enum(
|
|||
OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR
|
||||
VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.SITE
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
logger = getLogger(__name__)
|
||||
|
||||
|
||||
# NOTE: Maybe use the optionx attribute to normalize keynames.
|
||||
|
@ -250,7 +250,7 @@ class Configuration:
|
|||
self._parsers[variant].append((fname, parser))
|
||||
|
||||
def _load_file(self, variant: Kind, fname: str) -> RawConfigParser:
|
||||
logger.debug("For variant '%s', will try loading '%s'", variant, fname)
|
||||
logger.verbose("For variant '%s', will try loading '%s'", variant, fname)
|
||||
parser = self._construct_parser(fname)
|
||||
|
||||
for section in parser.sections():
|
||||
|
@ -266,14 +266,13 @@ class Configuration:
|
|||
# Doing this is useful when modifying and saving files, where we don't
|
||||
# need to construct a parser.
|
||||
if os.path.exists(fname):
|
||||
locale_encoding = locale.getpreferredencoding(False)
|
||||
try:
|
||||
parser.read(fname)
|
||||
parser.read(fname, encoding=locale_encoding)
|
||||
except UnicodeDecodeError:
|
||||
# See https://github.com/pypa/pip/issues/4963
|
||||
raise ConfigurationFileCouldNotBeLoaded(
|
||||
reason="contains invalid {} characters".format(
|
||||
locale.getpreferredencoding(False)
|
||||
),
|
||||
reason=f"contains invalid {locale_encoding} characters",
|
||||
fname=fname,
|
||||
)
|
||||
except configparser.Error as error:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import logging
|
||||
from typing import Set, Tuple
|
||||
from typing import Iterable, Set, Tuple
|
||||
|
||||
from pip._internal.build_env import BuildEnvironment
|
||||
from pip._internal.distributions.base import AbstractDistribution
|
||||
|
@ -19,9 +19,7 @@ class SourceDistribution(AbstractDistribution):
|
|||
"""
|
||||
|
||||
def get_metadata_distribution(self) -> BaseDistribution:
|
||||
from pip._internal.metadata.pkg_resources import Distribution as _Dist
|
||||
|
||||
return _Dist(self.req.get_dist())
|
||||
return self.req.get_dist()
|
||||
|
||||
def prepare_distribution_metadata(
|
||||
self, finder: PackageFinder, build_isolation: bool
|
||||
|
@ -32,28 +30,32 @@ class SourceDistribution(AbstractDistribution):
|
|||
# Set up the build isolation, if this requirement should be isolated
|
||||
should_isolate = self.req.use_pep517 and build_isolation
|
||||
if should_isolate:
|
||||
self._setup_isolation(finder)
|
||||
|
||||
# Setup an isolated environment and install the build backend static
|
||||
# requirements in it.
|
||||
self._prepare_build_backend(finder)
|
||||
# Check that if the requirement is editable, it either supports PEP 660 or
|
||||
# has a setup.py or a setup.cfg. This cannot be done earlier because we need
|
||||
# to setup the build backend to verify it supports build_editable, nor can
|
||||
# it be done later, because we want to avoid installing build requirements
|
||||
# needlessly. Doing it here also works around setuptools generating
|
||||
# UNKNOWN.egg-info when running get_requires_for_build_wheel on a directory
|
||||
# without setup.py nor setup.cfg.
|
||||
self.req.isolated_editable_sanity_check()
|
||||
# Install the dynamic build requirements.
|
||||
self._install_build_reqs(finder)
|
||||
elif self.req.use_pep517:
|
||||
pyproject_requires = self.req.pyproject_requires
|
||||
assert pyproject_requires is not None
|
||||
conflicting, missing = self.req.build_env.check_requirements(
|
||||
pyproject_requires
|
||||
)
|
||||
if conflicting:
|
||||
self._raise_conflicts("the backend dependencies", conflicting)
|
||||
if missing:
|
||||
self._raise_missing_reqs(missing)
|
||||
self.req.prepare_metadata()
|
||||
|
||||
def _setup_isolation(self, finder: PackageFinder) -> None:
|
||||
def _raise_conflicts(
|
||||
conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]]
|
||||
) -> None:
|
||||
format_string = (
|
||||
"Some build dependencies for {requirement} "
|
||||
"conflict with {conflicting_with}: {description}."
|
||||
)
|
||||
error_message = format_string.format(
|
||||
requirement=self.req,
|
||||
conflicting_with=conflicting_with,
|
||||
description=", ".join(
|
||||
f"{installed} is incompatible with {wanted}"
|
||||
for installed, wanted in sorted(conflicting)
|
||||
),
|
||||
)
|
||||
raise InstallationError(error_message)
|
||||
|
||||
def _prepare_build_backend(self, finder: PackageFinder) -> None:
|
||||
# Isolate in a BuildEnvironment and install the build-time
|
||||
# requirements.
|
||||
pyproject_requires = self.req.pyproject_requires
|
||||
|
@ -61,13 +63,13 @@ class SourceDistribution(AbstractDistribution):
|
|||
|
||||
self.req.build_env = BuildEnvironment()
|
||||
self.req.build_env.install_requirements(
|
||||
finder, pyproject_requires, "overlay", "Installing build dependencies"
|
||||
finder, pyproject_requires, "overlay", kind="build dependencies"
|
||||
)
|
||||
conflicting, missing = self.req.build_env.check_requirements(
|
||||
self.req.requirements_to_check
|
||||
)
|
||||
if conflicting:
|
||||
_raise_conflicts("PEP 517/518 supported requirements", conflicting)
|
||||
self._raise_conflicts("PEP 517/518 supported requirements", conflicting)
|
||||
if missing:
|
||||
logger.warning(
|
||||
"Missing build requirements in pyproject.toml for %s.",
|
||||
|
@ -78,19 +80,66 @@ class SourceDistribution(AbstractDistribution):
|
|||
"pip cannot fall back to setuptools without %s.",
|
||||
" and ".join(map(repr, sorted(missing))),
|
||||
)
|
||||
# Install any extra build dependencies that the backend requests.
|
||||
# This must be done in a second pass, as the pyproject.toml
|
||||
# dependencies must be installed before we can call the backend.
|
||||
|
||||
def _get_build_requires_wheel(self) -> Iterable[str]:
|
||||
with self.req.build_env:
|
||||
runner = runner_with_spinner_message("Getting requirements to build wheel")
|
||||
backend = self.req.pep517_backend
|
||||
assert backend is not None
|
||||
with backend.subprocess_runner(runner):
|
||||
reqs = backend.get_requires_for_build_wheel()
|
||||
return backend.get_requires_for_build_wheel()
|
||||
|
||||
conflicting, missing = self.req.build_env.check_requirements(reqs)
|
||||
def _get_build_requires_editable(self) -> Iterable[str]:
|
||||
with self.req.build_env:
|
||||
runner = runner_with_spinner_message(
|
||||
"Getting requirements to build editable"
|
||||
)
|
||||
backend = self.req.pep517_backend
|
||||
assert backend is not None
|
||||
with backend.subprocess_runner(runner):
|
||||
return backend.get_requires_for_build_editable()
|
||||
|
||||
def _install_build_reqs(self, finder: PackageFinder) -> None:
|
||||
# Install any extra build dependencies that the backend requests.
|
||||
# This must be done in a second pass, as the pyproject.toml
|
||||
# dependencies must be installed before we can call the backend.
|
||||
if (
|
||||
self.req.editable
|
||||
and self.req.permit_editable_wheels
|
||||
and self.req.supports_pyproject_editable()
|
||||
):
|
||||
build_reqs = self._get_build_requires_editable()
|
||||
else:
|
||||
build_reqs = self._get_build_requires_wheel()
|
||||
conflicting, missing = self.req.build_env.check_requirements(build_reqs)
|
||||
if conflicting:
|
||||
_raise_conflicts("the backend dependencies", conflicting)
|
||||
self._raise_conflicts("the backend dependencies", conflicting)
|
||||
self.req.build_env.install_requirements(
|
||||
finder, missing, "normal", "Installing backend dependencies"
|
||||
finder, missing, "normal", kind="backend dependencies"
|
||||
)
|
||||
|
||||
def _raise_conflicts(
|
||||
self, conflicting_with: str, conflicting_reqs: Set[Tuple[str, str]]
|
||||
) -> None:
|
||||
format_string = (
|
||||
"Some build dependencies for {requirement} "
|
||||
"conflict with {conflicting_with}: {description}."
|
||||
)
|
||||
error_message = format_string.format(
|
||||
requirement=self.req,
|
||||
conflicting_with=conflicting_with,
|
||||
description=", ".join(
|
||||
f"{installed} is incompatible with {wanted}"
|
||||
for installed, wanted in sorted(conflicting_reqs)
|
||||
),
|
||||
)
|
||||
raise InstallationError(error_message)
|
||||
|
||||
def _raise_missing_reqs(self, missing: Set[str]) -> None:
|
||||
format_string = (
|
||||
"Some build dependencies for {requirement} are missing: {missing}."
|
||||
)
|
||||
error_message = format_string.format(
|
||||
requirement=self.req, missing=", ".join(map(repr, sorted(missing)))
|
||||
)
|
||||
raise InstallationError(error_message)
|
||||
|
|
|
@ -1,23 +1,174 @@
|
|||
"""Exceptions used throughout package"""
|
||||
"""Exceptions used throughout package.
|
||||
|
||||
This module MUST NOT try to import from anything within `pip._internal` to
|
||||
operate. This is expected to be importable from any/all files within the
|
||||
subpackage and, thus, should not depend on them.
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import re
|
||||
from itertools import chain, groupby, repeat
|
||||
from typing import TYPE_CHECKING, Dict, List, Optional, Union
|
||||
|
||||
from pip._vendor.pkg_resources import Distribution
|
||||
from pip._vendor.requests.models import Request, Response
|
||||
from pip._vendor.rich.console import Console, ConsoleOptions, RenderResult
|
||||
from pip._vendor.rich.markup import escape
|
||||
from pip._vendor.rich.text import Text
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from hashlib import _Hash
|
||||
from typing import Literal
|
||||
|
||||
from pip._internal.metadata import BaseDistribution
|
||||
from pip._internal.req.req_install import InstallRequirement
|
||||
|
||||
|
||||
#
|
||||
# Scaffolding
|
||||
#
|
||||
def _is_kebab_case(s: str) -> bool:
|
||||
return re.match(r"^[a-z]+(-[a-z]+)*$", s) is not None
|
||||
|
||||
|
||||
def _prefix_with_indent(
|
||||
s: Union[Text, str],
|
||||
console: Console,
|
||||
*,
|
||||
prefix: str,
|
||||
indent: str,
|
||||
) -> Text:
|
||||
if isinstance(s, Text):
|
||||
text = s
|
||||
else:
|
||||
text = console.render_str(s)
|
||||
|
||||
return console.render_str(prefix, overflow="ignore") + console.render_str(
|
||||
f"\n{indent}", overflow="ignore"
|
||||
).join(text.split(allow_blank=True))
|
||||
|
||||
|
||||
class PipError(Exception):
|
||||
"""Base pip exception"""
|
||||
"""The base pip error."""
|
||||
|
||||
|
||||
class DiagnosticPipError(PipError):
|
||||
"""An error, that presents diagnostic information to the user.
|
||||
|
||||
This contains a bunch of logic, to enable pretty presentation of our error
|
||||
messages. Each error gets a unique reference. Each error can also include
|
||||
additional context, a hint and/or a note -- which are presented with the
|
||||
main error message in a consistent style.
|
||||
|
||||
This is adapted from the error output styling in `sphinx-theme-builder`.
|
||||
"""
|
||||
|
||||
reference: str
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
kind: 'Literal["error", "warning"]' = "error",
|
||||
reference: Optional[str] = None,
|
||||
message: Union[str, Text],
|
||||
context: Optional[Union[str, Text]],
|
||||
hint_stmt: Optional[Union[str, Text]],
|
||||
note_stmt: Optional[Union[str, Text]] = None,
|
||||
link: Optional[str] = None,
|
||||
) -> None:
|
||||
# Ensure a proper reference is provided.
|
||||
if reference is None:
|
||||
assert hasattr(self, "reference"), "error reference not provided!"
|
||||
reference = self.reference
|
||||
assert _is_kebab_case(reference), "error reference must be kebab-case!"
|
||||
|
||||
self.kind = kind
|
||||
self.reference = reference
|
||||
|
||||
self.message = message
|
||||
self.context = context
|
||||
|
||||
self.note_stmt = note_stmt
|
||||
self.hint_stmt = hint_stmt
|
||||
|
||||
self.link = link
|
||||
|
||||
super().__init__(f"<{self.__class__.__name__}: {self.reference}>")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"<{self.__class__.__name__}("
|
||||
f"reference={self.reference!r}, "
|
||||
f"message={self.message!r}, "
|
||||
f"context={self.context!r}, "
|
||||
f"note_stmt={self.note_stmt!r}, "
|
||||
f"hint_stmt={self.hint_stmt!r}"
|
||||
")>"
|
||||
)
|
||||
|
||||
def __rich_console__(
|
||||
self,
|
||||
console: Console,
|
||||
options: ConsoleOptions,
|
||||
) -> RenderResult:
|
||||
colour = "red" if self.kind == "error" else "yellow"
|
||||
|
||||
yield f"[{colour} bold]{self.kind}[/]: [bold]{self.reference}[/]"
|
||||
yield ""
|
||||
|
||||
if not options.ascii_only:
|
||||
# Present the main message, with relevant context indented.
|
||||
if self.context is not None:
|
||||
yield _prefix_with_indent(
|
||||
self.message,
|
||||
console,
|
||||
prefix=f"[{colour}]×[/] ",
|
||||
indent=f"[{colour}]│[/] ",
|
||||
)
|
||||
yield _prefix_with_indent(
|
||||
self.context,
|
||||
console,
|
||||
prefix=f"[{colour}]╰─>[/] ",
|
||||
indent=f"[{colour}] [/] ",
|
||||
)
|
||||
else:
|
||||
yield _prefix_with_indent(
|
||||
self.message,
|
||||
console,
|
||||
prefix="[red]×[/] ",
|
||||
indent=" ",
|
||||
)
|
||||
else:
|
||||
yield self.message
|
||||
if self.context is not None:
|
||||
yield ""
|
||||
yield self.context
|
||||
|
||||
if self.note_stmt is not None or self.hint_stmt is not None:
|
||||
yield ""
|
||||
|
||||
if self.note_stmt is not None:
|
||||
yield _prefix_with_indent(
|
||||
self.note_stmt,
|
||||
console,
|
||||
prefix="[magenta bold]note[/]: ",
|
||||
indent=" ",
|
||||
)
|
||||
if self.hint_stmt is not None:
|
||||
yield _prefix_with_indent(
|
||||
self.hint_stmt,
|
||||
console,
|
||||
prefix="[cyan bold]hint[/]: ",
|
||||
indent=" ",
|
||||
)
|
||||
|
||||
if self.link is not None:
|
||||
yield ""
|
||||
yield f"Link: {self.link}"
|
||||
|
||||
|
||||
#
|
||||
# Actual Errors
|
||||
#
|
||||
class ConfigurationError(PipError):
|
||||
"""General exception in configuration"""
|
||||
|
||||
|
@ -30,18 +181,52 @@ class UninstallationError(PipError):
|
|||
"""General exception during uninstallation"""
|
||||
|
||||
|
||||
class MissingPyProjectBuildRequires(DiagnosticPipError):
|
||||
"""Raised when pyproject.toml has `build-system`, but no `build-system.requires`."""
|
||||
|
||||
reference = "missing-pyproject-build-system-requires"
|
||||
|
||||
def __init__(self, *, package: str) -> None:
|
||||
super().__init__(
|
||||
message=f"Can not process {escape(package)}",
|
||||
context=Text(
|
||||
"This package has an invalid pyproject.toml file.\n"
|
||||
"The [build-system] table is missing the mandatory `requires` key."
|
||||
),
|
||||
note_stmt="This is an issue with the package mentioned above, not pip.",
|
||||
hint_stmt=Text("See PEP 518 for the detailed specification."),
|
||||
)
|
||||
|
||||
|
||||
class InvalidPyProjectBuildRequires(DiagnosticPipError):
|
||||
"""Raised when pyproject.toml an invalid `build-system.requires`."""
|
||||
|
||||
reference = "invalid-pyproject-build-system-requires"
|
||||
|
||||
def __init__(self, *, package: str, reason: str) -> None:
|
||||
super().__init__(
|
||||
message=f"Can not process {escape(package)}",
|
||||
context=Text(
|
||||
"This package has an invalid `build-system.requires` key in "
|
||||
f"pyproject.toml.\n{reason}"
|
||||
),
|
||||
note_stmt="This is an issue with the package mentioned above, not pip.",
|
||||
hint_stmt=Text("See PEP 518 for the detailed specification."),
|
||||
)
|
||||
|
||||
|
||||
class NoneMetadataError(PipError):
|
||||
"""
|
||||
Raised when accessing "METADATA" or "PKG-INFO" metadata for a
|
||||
pip._vendor.pkg_resources.Distribution object and
|
||||
`dist.has_metadata('METADATA')` returns True but
|
||||
`dist.get_metadata('METADATA')` returns None (and similarly for
|
||||
"PKG-INFO").
|
||||
"""Raised when accessing a Distribution's "METADATA" or "PKG-INFO".
|
||||
|
||||
This signifies an inconsistency, when the Distribution claims to have
|
||||
the metadata file (if not, raise ``FileNotFoundError`` instead), but is
|
||||
not actually able to produce its content. This may be due to permission
|
||||
errors.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
dist: Union[Distribution, "BaseDistribution"],
|
||||
dist: "BaseDistribution",
|
||||
metadata_name: str,
|
||||
) -> None:
|
||||
"""
|
||||
|
@ -132,6 +317,17 @@ class UnsupportedWheel(InstallationError):
|
|||
"""Unsupported wheel."""
|
||||
|
||||
|
||||
class InvalidWheel(InstallationError):
|
||||
"""Invalid (e.g. corrupt) wheel."""
|
||||
|
||||
def __init__(self, location: str, name: str):
|
||||
self.location = location
|
||||
self.name = name
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"Wheel '{self.name}' located at {self.location} is invalid."
|
||||
|
||||
|
||||
class MetadataInconsistent(InstallationError):
|
||||
"""Built metadata contains inconsistent information.
|
||||
|
||||
|
@ -156,18 +352,78 @@ class MetadataInconsistent(InstallationError):
|
|||
return template.format(self.ireq, self.field, self.f_val, self.m_val)
|
||||
|
||||
|
||||
class InstallationSubprocessError(InstallationError):
|
||||
"""A subprocess call failed during installation."""
|
||||
class LegacyInstallFailure(DiagnosticPipError):
|
||||
"""Error occurred while executing `setup.py install`"""
|
||||
|
||||
def __init__(self, returncode: int, description: str) -> None:
|
||||
self.returncode = returncode
|
||||
self.description = description
|
||||
reference = "legacy-install-failure"
|
||||
|
||||
def __init__(self, package_details: str) -> None:
|
||||
super().__init__(
|
||||
message="Encountered error while trying to install package.",
|
||||
context=package_details,
|
||||
hint_stmt="See above for output from the failure.",
|
||||
note_stmt="This is an issue with the package mentioned above, not pip.",
|
||||
)
|
||||
|
||||
|
||||
class InstallationSubprocessError(DiagnosticPipError, InstallationError):
|
||||
"""A subprocess call failed."""
|
||||
|
||||
reference = "subprocess-exited-with-error"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
command_description: str,
|
||||
exit_code: int,
|
||||
output_lines: Optional[List[str]],
|
||||
) -> None:
|
||||
if output_lines is None:
|
||||
output_prompt = Text("See above for output.")
|
||||
else:
|
||||
output_prompt = (
|
||||
Text.from_markup(f"[red][{len(output_lines)} lines of output][/]\n")
|
||||
+ Text("".join(output_lines))
|
||||
+ Text.from_markup(R"[red]\[end of output][/]")
|
||||
)
|
||||
|
||||
super().__init__(
|
||||
message=(
|
||||
f"[green]{escape(command_description)}[/] did not run successfully.\n"
|
||||
f"exit code: {exit_code}"
|
||||
),
|
||||
context=output_prompt,
|
||||
hint_stmt=None,
|
||||
note_stmt=(
|
||||
"This error originates from a subprocess, and is likely not a "
|
||||
"problem with pip."
|
||||
),
|
||||
)
|
||||
|
||||
self.command_description = command_description
|
||||
self.exit_code = exit_code
|
||||
|
||||
def __str__(self) -> str:
|
||||
return (
|
||||
"Command errored out with exit status {}: {} "
|
||||
"Check the logs for full command output."
|
||||
).format(self.returncode, self.description)
|
||||
return f"{self.command_description} exited with {self.exit_code}"
|
||||
|
||||
|
||||
class MetadataGenerationFailed(InstallationSubprocessError, InstallationError):
|
||||
reference = "metadata-generation-failed"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
package_details: str,
|
||||
) -> None:
|
||||
super(InstallationSubprocessError, self).__init__(
|
||||
message="Encountered error while generating package metadata.",
|
||||
context=escape(package_details),
|
||||
hint_stmt="See above for details.",
|
||||
note_stmt="This is an issue with the package mentioned above, not pip.",
|
||||
)
|
||||
|
||||
def __str__(self) -> str:
|
||||
return "metadata generation failed"
|
||||
|
||||
|
||||
class HashErrors(InstallationError):
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue