Backend loaded from system-wide location when virtual environment is created with `--system-site-packages`
See original GitHub issueDescription
Recently I was looking into a curious bug reported to setuptools (pypa/setuptools#3240) and while studying it,
I found that the setuptools backend was being loaded from a different location that I would expect when users run pip install .
, with pip
being provided by python3 -m venv --system-site-packages
.
I am not sure this is even related to pip
itself of if the behaviour is intended, but maybe you guys have some idea on what can be causing it?
Expected behavior
When a package is installed via pip install .
I would expect that the backend is loaded from either:
- A transient virtual environment created by
pip
itself, were all the build dependencies are installed according to PEP 517 - The virtual environment containing
pip
itself (in case of no isolation).
When pip is installed via python3 -m venv --system-site-packages
, it seems that pip
is trying to reach out for the backend in the system’s site-packages, even when the backend is installed (with the correct version) inside the virtual environment providing pip.
pip version
22.0.4
Python version
3.10.4
OS
Ubuntu 20.04.4 LTS. Also tested in containers: python:3.10-alpine3.14, python:3.10-bullseye
How to Reproduce
In this replication I have selected an Alpine container, so we don’t have to think about the Debian/setuptools-specific _distutils_system_mod.py
hook, but the same behaviour can be observed in python:3.10-bullseye
> docker run --rm -it python:3.10-alpine3.14 /bin/ash
A. Create a project with a specific version of setuptools. Set a virtual environment that fulfils the build dependencies.
mkdir /tmp/proj
cd /tmp/proj
cat <<EOS > pyproject.toml
[build-system]
requires = ['setuptools==47']
build-backend = 'setuptools.build_meta'
EOS
cat <<EOS > setup.cfg
[metadata]
name = proj
version = 42
EOS
python3 -m venv --system-site-packages .venv
.venv/bin/python -m pip install -U pip 'setuptools==47'
.venv/bin/python -m pip list
# Package Version
# ---------- -------
# pip 22.0.4
# setuptools 47.0.0
# wheel 0.37.1
Here I choose setuptools 47 because it is a version that does not try to mess with .pth
files (but the same behaviour can be observed with all the recent versions of setuptools).
.venv/bin/python3 -c 'import setuptools; print(setuptools.__version__)'
# 47.0.0
ls .venv/lib/python3.10/site-packages/*.pth
# ls: .venv/lib/python3.10/site-packages/*.pth: No such file or directory
B. Install an older version of setuptools in the system wide Python installation (outside of the virtual environment)
python3 -m pip uninstall -y setuptools
python3 -m pip install 'setuptools==39'
# Meanwhile the version inside the virtual environment is intact:
.venv/bin/python -c 'import setuptools; print(setuptools.__version__)'
# 47.0.0
C. Run the installation and see it failing because the wrong version of setuptools is loaded from outside the virtual environment.
.venv/bin/python -m pip install .
From the backtrace we can see the frontend/installer is trying to load setuptools from /usr/local/lib/python3.10/site-packages/setuptools/__init__.py
(outside of the environment).
Here I am using setuptools==39
just because I want to show the installation failing loudly, but even if we use more recent versions of setuptools
the backend would still be loaded from the system’s site-packages
(or dist-packages
). It is just more difficult to show the evidence (see https://github.com/pypa/setuptools/issues/3240#issuecomment-1086627416 for more details).
Output
Processing /tmp/proj
Installing build dependencies ... done
Getting requirements to build wheel ... error
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> [38 lines of output]
Traceback (most recent call last):
File "/tmp/proj/.venv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 363, in <module>
main()
File "/tmp/proj/.venv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 345, in main
json_out['return_val'] = hook(**hook_input['kwargs'])
File "/tmp/proj/.venv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 124, in get_requires_for_build_wheel
backend = _build_backend()
File "/tmp/proj/.venv/lib/python3.10/site-packages/pip/_vendor/pep517/in_process/_in_process.py", line 89, in _build_backend
obj = import_module(mod_path)
File "/usr/local/lib/python3.10/importlib/__init__.py", line 126, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 992, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 688, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 883, in exec_module
File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
File "/usr/local/lib/python3.10/site-packages/setuptools/__init__.py", line 12, in <module>
import setuptools.version
File "/usr/local/lib/python3.10/site-packages/setuptools/version.py", line 1, in <module>
import pkg_resources
File "/usr/local/lib/python3.10/site-packages/pkg_resources/__init__.py", line 77, in <module>
__import__('pkg_resources.extern.packaging.requirements')
File "/usr/local/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py", line 9, in <module>
from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException
File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
File "<frozen importlib._bootstrap>", line 1006, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 672, in _load_unlocked
File "<frozen importlib._bootstrap>", line 632, in _load_backward_compatible
File "/usr/local/lib/python3.10/site-packages/pkg_resources/extern/__init__.py", line 43, in load_module
__import__(extant)
File "/usr/local/lib/python3.10/site-packages/pkg_resources/_vendor/pyparsing.py", line 943, in <module>
collections.MutableMapping.register(ParseResults)
AttributeError: module 'collections' has no attribute 'MutableMapping'
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
error: subprocess-exited-with-error
× Getting requirements to build wheel did not run successfully.
│ exit code: 1
╰─> See above for output.
note: This error originates from a subprocess, and is likely not a problem with pip.
Code of Conduct
- I agree to follow the PSF Code of Conduct.
Issue Analytics
- State:
- Created a year ago
- Comments:8 (3 by maintainers)
Top GitHub Comments
Consolidating into #6264.
I’m not sure it’s an OR. If it is, then I’d like to split things into two separate issues instead of one. It was @abravalheri’s comment on that issue, that suggested to me that this is an AND relationship.