pip icon indicating copy to clipboard operation
pip copied to clipboard

PEP 517 build process fails to take credential from interactive session

Open chrihartl opened this issue 4 years ago • 7 comments

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

  1. Have an internal Artifactory server that mirrors PyPi packages and a user/password.
  2. Use a pip.conf as described above (index-url pointing to the Artifactory server, but without user/password info in the URL)
  3. 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

chrihartl avatar Nov 18 '21 15:11 chrihartl

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).

chrihartl avatar Nov 18 '21 15:11 chrihartl

Btw the workaround for this is to use --no-build-isolation. Which of course negates all the benefits of the nice PEPs...

sbor23 avatar Aug 15 '22 12:08 sbor23

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.

NiklasRosenstein avatar Sep 26 '22 13:09 NiklasRosenstein

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.

Darsstar avatar May 23 '23 08:05 Darsstar