Context
There is a long history of discussions around, and issues with, the use of Pip in Conda environments. There are both legitimate needs for using Pip in a Conda environment and easy to make mistakes by users which break environments or applications when they are using pip
when then should have used conda
or mamba
.
Over the past few months there have been a number of threads on the Python packaging Discourse where Conda came up. For example:
- PEP 704 - Require virtual environments by default for package installers, which proposes a change which would be a significant backwards compat break in pip for conda users. Discourse thread
- The Wanting a singular packaging tool/vision thread
- The Python Packaging Strategy Discussion - Part 1 thread
- PEP 668 - Marking Python base environments as “externally managed” (a bit older). Discourse thread
-
This post specifically outlines the existing “knobs” available for tweaking how
pip
interacts with other package managers.
Rather than always pushing back with “this doesn’t work for conda”, Steve Dower suggested that the conda community should specify how it wants pip to behave inside conda envs (see https://discuss.python.org/t/wanting-a-singular-packaging-tool-vision/21141/149). That is not an easy question, but it would be great to see a coherent view indeed. This may, but doesn’t have to, include a request for new features from pip
or from Python packaging.
I’ll note that the question is broader than pip
- there are other Python package installers, and there are also topics like virtual environments and dependency specifiers that interact with conda
/mamba
or conda environments.
Usage scenarios
There are multiple reasons for users or tools wanting to use pip
or wheels from PyPI inside a conda environments:
- Installing Python packages from PyPI for which no conda package is available in
defaults
,conda-forge
or another channel, - Installing a package from source locally. This can be a development version of any package, even if it’s available as a release in a conda channel,
- Using an all-wheel workflow like
conda create -n my-devenv python=3.11
(which does installpip
in addition to python 3.11) followed bypip install a-bunch-of-pypi-pkgs
, - As part of the workflow for building conda packages:
-
recipe/build.sh
in a conda-forge feedstock is likely to contain something like${PYTHON} -m pip install . -vv
, as documented in Contributing packages — conda-forge 2023.02.09 documentation, - Another example: Contributing packages — conda-forge 2023.02.09 documentation
-
pip list
andpip check
are used too: Guidelines — conda-forge 2023.02.09 documentation - Note that the conda-forge automation ensures
--no-build-isolation
is used by default when usingpip
within a conda-forge build, in order to avoid problems when building packages with compiled extensions,
-
There is some basic guidance in the Conda docs for this:
- Managing packages — conda 23.1.0 documentation
- Managing environments — conda 23.1.0 documentation
- The docs also contain an example of using
pip
to install a package from PyPI as part of anenvironment.yml
file:
name: stats2
channels:
- javascript
dependencies:
- python=3.9
- bokeh=2.4.2
- conda-forge::numpy=1.21.*
- nodejs=16.13.*
- flask
- pip
- pip:
- Flask-Testing
- There is a
pip_interop_enabled
Improving interoperability with pip — conda 23.1.0.post38+278795193 documentation experimental mode forconda
. Unlike mostconda
features, this doesn’t seem to have an analog inmamba
(it’s possible thatmamba
already has the improved behavior hidden behind this flag, not sure).
On the other hand, pip
is often misused (especially by beginning users) when conda
or mamba
should be used instead. This is a very frequent source of broken environments and of bug reports to popular Python packages. The Spyder team even made a polished 3-minute video about this with the usual “avoid mixing pip
and conda
” advice. Even advanced Python users who are comfortable building from source tend to shoot themselves in the foot because they use pip install .
instead of pip install . --no-build-isolation
.
Another thing that leads to unpredictable results is iterative use of conda install
and pip install
in an environment - this tends to degrade and then break. If pip
usage is indeed warranted, it should be done once - any further updates require recreating the environment for reliable results (as documented under “Recreate the environment if changes are needed” in this section of the conda docs).
Conceptual issues with usage scenarios
One fairly fundamental problem here is that pip
is used for multiple purposes:
- Building a package from source, then installing it,
- Installing wheels from PyPI
- Package/dependency management
- Virtual environment creation/management: now for isolated builds, possibly more in the future.
conda
on the other hand has a single coherent purpose (installing a compatible set of built packages into an environment) but does not have a good “build from source” (or “developer”) story. The metadata in a Python package’s source tree (in pyproject.toml
) is not generic dependency metadata, it’s PyPI-specific. The mapping from PyPI dependencies to conda package dependencies happens in conda recipes, rather than in the project’s own VCS repo. Hence the need to use pip
, rather than a similar conda install .
.
So what conda users need from pip
is a subset of everything that pip
does, and it comes with a UX that isn’t ideal.
Some concrete questions to answer
- Should it be possible to use
pip
(and other installers likepypa/installer
) to install a Python package into a conda environment from a vcs checkout, an sdist, or a wheel?- answer RG: yes
- Also for the
base
environment?- answer RG: no, too fragile
- Should
pip
be able to uninstall/overwriteconda
packages, and vice versa?- answer RG: probably yes, users rely on this and there are valid usage scenarios, so making this work as smoothly as possible seems preferred over preventing this.
- Should a conda env be considered or marked as a virtual environment?
- answer RG: no, they’re clearly different beasts, this will lead to problems
Design changes?
Options given the current state of Python packaging and Pip include:
- Do/change nothing
- Protect the
base
environment better by addingEXTERNALLY-MANAGED
to it (see conda#12245) - Add
EXTERNALLY-MANAGED
to all environments, which makes users opt in to potential breakage by using a flag:pip install ... --break-system-packages
.- Optionally, provide an alternative installer (maybe even a renamed
pip
?) for the valid use cases that conda users have, like installing from source or installing packages that are not present in a conda channel.
- Optionally, provide an alternative installer (maybe even a renamed
Options for future design changes that would require Pip or Python packaging changes include:
-
pip
not installing dependencies that are available as conda packages. E.g., ifpip install my-niche-package
contains a dependency onnumpy
, thenpip
should not installnumpy
(it could either error out with an informative message, or - very futuristic, and probably hard - installnumpy
withconda
/mamba
) - Shared metadata, or metadata mapping, such that the
pyproject.toml
dependencies would be fully translatable to conda packages.- This would make it easier to do things like
conda install .
spinning up an isolated conda env with conda build dependencies, rather than a virtual environment with packages installed from wheels, - It would also make it easier for projects to not have multiple
environment.yml
,requirements.txt
, etc. files (there’s already a PyPI-only issue here, because there is no such thing aspip install . --only-deps
and there should be), - Equivalently, the
environment.yaml
andrequirements.txt
formats could converge.
- This would make it easier to do things like
- Generalize the concept of virtual environments, so tools that use them can more easily support conda environments as well (think of pip/tox/nox/asv/etc. here; anything that automatically creates a temporary or permanent venv)
- ?
Other specific requests for pip
or Python packaging as a whole?
- No breakage for scenarios that work today (so “no” to PEP 704’s idea of requiring a virtual environment to install into).
- ?
Relevant open issues
This is an incomplete list, but touches on some of the more important open issues:
- Editable installs (
pip install -e .
) doesn’t interact well with conda: conda#5861 - Add an EXTERNALLY-MANAGED file to base environment: conda#12245
-
conda env export
tends to not be robust when PyPI packages are present: conda#9624 -
pip_interop_enabled
issues: conda#11177, conda#12242,
Next steps
The above is a start at a summary; it’d be great to discuss here as well as in an upcoming conda community meeting (as proposed by @beckermr in the conda Element channel), expand this doc, and then turn it into (a) doc improvements in conda/mamba/conda-forge docs, and (b) in something that can be presented as a “think is what the conda community thinks or would like” to the PyPA & https://discuss.python.org/ crowd.