Python 3.8.3 loosens ensurepip's dependency on pip internals
ensurepip now runs pip as a module instead of relying on its internal main function. The change matters most when distributors update the bundled installer independently.
The standard library needs a way to install pip without depending on the location of pip's internal entry function. Python 3.8.3, released on May 13, includes a small change to that integration. ensurepip now invokes pip through runpy. This reduces the coupling between the interpreter's bootstrap code and the implementation of its bundled package installer.
The maintenance notes describe the benefit as easier pip updates for CPython and distributors. The change does not replace Python's packaging system. It removes one particular assumption that made two separately developed components harder to update together.
I find Python's packaging machinery disproportionately complicated. This repair is useful because it removes a dependency on an internal function without introducing another public packaging workflow. The improvement concerns how the existing bootstrap operation is implemented.
Bundling makes the original failure narrower
In issue 38662, Pradyun Gedam explains that the previous implementation assumed pip exposed a callable main function at a particular location. A change in pip 19.3 made that assumption relevant to updates of the bundled wheel. A maintainer changing the wheel could also need to revise the code invoking it.
The discussion distinguishes this from existing installations suddenly breaking when a newer pip appears elsewhere. ensurepip installs the wheel that it already bundles. Its existing invocation and bundled version therefore remain paired. A new pip release does not change that pair automatically.
This distinction matters for interpreting a maintenance release. The issue concerns reducing friction when that bundled component changes. It is not evidence that every previous Python installation can no longer bootstrap pip. The identity of the code being run determines whether a changed internal entry point is relevant.
The distributor case makes the cost more obvious. Miro Hrončok describes Fedora updating pip frequently and supporting multiple pip versions. Depending on an internal function means a distributor must track implementation changes that are unrelated to the intended command-line operation. The issue records that practical motivation alongside CPython's own need to refresh bundled wheels.
The released implementation executes a module
The Python 3.8.3 source for ensurepip shows _run_pip adding supplied wheel paths to sys.path. It saves the current argument list, supplies pip's arguments, and uses the following invocation.
runpy.run_module("pip", run_name="__main__", alter_sys=True)
That expression runs the module using the main-module convention. The surrounding code catches SystemExit and returns its status code. A finally block restores the saved argument list. If pip does not exit, the helper raises SystemError, making that unexpected control flow explicit.
This is an internal implementation excerpt, not a suggested replacement for an application's packaging command. Its purpose is to execute the bundled installer without importing a private main function. Argument handling and exit handling remain part of the adapter, so changing the entry mechanism does not eliminate all integration work.
The same source makes the bootstrap's input concrete. It retrieves bundled wheel data, writes the wheels into a temporary directory, and constructs their import paths. It then invokes pip with install, --no-index and --find-links pointing at that directory. Package selection comes from the bundled projects. The invocation change leaves that arrangement visible.
Configuration and process state still belong to the bootstrap
ensurepip deliberately ignores pip environment settings during this operation. The released code removes environment variables whose names begin with PIP_ and sets PIP_CONFIG_FILE to the null device. That makes the bootstrap's configuration distinct from an ordinary interactive pip invocation using a user's configuration.
The Python API's docstring also warns that bootstrapping alters sys.path and os.environ. Running through runpy does not turn the helper into a subprocess or make those changes disappear. The implementation's argument restoration is a specific cleanup action. It is not a promise that all process state remains untouched.
These details explain why the adapter remains necessary even after the internal main-function import is gone. The bootstrap chooses its bundled inputs and installation arguments, then manages how the installer runs inside that process. The change gives pip control over its own module entry point while preserving ensurepip's responsibility for the bootstrap environment.
I prefer this narrower dependency. The standard library needs pip's install operation, and pip should be able to rearrange the functions implementing that operation. Making the boundary match the existing executable module reduces the amount of pip implementation knowledge that CPython and distributors must preserve.
What an update becomes simpler to change
The issue's stated goal is to make a wheel update less dependent on the location of pip's main function. That does not establish compatibility with every possible future pip behaviour. The surrounding code still supplies particular arguments and expects an exit status. Those remain concrete integration assumptions.
For this release, the improvement is identifiable in the source. Wheel extraction and the local installation arguments stay in ensurepip, while pip's module entry point determines how its command executes. A distributor refreshing the bundled installer has one fewer internal function dependency to reconcile with that update.