nikkie-ftnextの日記

イベントレポートや読書メモを発信

Pythonのvenvの--upgrade-depsオプションは、どこから来てどこへ行くのか

はじめに

ぶっ飛ばせ!! nikkieです😭

先日言語処理学会Python仮想環境の話題があり、以下のツイートに多くの反響をいただきました。
情報量を増やした記事を書きます。
ただし、すぐ役に立つ部分で言うとツイートを超える情報はなく、なぜこのオプションが追加されたのか、どう実装されているのかを見ていく内容です。

目次

venvの--upgrade-depsオプション

Python標準ライブラリの中で仮想環境の作成を担うvenvモジュール。

Python 3.9から--upgrade-depsオプションを指定できるようになりました。
仮想環境の中のpipsetuptoolsを最新にします

このオプション、『Python実践レシピ』きっかけで知りました1
仮想環境を有効にした後にpip install -U pip setuptoolsと叩く必要がなくなるので、愛用しています。

どこから来たのか

はじまりの

Author: Cooper Lees (cooperlees) 2018-08-31 15:25

I'd like to propose add a --upgrade to venv module to automatically update pip and potentially setuptools if supplied.

This will allow me to skip my next command that I usually always do:
/tmp/awesome_venv/bin/pip install --upgrade pip setuptools

提案者cooperleesさんも毎回pip install -U pip setuptoolsされていたようですね。

このスレッドでは特に議論はなく、以下のプルリクがマージされています。

どう実装されているのか(ごく簡単に)

--upgrade-depsが指定されると、仮想環境を作るロジック2の中で以下の分岐が実行されます:
https://github.com/python/cpython/blob/v3.11.8/Lib/venv/__init__.py#L85-L86

if self.upgrade_deps:
    self.upgrade_dependencies(context)

呼び出されている関数はこちら:
https://github.com/python/cpython/blob/v3.11.8/Lib/venv/__init__.py#L454-L459

def upgrade_dependencies(self, context):
    self._call_new_python(context, '-m', 'pip', 'install', '--upgrade',
                          *CORE_VENV_DEPS)

_call_new_python()メソッドですが、
https://github.com/python/cpython/blob/v3.11.8/Lib/venv/__init__.py#L341
標準ライブラリのsubprocessを使って、渡したコマンドを実行しています3

subprocess.check_output(args, **kwargs)

つまり、--upgrade-depsを指定すると、仮想環境を作る中でpip install --upgrade pip setuptoolsがsubprocessで実行される!という理解です。

どこへ行くのか

このたびドキュメントを見ていて気づいたのですが、

バージョン 3.12 で変更: setuptools is no longer a core venv dependency.

Python 3.12からは--upgrade-depspipのみ最新化に変わったようです。

プルリクエストはこちら

CORE_VENV_DEPSという変数が指すタプルは、('pip', 'setuptools')から('pip',)に変わりました。

Issueはこちら

setuptoolsを削除した理由は、インストールワークフローを標準に近づけるためだそうです。

in an environment where setuptools is installed but wheel is not (such as one created with python -m venv), pip falls back on running the deprecated and non-standard setup.py install.

意訳「(例えばpython -m venvで作られるような)setuptoolsがインストールされwheelがインストールされていない環境では、pipは非推奨で非標準的なsetup.py installを実行するようにフォールバックしてしまう

pip 22.1からsetuptoolsのない環境でpipが正しく動くようになったので、

So, in order to progressively expose more users to standard-based installation workflows, we (the pip team) would like that virtual environments are created without setuptools by default.

意訳「漸進的により多くのユーザに標準に基づいたインストールワークフローを経験させるために、私たちpip開発チームは仮想環境をデフォルトでsetuptoolsなしで作られるようにしたい

終わりに

venvの--upgrade-depsオプションについて、なぜ追加されたのか、どう実装されているのか、最新の状況を見てきました。

  • 仮想環境を作る際、pip install pip setuptoolsのひと手間をなくすためにPython 3.9で爆誕
  • 実装では、subprocessでpip install --upgrade pip setuptoolsしている(仮想環境構築の中で自動化した)
  • Python 3.12からはsetuptoolsがvenvで作る仮想環境からなくなり4、pipのみ最新化するオプションとなった

「--upgrade-depsオプション便利〜」と愛用してましたが、経緯や実装を知れて満足です。
そうか、subprocessで叩いちゃえばいいのか。


  1. その時の記事
  2. main()関数の中でEnvBuilderのcreate()メソッドが呼ばれています https://github.com/python/cpython/blob/v3.11.8/Lib/venv/__init__.py#L546
  3. https://docs.python.org/ja/3/library/subprocess.html#subprocess.check_output
  4. gh-95299: Do not pre-install setuptools in virtual environments created with venv.https://docs.python.org/ja/3/whatsnew/3.12.html#summary-release-highlights