PEP 517 build process fails to take credential from interactive session
Description
My pip.conf is:
[global]
cert = /path/to/cert-bundle.crt
index-url = https://<internal-server>/artifactory/api/pypi/pypi/simple
As the index-url does not contain user/password information, I ususally get a prompt when installing a package, and it works fine:
(venv) pip install pytz
Looking in indexes: https://<internal-server>/artifactory/api/pypi/pypi/simple
User for <internal-server>: me
Password:
Collecting pytz
Downloading https://<internal-server>/artifactory/api/pypi/pypi/packages/packages/.../pytz-2021.3-py2.py3-none-any.whl (503 kB)
|████████████████████████████████| 503 kB 5.6 MB/s
Installing collected packages: pytz
Successfully installed pytz-2021.3
However, when I try to pip install krb5, I am initially asked for username and password, then it starts to collect the package; but then it triggers installation of build dependencies, and this fails, because the "deep process" also runs pip, and this would again require a password prompt, but I am not actually asked to provide input. Therefore the process fails with EOFError: EOF when reading a line.
See the full output further down.
(The error handling is also suboptimal in this case: On the first error it believes that krb5-0.2.0 is not available on the internal server, and repeats the same exercise looking for other versions.)
Expected behavior
I would expect that either pip somehow caches the provided credentials for subsequent calls, or, if not, that it again prompts the user to provide the credentials.
pip version
21.3.1
Python version
3.6
OS
Centos (Docker), Windows
How to Reproduce
- Have an internal Artifactory server that mirrors PyPi packages and a user/password.
- Use a pip.conf as described above (index-url pointing to the Artifactory server, but without user/password info in the URL)
- Run
pip install krb5(or probably other packages that trigger build dependencies using wheel)
Output
(venv) pip install krb5
Looking in indexes: https://<internal-server>/artifactory/api/pypi/pypi/simple
User for <internal-server>: me
Password:
Collecting krb5
Using cached https://<internal-server>/artifactory/api/pypi/pypi/packages/packages/.../krb5-0.2.0.tar.gz (1.1 MB)
Installing build dependencies ... error
ERROR: Command errored out with exit status 2:
command:
/path/to/venv/bin/python3 \
/path/to/venv/lib64/python3.6/site-packages/pip install \
--ignore-installed --no-user --prefix /tmp/pip-build-env-.../overlay \
--no-warn-script-location --no-binary :none: --only-binary :none: \
-i https://<internal-server>/artifactory/api/pypi/pypi/simple -- \
'setuptools >= 40.6.0' wheel
cwd: None
Complete output (58 lines):
Looking in indexes: https://<internal-server>/artifactory/api/pypi/pypi/simple
User for <internal-server>: ERROR: Exception:
Traceback (most recent call last):
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/cli/base_command.py", line 164, in exc_logging_wrapper
status = run_func(*args)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/cli/req_command.py", line 205, in wrapper
return func(self, options, args)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/commands/install.py", line 339, in run
reqs, check_supported_wheels=not options.target_dir
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/resolution/resolvelib/resolver.py", line 93, in resolve
collected.requirements, max_rounds=try_to_avoid_resolution_too_deep
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/resolvelib/resolvers.py", line 482, in resolve
state = resolution.resolve(requirements, max_rounds=max_rounds)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/resolvelib/resolvers.py", line 349, in resolve
self._add_to_criteria(self.state.criteria, r, parent=None)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/resolvelib/resolvers.py", line 173, in _add_to_criteria
if not criterion.candidates:
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/resolvelib/structs.py", line 151, in __bool__
return bool(self._sequence)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 155, in __bool__
return any(self)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 143, in <genexpr>
return (c for c in iterator if id(c) not in self._incompatible_ids)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py", line 44, in _iter_built
for version, func in infos:
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/resolution/resolvelib/factory.py", line 272, in iter_index_candidate_infos
hashes=hashes,
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/package_finder.py", line 857, in find_best_candidate
candidates = self.find_all_candidates(project_name)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/package_finder.py", line 805, in find_all_candidates
page_candidates = list(page_candidates_it)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/sources.py", line 134, in page_candidates
yield from self._candidates_from_page(self._link)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/package_finder.py", line 765, in process_project_url
html_page = self._link_collector.fetch_page(project_url)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/collector.py", line 492, in fetch_page
return _get_html_page(location, session=self.session)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/collector.py", line 397, in _get_html_page
resp = _get_html_response(url, session=session)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/index/collector.py", line 131, in _get_html_response
"Cache-Control": "max-age=0",
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/requests/sessions.py", line 555, in get
return self.request('GET', url, **kwargs)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/network/session.py", line 454, in request
return super().request(method, url, *args, **kwargs)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/requests/sessions.py", line 542, in request
resp = self.send(prep, **send_kwargs)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/requests/sessions.py", line 662, in send
r = dispatch_hook('response', hooks, r, **kwargs)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_vendor/requests/hooks.py", line 31, in dispatch_hook
_hook_data = hook(hook_data, **kwargs)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/network/auth.py", line 270, in handle_401
username, password, save = self._prompt_for_password(parsed.netloc)
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/network/auth.py", line 233, in _prompt_for_password
username = ask_input(f"User for {netloc}: ")
File "/path/to/venv/lib64/python3.6/site-packages/pip/_internal/utils/misc.py", line 202, in ask_input
return input(message)
EOFError: EOF when reading a line
----------------------------------------
WARNING: Discarding https://<internal-server>/artifactory/api/pypi/pypi/packages/packages/.../krb5-0.2.0.tar.gz#sha256=...
(from https://<internal-server>/artifactory/api/pypi/pypi/simple/krb5/) (requires-python:>=3.6).
Command errored out with exit status 2:
/path/to/venv/bin/python3 \
/path/to/venv/lib64/python3.6/site-packages/pip install \
--ignore-installed --no-user --prefix /tmp/pip-build-env-4.../overlay \
--no-warn-script-location --no-binary :none: --only-binary :none: \
-i https://<internal-server>/artifactory/api/pypi/pypi/simple -- \
'setuptools >= 40.6.0' wheel
Check the logs for full command output.
[Repeats with 0.1.2 and 0.1.1, but fails in the same way, of course.]
ERROR: Could not find a version that satisfies the requirement krb5 (from versions: 0.1.1, 0.1.2, 0.2.0)
ERROR: No matching distribution found for krb5
Code of Conduct
- [X] I agree to follow the PSF Code of Conduct.
I should mention that this problem does not happen, if the pip.conf instead looks like this:
[global]
cert = /path/to/cert-bundle.crt
index-url = https://<user>:<password/token>@<internal-server>/artifactory/api/pypi/pypi/simple
I.e. if the pip.conf itself contains an index-url INCLUDING credentials, then it works (as expected).
Btw the workaround for this is to use --no-build-isolation. Which of course negates all the benefits of the nice PEPs...
I just ran into this as well. Passing the index URL with credentials as an argument to Pip works, too. But it would be nice if the credentials that were prompted interactively in the beginning would be passed to the isolated build.
Pip 23.1 has improved keyring support, which might be a similar solution/workaround as passing a URL with credentials, but can be a bit more set-and-forget. (You'll likely want the subprocess backend.