Skip to content

ensurepip looks for wheels in CWD when WHEEL_PKG_DIR is an empty string #146310

Description

@zahlman

Bug description:

Until and in 3.12, ensurepip stored the sysconfig.get_config_var('WHEEL_PKG_DIR') result verbatim as a string in _WHEEL_PKG_DIR, and used os functionality to list wheels in the specified directory.

Since 3.13 (tested on 3.14 but I also reviewed the 3.13 library code), the config value (when not None) is normalized to a pathlib.Path, and the .glob method of that is used instead.

This causes a different behaviour when the returned value (as is the case for my local source builds) is an empty string ('', not None):

>>> import os
>>> os.listdir('')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
FileNotFoundError: [Errno 2] No such file or directory: ''

>>> from pathlib import Path
>>> Path('')
PosixPath('.')
>>> Path('').glob('*')
<generator object Path.glob at 0x7c06678cc590>

Therefore, ensurepip will now bootstrap from the process' CWD, if it contains a suitable pip wheel. And a renamed file that is not a valid pip wheel can theoretically just crash:

$ touch pip-is-not-in-here.whl
$ py3.14 -m ensurepip
Traceback (most recent call last):
  File "<string>", line 6, in <module>
    runpy.run_module("pip", run_name="__main__", alter_sys=True)
    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen runpy>", line 222, in run_module
  File "<frozen runpy>", line 142, in _get_module_details
ImportError: No module named pip
Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/opt/python/standard/lib/python3.14/ensurepip/__main__.py", line 5, in <module>
    sys.exit(ensurepip._main())
             ~~~~~~~~~~~~~~~^^
  File "/opt/python/standard/lib/python3.14/ensurepip/__init__.py", line 257, in _main
    return _bootstrap(
        root=args.root,
    ...<4 lines>...
        default_pip=args.default_pip,
    )
  File "/opt/python/standard/lib/python3.14/ensurepip/__init__.py", line 172, in _bootstrap
    return _run_pip([*args, "pip"], [os.fsdecode(tmp_wheel_path)])
  File "/opt/python/standard/lib/python3.14/ensurepip/__init__.py", line 87, in _run_pip
    return subprocess.run(cmd, check=True).returncode
           ~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/opt/python/standard/lib/python3.14/subprocess.py", line 577, in run
    raise CalledProcessError(retcode, process.args,
                             output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/usr/local/bin/py3.14', '-W', 'ignore::DeprecationWarning', '-c', '\nimport runpy\nimport sys\nsys.path = [\'/tmp/tmpc9p5g7z_/pip-is-not-in-here.whl\'] + sys.path\nsys.argv[1:] = [\'install\', \'--no-cache-dir\', \'--no-index\', \'--find-links\', \'/tmp/tmpc9p5g7z_\', \'pip\']\nrunpy.run_module("pip", run_name="__main__", alter_sys=True)\n']' returned non-zero exit status 1.

Actually this behaviour is useful for me (I want to test bootstrapping some modified versions of pip), but it does seem to represent an un-documented change that could break things for someone else.

(Actually I wonder if it is really os.listdir('') that should have been changed forever ago. After all, a '' entry in sys.path does work!)

CPython versions tested on:

3.14

Operating systems tested on:

No response

Linked PRs

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14bugs and security fixes3.15pre-release feature fixes, bugs and security fixestopic-ensurepiptype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions