ベンダーポリシー

  • ベンダーライブラリは、ベンダー処理を成功させるために必要な場合を除き、**変更してはなりません**。

  • ベンダーライブラリは、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__.pyvendored()のエントリが対応する必要があります。

理由

歴史的に、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、pyvenvvirtualenvでデフォルトでインストールされます。)

セキュリティ

これは一見奇妙に思えるかもしれませんが、ベンダー処理はセキュリティアップデートのために依存関係の更新を複雑にする傾向があり、それはpipにも当てはまります。しかし、依存関係を避けるための他の理由を考えると、代替案はpipが自分で車輪の再発明を行うことです。これはpipが歴史的に行ってきたことです。これは、pipが独自のHTTPS検証ルーチンを再実装することを余儀なくさせ、Python標準ライブラリのSSL検証の欠如の回避策として機能しました。これは、requestsurllib3の検証ルーチンで同様のバグが発生しましたが、それらは独立して発見および修正される必要がありました。ベンダー処理を行っているにもかかわらず、ライブラリの再利用により、依存関係の優れた作業に依存することで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ツールはローカルパッチを自動的に適用しますが、パッチの更新が正常に適用されない場合があります。その場合、更新は失敗します。この問題を解決するには、次の手順を実行します。

  1. クリーンな出発点を確認するために、revendoringブランチの不完全な変更を元に戻します。

  2. 問題のあるライブラリを再度revendoringします。nox -s vendoring -- --upgrade <library_name>

  3. これも失敗しますが、作業ディレクトリに元のソースがあります。ソースに対して既存のパッチを確認し、パッチを修正してソースの新しいバージョンを反映します。 git addを使用してvendoringが行った変更を追加した場合、ソースを変更してパッチファイルを反映し、git diffで新しいパッチを生成できます。

  4. パッチファイルの変更を除くすべての変更を元に戻します。変更されたパッチファイルはステージングせずに、作業ツリーに保存しておきます。

  5. ベンダー処理を再実行します。今回は、変更されたパッチファイルが検出され、クリーンに適用されるはずです。パッチファイルの変更は、ベンダー処理の再実行と共にコミットされるため、新しいコミットはテストとPRとして公開する準備が整います。

デバンドル

根拠で述べたように、pipチームとしては、pipをデバンドルしない(オプションでpip/_vendor/requests/cacert.pemを除く)ことを、そしてpipをそのままにしておくことを好みます。しかし、どうしてもデバンドルする必要がある場合は、(CIではテストしていない)準サポートの方法があります。これは、上記の問題を解決するために、お客様側で少し追加作業が必要になります。

  1. pip/_vendor/内のすべてのファイルを削除します。pip/_vendor/__init__.pypip/_vendor/vendor.txtは**除きます**。

  2. パッチを適用したライブラリの各コピーを使用して、pipの依存関係(およびそれらの依存関係)のホイールを生成します。これらは、pipがアクセスできるファイルシステム上の場所に配置する必要があります(pip/_vendorがデフォルトの想定場所です)。

  3. pip/_vendor/__init__.pyを修正して、DEBUNDLED変数をTrueにします。

  4. インストール時に、pip自身のdist-infoディレクトリ内のINSTALLERファイルはpip以外の値に設定する必要があります。これにより、pipは自身を使用してインストールされなかったことを検出できます。

  5. (オプション)ホイールをpip/_vendor/以外の場所に配置した場合は、pip/_vendor/__init__.pyを修正して、WHEEL_DIR変数が配置した場所を指すようにします。

  6. (オプション)最新の利用可能なpipのバージョンを決定し、正しいアップグレードメッセージをユーザーに表示するための適切なロジックを使用してpip_self_version_checkロジックを更新します。

部分的なデバンドルは**サポートされていません**。正常にデバンドルするには、すべての依存関係のホイールを準備する必要があります。