ベンダーポリシー¶
ベンダーライブラリは、ベンダー処理を成功させるために必要な場合を除き、**変更してはなりません**。
ベンダーライブラリは、PyPIで入手可能なライブラリのリリース版**でなければなりません**。
ベンダーライブラリは、MITライセンスでリリースされている
pip
に統合することを許可するライセンスで**利用可能でなければなりません**。ベンダーライブラリには、LICENSEファイルが**添付されていなければなりません**。
pipでベンダー処理されたライブラリのバージョンは、
pip/_vendor/vendor.txt
に**反映されていなければなりません**。ベンダーライブラリは、
2to3
やCコードのコンパイルなどのビルドステップなしで機能する**必要があり**ます。実際には、これはシングルソースの2.x/3.xと純粋なPythonに限定されます。ライブラリに加えられた変更は、
pip/_vendor/README.rst
に**記録する必要があり**、対応するパッチはtools/vendoring/patches
に**含める必要があり**ます。ベンダーライブラリには、
pip/_vendor/__init__.py
にvendored()
のエントリが対応する必要があります。
理由¶
歴史的に、pipはsetuptools
自体を除いて依存関係を持っていませんでした。代わりに、依存関係を必要とせずに必要な機能を実装することを選択していました。しかし、pip 1.5から、pip内部で実装されていたコードをPyPIからの再利用可能なライブラリに置き換え始めました。これにより、より高品質でより実戦テスト済みのコード、バグ修正(特にセキュリティ関連のもの)の一元化、より少ない労力でより良い/多くの機能など、ライブラリを再利用することの一般的な利点がもたらされました。
しかし、従来の方法(install_requires
経由)で依存関係を持つことには、いくつかの問題があります。これらの問題は次のとおりです。
- 脆弱性
pipが機能するために別のライブラリに依存している場合、何らかの理由でそのライブラリがインストールされていないか、互換性のないバージョンがインストールされている場合、pipは機能しなくなります。これはもちろん、すべてのPythonアプリケーションに当てはまりますが、pip以外のすべてのアプリケーションでは、修正方法はpipを再実行することです。明らかに、pipが実行できない場合、pipを使用してpipを修正することはできません。そのため、依存関係を手動で解決して手動でインストールする必要があります。
- 他のライブラリのアンインストールを不可能にする
pipの現在の依存関係の1つは
requests
ライブラリであり、pipは実行するためにかなり新しいバージョンを必要とします。pipが従来の方法でrequests
に依存している場合、私たちはこれまで存在した(そしてこれからも存在する)すべてのrequests
バージョンとの互換性を維持するか、またはpipが特定のバージョンのrequests
のアンインストールを不可能にすることを許可するかのどちらかを選択しなければなりません。(2番目の問題は、技術的にはすべてのPythonアプリケーションに当てはまりますが、pipの普及によって拡大されます。pipは、Python、pyvenv
、virtualenv
でデフォルトでインストールされます。)- セキュリティ
これは一見奇妙に思えるかもしれませんが、ベンダー処理はセキュリティアップデートのために依存関係の更新を複雑にする傾向があり、それはpipにも当てはまります。しかし、依存関係を避けるための他の理由を考えると、代替案はpipが自分で車輪の再発明を行うことです。これはpipが歴史的に行ってきたことです。これは、pipが独自のHTTPS検証ルーチンを再実装することを余儀なくさせ、Python標準ライブラリのSSL検証の欠如の回避策として機能しました。これは、
requests
とurllib3
の検証ルーチンで同様のバグが発生しましたが、それらは独立して発見および修正される必要がありました。ベンダー処理を行っているにもかかわらず、ライブラリの再利用により、依存関係の優れた作業に依存することでpipのセキュリティが向上し、依存関係の新しいバージョンを簡単に取り込むことで、より迅速で簡単なセキュリティ修正が可能になります。- ブートストラッピング
現在、pipをインストールする最も一般的な方法は、pipの自己完結性を利用してpip自体をインストールすることに依存しています。これらのツールは、pipのコピーをバンドルし、
sys.path
に追加し、そのpipのコピーを実行することによって機能します。(重複を減らすための)「ミニインストーラー」を実装する代わりに、pipはすでにPythonパッケージのインストール方法を知っており、あらゆる「ミニインストーラー」よりもはるかに実戦テスト済みです。
多くの下流の再配布者は、この種のバンドリングに対してポリシーを持っており、代わりに、配布するソフトウェアにパッチを適用してバンドルを解除し、すでにパッケージ化されているソフトウェアのグローバルバージョン(独自の修正が適用されている可能性があります)に依存するようにします。(pipチームは)、上記の理由により、pipがこの方法でバンドル解除されないことを望んでおり、代わりに現在のままのままであることを望んでいます。
長期的に、誰かが上記の解決策に対して、現在使用しているバンドル方法以外の、不合理な追加の問題を追加しないポータブルな解決策を持っている場合、私たちは喜んで検討し、おそらくその方法に切り替えるでしょう。この解決策は、pipが使用されることを期待するすべての状況で正しく機能し、OSパッケージなどの外部メカニズムを義務付けるものであってはなりません。
修正¶
setuptools
は、pkg_resources
のみを保持するために完全に削除されています。pkg_resources
は、依存関係をpip._vendor
からインポートし、appdirs
ではなくplatformdirs
のベンダー処理されたコピーを使用するように変更されています。packaging
は、依存関係をpip._vendor
からインポートするように変更されています。CacheControl
は、依存関係をpip._vendor
からインポートするように変更されています。requests
は、他の依存関係をpip._vendor
からインポートし、simplejson
(すべてのプラットフォーム)とpyopenssl
(Windows)をロードしないように変更されています。platformdirs
は、サブモジュールをpip._vendor.platformdirs
からインポートするように変更されています。
自動ベンダー処理¶
ベンダー処理は、pip/_vendor/vendor.txt
の内容とtools/vendoring/patches
内のさまざまなパッチからvendoringツールを使用して自動化されます。vendoring sync . -v
で起動します(vendoring>=0.2.2
が必要です)。ツールの設定はpyproject.toml
で行います。
ローカルパッチの管理¶
vendoring
ツールはローカルパッチを自動的に適用しますが、パッチの更新が正常に適用されない場合があります。その場合、更新は失敗します。この問題を解決するには、次の手順を実行します。
クリーンな出発点を確認するために、revendoringブランチの不完全な変更を元に戻します。
問題のあるライブラリを再度revendoringします。
nox -s vendoring -- --upgrade <library_name>
。これも失敗しますが、作業ディレクトリに元のソースがあります。ソースに対して既存のパッチを確認し、パッチを修正してソースの新しいバージョンを反映します。
git add
を使用してvendoringが行った変更を追加した場合、ソースを変更してパッチファイルを反映し、git diff
で新しいパッチを生成できます。パッチファイルの変更を除くすべての変更を元に戻します。変更されたパッチファイルはステージングせずに、作業ツリーに保存しておきます。
ベンダー処理を再実行します。今回は、変更されたパッチファイルが検出され、クリーンに適用されるはずです。パッチファイルの変更は、ベンダー処理の再実行と共にコミットされるため、新しいコミットはテストとPRとして公開する準備が整います。
デバンドル¶
根拠で述べたように、pipチームとしては、pipをデバンドルしない(オプションでpip/_vendor/requests/cacert.pem
を除く)ことを、そしてpipをそのままにしておくことを好みます。しかし、どうしてもデバンドルする必要がある場合は、(CIではテストしていない)準サポートの方法があります。これは、上記の問題を解決するために、お客様側で少し追加作業が必要になります。
pip/_vendor/
内のすべてのファイルを削除します。pip/_vendor/__init__.py
とpip/_vendor/vendor.txt
は**除きます**。パッチを適用したライブラリの各コピーを使用して、pipの依存関係(およびそれらの依存関係)のホイールを生成します。これらは、pipがアクセスできるファイルシステム上の場所に配置する必要があります(
pip/_vendor
がデフォルトの想定場所です)。pip/_vendor/__init__.py
を修正して、DEBUNDLED
変数をTrue
にします。インストール時に、pip自身の
dist-info
ディレクトリ内のINSTALLER
ファイルはpip
以外の値に設定する必要があります。これにより、pipは自身を使用してインストールされなかったことを検出できます。(オプション)ホイールを
pip/_vendor/
以外の場所に配置した場合は、pip/_vendor/__init__.py
を修正して、WHEEL_DIR
変数が配置した場所を指すようにします。(オプション)最新の利用可能なpipのバージョンを決定し、正しいアップグレードメッセージをユーザーに表示するための適切なロジックを使用して
pip_self_version_check
ロジックを更新します。
部分的なデバンドルは**サポートされていません**。正常にデバンドルするには、すべての依存関係のホイールを準備する必要があります。