Search code examples
pythonpipvirtualenvpython-wheelpython-venv

Control the pip version in virtualenv


How do I control the version of pip which is used in a freshly created venv?

By default, it uses a vendored pip distribution which may be out of date or unsuitable for whatever other reason. I want to be able to create a venv with a user-specified version of pip installed initially, as opposed to creating one and then upgrading the pip installation from within the env.


Solution

  • Since Python 3.9 the stdlib venv module has EnvBuilder.upgrade_dependencies. Unfortunately, it has two shortcomings:

    • Won't really help users to install a specific pip version, only the latest.
    • It still installs the vendored pip and setuptools versions first, and then uninstall them if they're outdated, which they almost always will be in practice.

    It would be ideal to install the latest versions directly! The venv CLI provides a --without-pip argument that is useful here. You can use this to opt-out of the vendored pip, and then actually use the vendored pip wheel to install your desired pip version instead (along with any other packages you might want in a freshly created virtual environment).

    It's best to put it into a function - this goes into your shell profile or rc file:

    function ve() {
        local py="python3"
        if [ ! -d ./.venv ]; then
            echo "creating venv..."
            if ! $py -m venv .venv --prompt=$(basename $PWD) --without-pip; then
                echo "ERROR: Problem creating venv" >&2
                return 1
            else
                local whl=$($py -c "import pathlib, ensurepip; [whl] = pathlib.Path(ensurepip.__path__[0]).glob('_bundled/pip*.whl'); print(whl)")
                echo "boostrapping pip using $whl"
                .venv/bin/python $whl/pip install --upgrade pip setuptools wheel
                source .venv/bin/activate
            fi
        else
            source .venv/bin/activate
        fi
    }
    

    As written, this function just pulls latest pip, setuptools, and wheel from index. To force specific versions you can just change this line of the shell script:

    .venv/bin/python $whl/pip install --upgrade pip setuptools wheel
    

    Into this, for example:

    .venv/bin/python $whl/pip install pip==19.3.1
    

    For Python 2.7 users, you may do a similar trick because virtualenv provides similar command-line options in --no-pip, --no-setuptools, and --no-wheel, and there is still a vendored pip wheel available to bootstrap since Python 2.7.9. Pathlib will not be available, so you'll need to change the pathlib usage into os.path + glob.