Skip to content

Commit d12ab1c

Browse files
authored
Merge pull request #10100 from pradyunsg/topic/repeatable-installs
2 parents 1f1e1d6 + cc188ae commit d12ab1c

File tree

4 files changed

+104
-84
lines changed

4 files changed

+104
-84
lines changed

docs/html/cli/pip_install.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -519,9 +519,9 @@ of having the wheel cache disabled is thus extra build time for sdists, and
519519
this can be solved by making sure pre-built wheels are available from the index
520520
server.
521521

522-
Hash-checking mode also works with :ref:`pip download` and :ref:`pip wheel`. A
523-
:ref:`comparison of hash-checking mode with other repeatability strategies
524-
<Repeatability>` is available in the User Guide.
522+
Hash-checking mode also works with :ref:`pip download` and :ref:`pip wheel`.
523+
See :doc:`../topics/repeatable-installs` for a comparison of hash-checking mode
524+
with other repeatability strategies.
525525

526526
.. warning::
527527

docs/html/topics/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ This section of the documentation is currently being fleshed out. See
1313
authentication
1414
caching
1515
configuration
16+
repeatable-installs
1617
vcs-support
1718
```
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# Repeatable Installs
2+
3+
pip can be used to achieve various levels of repeatable environments. This page
4+
walks through increasingly stricter definitions of what "repeatable" means.
5+
6+
## Pinning the package versions
7+
8+
Pinning package versions of your dependencies in the requirements file
9+
protects you from bugs or incompatibilities in newly released versions:
10+
11+
```
12+
SomePackage == 1.2.3
13+
DependencyOfSomePackage == 4.5.6
14+
```
15+
16+
```{note}
17+
Pinning refers to using the `==` operator to require the package to be a
18+
specific version.
19+
```
20+
21+
A requirements file, containing pinned package versions can be generated using
22+
{ref}`pip freeze`. This would not only the top-level packages, but also all of
23+
their transitive dependencies. Performing the installation using
24+
{ref}`--no-deps <install_--no-deps>` would provide an extra dose of insurance
25+
against installing anything not explicitly listed.
26+
27+
This strategy is easy to implement and works across OSes and architectures.
28+
However, it trusts the locations you're fetching the packages from (like PyPI)
29+
and the certificate authority chain. It also relies on those locations not
30+
allowing packages to change without a version increase. (PyPI does protect
31+
against this.)
32+
33+
## Hash-checking
34+
35+
Beyond pinning version numbers, you can add hashes against which to verify
36+
downloaded packages:
37+
38+
```none
39+
FooProject == 1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
40+
```
41+
42+
This protects against a compromise of PyPI or the HTTPS certificate chain. It
43+
also guards against a package changing without its version number changing (on
44+
indexes that allow this). This approach is a good fit for automated server
45+
deployments.
46+
47+
Hash-checking mode is a labour-saving alternative to running a private index
48+
server containing approved packages: it removes the need to upload packages,
49+
maintain ACLs, and keep an audit trail (which a VCS gives you on the
50+
requirements file for free). It can also substitute for a vendored library,
51+
providing easier upgrades and less VCS noise. It does not, of course,
52+
provide the availability benefits of a private index or a vendored library.
53+
54+
[pip-tools] is a package that builds upon pip, and provides a good workflow for
55+
managing and generating requirements files.
56+
57+
[pip-tools]: https://github.com/jazzband/pip-tools#readme
58+
59+
## Using a wheelhouse (AKA Installation Bundles)
60+
61+
{ref}`pip wheel` can be used to generate and package all of a project's
62+
dependencies, with all the compilation performed, into a single directory that
63+
can be converted into a single archive. This archive then allows installation
64+
when index servers are unavailable and avoids time-consuming recompilation.
65+
66+
````{admonition} Example
67+
Creating the bundle, on a modern Unix system:
68+
69+
```
70+
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
71+
$ python -m pip wheel -r requirements.txt --wheel-dir=$tempdir
72+
$ cwd=`pwd`
73+
$ (cd "$tempdir"; tar -cjvf "$cwd/bundled.tar.bz2" *)
74+
```
75+
76+
Installing from the bundle, on a modern Unix system:
77+
78+
```
79+
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
80+
$ (cd $tempdir; tar -xvf /path/to/bundled.tar.bz2)
81+
$ python -m pip install --force-reinstall --no-index --no-deps $tempdir/*
82+
```
83+
````
84+
85+
Note that such a wheelhouse contains compiled packages, which are typically
86+
OS and architecture-specific, so these archives are not necessarily portable
87+
across machines.
88+
89+
Hash-checking mode can also be used along with this method (since this uses a
90+
requirements file as well), to ensure that future archives are built with
91+
identical packages.
92+
93+
```{warning}
94+
Beware of the `setup_requires` keyword arg in {file}`setup.py`. The (rare)
95+
packages that use it will cause those dependencies to be downloaded by
96+
setuptools directly, skipping pip's protections. If you need to use such a
97+
package, see {ref}`Controlling setup_requires <controlling-setup-requires>`.
98+
```

docs/html/user_guide.rst

Lines changed: 2 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ installed by pip in any particular order.
122122
In practice, there are 4 common uses of Requirements files:
123123

124124
1. Requirements files are used to hold the result from :ref:`pip freeze` for the
125-
purpose of achieving :ref:`repeatable installations <Repeatability>`. In
125+
purpose of achieving :doc:`topics/repeatable-installs`. In
126126
this case, your requirement file contains a pinned version of everything that
127127
was installed when ``pip freeze`` was run.
128128

@@ -762,86 +762,7 @@ is the latest version:
762762
Ensuring Repeatability
763763
======================
764764

765-
pip can achieve various levels of repeatability:
766-
767-
Pinned Version Numbers
768-
----------------------
769-
770-
Pinning the versions of your dependencies in the requirements file
771-
protects you from bugs or incompatibilities in newly released versions::
772-
773-
SomePackage == 1.2.3
774-
DependencyOfSomePackage == 4.5.6
775-
776-
Using :ref:`pip freeze` to generate the requirements file will ensure that not
777-
only the top-level dependencies are included but their sub-dependencies as
778-
well, and so on. Perform the installation using :ref:`--no-deps
779-
<install_--no-deps>` for an extra dose of insurance against installing
780-
anything not explicitly listed.
781-
782-
This strategy is easy to implement and works across OSes and architectures.
783-
However, it trusts PyPI and the certificate authority chain. It
784-
also relies on indices and find-links locations not allowing
785-
packages to change without a version increase. (PyPI does protect
786-
against this.)
787-
788-
Hash-checking Mode
789-
------------------
790-
791-
Beyond pinning version numbers, you can add hashes against which to verify
792-
downloaded packages::
793-
794-
FooProject == 1.2 --hash=sha256:2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824
795-
796-
This protects against a compromise of PyPI or the HTTPS
797-
certificate chain. It also guards against a package changing
798-
without its version number changing (on indexes that allow this).
799-
This approach is a good fit for automated server deployments.
800-
801-
Hash-checking mode is a labor-saving alternative to running a private index
802-
server containing approved packages: it removes the need to upload packages,
803-
maintain ACLs, and keep an audit trail (which a VCS gives you on the
804-
requirements file for free). It can also substitute for a vendor library,
805-
providing easier upgrades and less VCS noise. It does not, of course,
806-
provide the availability benefits of a private index or a vendor library.
807-
808-
For more, see
809-
:ref:`pip install\'s discussion of hash-checking mode <hash-checking mode>`.
810-
811-
.. _`Installation Bundle`:
812-
813-
Installation Bundles
814-
--------------------
815-
816-
Using :ref:`pip wheel`, you can bundle up all of a project's dependencies, with
817-
any compilation done, into a single archive. This allows installation when
818-
index servers are unavailable and avoids time-consuming recompilation. Create
819-
an archive like this::
820-
821-
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
822-
$ python -m pip wheel -r requirements.txt --wheel-dir=$tempdir
823-
$ cwd=`pwd`
824-
$ (cd "$tempdir"; tar -cjvf "$cwd/bundled.tar.bz2" *)
825-
826-
You can then install from the archive like this::
827-
828-
$ tempdir=$(mktemp -d /tmp/wheelhouse-XXXXX)
829-
$ (cd $tempdir; tar -xvf /path/to/bundled.tar.bz2)
830-
$ python -m pip install --force-reinstall --ignore-installed --upgrade --no-index --no-deps $tempdir/*
831-
832-
Note that compiled packages are typically OS- and architecture-specific, so
833-
these archives are not necessarily portable across machines.
834-
835-
Hash-checking mode can be used along with this method to ensure that future
836-
archives are built with identical packages.
837-
838-
.. warning::
839-
840-
Finally, beware of the ``setup_requires`` keyword arg in :file:`setup.py`.
841-
The (rare) packages that use it will cause those dependencies to be
842-
downloaded by setuptools directly, skipping pip's protections. If you need
843-
to use such a package, see :ref:`Controlling
844-
setup_requires<controlling-setup-requires>`.
765+
This is now covered in :doc:`../topics/repeatable-installs`.
845766

846767
.. _`Fixing conflicting dependencies`:
847768

0 commit comments

Comments
 (0)