virtualenvとpipが嫌いな理由

私は、virtualenv(以降-venv)とpipの普遍的な愛を共有しません。 それらは混乱を引き起こすだけでなく、害を及ぼすと信じています。 Pythonプログラマーはほとんどの場合私に反対し、venv + pipは事実上Pythonコミュニティの標準と見なされています。 自分の発言が根拠のないものであることがわかっているので、この論文を書くことにしました。 もちろん、私は実生活でこのトピックについて議論することがあります。まあ、私は人々を作り上げ、彼らがどれだけ情熱的に自分の立場を維持しているかを見るのが好きです。 しかし、同時に、口頭で自分の立場を完全に正当化することはできないように思えます。 したがって、私は自分の主張を常に口頭で証明しようとするのではなく、この記事を書くことにしました。 おそらく誰も同意しないので、多分それから私に同意する人もいるでしょう。 逆に、私の議論が完全に理解されるとすぐに、それらを合理的に反論する人がいるでしょう。 いずれにしても、私はどんなシナリオにも喜んでいるでしょう。



venvと分離の錯覚

メインオペレーティングシステムに隠された依存関係がない分離と簡単に再現可能な純粋なpython環境は間違いなく良いことです。 venvの主な目的は、便利なPythonレベルの分離方法を提供することです。 しかし、ここですべてが完璧というわけではありません。システムライブラリに依存するPythonパッケージの場合、分離は部分的にのみ実装され、これらのパッケージのpythonコンポーネントのみに拡張されます。 開発者がこれを認識していればそれほど悪くはありませんが、そうでない場合は深刻で理解できない問題に直面する可能性があります。



完全な分離方法は、venvの冗長性につながります

ファイルシステム全体を分離するには、いくつかの方法があります。 最も完全だが重い方法は、 ハイパーバイザーの下で仮想マシンを使用することです。 この機能は、Vagrantなどの多くのプログラムによって提供されます。 一方、chrootなどの軽量ソリューション、またはオペレーティングシステムレベルで動作する軽量コンテナがあります。たとえば、LinuxではLXCです。 さらに、LXCはbtrfsなどのコピーオンライトファイルシステムを使用して、venvの場合よりも高速でディスクスペースの少ない環境を作成できます。



venvはアンチデプロイメントパターンです

LXCなどのテクノロジーについて言及するとき、私は読者によってはイライラします。 はい、実際には、ターゲット環境とLXCの互換性を常に保証できるとは限りません。 また、LXCに必要なスーパー管理者権限を常に付与できるわけではありません(これは、単にアプリケーションを展開するだけです!)

しかし、私はvenvもデプロイメントに適さないと信じています。 なんで? 最初に述べたように、venvの最初の目的は、 インタラクティブに作成されたpythonサンドボックスへの便利なユーザーアクセスを提供することだけです。 展開は、少なくとも半自動で簡単に再現可能なプロセスです。 したがって、venvを自動化して、手動で行うほうが便利なことを自動的に実行しようとすると、プログラムのエントリポイントとしてPYTHONPATH環境変数を設定するだけでなく、より複雑で重要なタスクと思われます。 Djangoなどの巨大なパッケージをpip経由で任意のフォルダーにインストールするのは非常に簡単です(プレフィックスオプションを使用)。 少なくとも間接的にvenvを管理し、多数のシバンと混同するよりもはるかに簡単です 。 また、venvを使用すると、基本的にターゲット環境を制御できないことを忘れないでください。また、オペレーティングシステム自体にクライアントmysqlライブラリとヘッダーファイルをインストールするよう、展開先のコンピューターの管理者に丁寧に依頼する必要があります。 これはすべて、デプロイメント用にmysql-pythonを単純にコンパイルできるようにするためです!

商用ソフトウェアの配布は簡単ではなく、venvは役に立ちません。



venvは松葉杖でいっぱいです

venvをインストールするとき、実際には空ではありません。 標準のPythonライブラリ全体がlib /ディレクトリにコピーされます。 インクルード/-pythonヘッダーファイルの束。 これらのディレクトリの存在の意味は私には遠慮がちなようですが(次の段落で詳しく説明します)、bin /ははるかに迷惑です。 bin /には、pipとeasy_installがあります。 venvは、システムの下ではなく、同じディレクトリにあるPythonインタープリターの下で実行するために、両方のシェバンを台無しにします。 追加でインストールされたパッケージのShebangsおよび他のすべてのスクリプトは、まったく同じ方法で破損します。 そして、このvenvの振る舞いを維持し、シバンを常に監視する必要があります。一方、システムcronを介して実行するなど、venvの内部にあるスクリプトを操作する必要があります。 スクリプトが正しいインタープリターで実行されるように、適切なvenvへのパスをハードコードする必要があります。 これは、少なくともPATH / PYTHONPATHを手動で構成するのと同じくらい面倒です。 実際、何もしない方が簡単ですが、少し後で説明します。



ああ、私はビンを言及するのを忘れた/アクティベート

PATH環境変数を設定し、コンソールの入力行を変更します。 いつもこれが好きで、それが高度な技術だと思っていたなら、おめでとう、あなたは戦車に住んでいたように見えます。 ただし、スクリプトのように。 .NET Windows開発者はあなたを笑っています。



--no-site-packages

venvは2つの方法でsys.pathを台無しにします。 --sytem-site-packagesオプションは、venvのサイトパッケージを既存のパスリストの一番上に付加し、グローバルにインストールされたpythonモジュールをvenv内で使用できるようにします。 --no-site-packagesオプションもあります。これはデフォルトで有効になっており、ご想像のとおり、この添付は行いません。 どうやらこれが、stdlibやヘッダーファイルなどの一部のライブラリのコピーがvenv内にランダムにダンプされる理由です。 実際、このオプションの存在の事実、およびデフォルトで設定されているという事実は、私の意見では、それ自体を物語っています。 明らかに、venvの支持者は、システム上のパッケージとvenvの間に隠された依存関係を持ちたくありません。 間違ったバージョンのパッケージが誤ってvenvに漏れることを望んでいないためです。 ただし、それらのお気に入りのvenvは常にパスのリストの先頭に表示されるため、まだ少しのチャンスがあります(いや、 pip freezeコマンドについては忘れていません。これについては後で説明します)。 この恐れは不必要に思えるかもしれませんが、ここに逆説があります。 実際、venvは100%の分離を提供しませんでした! システムバージョンのmysql-pythonを使用していないことを100%確信しているのに、システムバージョンのlibmysqlclientを使用していることを100%確信しているのは良いことです。 部分的に断熱材を使用し、部分的に無視することは不可能です!



pipとvenvは素晴らしい束です

誰もが同じ人、イアン・ビッキングによって書かれているからこそそう思う。 両方のプログラムには、独自の哲学と独自のユースケースがあります。 私はvenvが人々を信じさせるので、ほとんどの部分は好きではありませんが、独自のニッチを持っていることを認めます。 実際、私自身は、短時間の1回限りのテストにそれを時々使用します。 しかし、一方でピップはまったく生まれるべきではありませんでした。 これは、easy_installの「ほぼ互換性のある」代替手段であり、追加機能はまったくありません。 代わりに、私はeasy_installを、puppetのようなインタラクティブではなく、一般的にソースからパッケージをコンパイルするようなプログラムと組み合わせて使用​​することを好みます。 私はピップに対して偏見を持っているように見えるかもしれませんが、そうではありません。 コンソールでpip installを記述する方がeasy_installよりもやや良いことに同意します。 easy_installはばかげているように聞こえます。 また、名前の下線は明らかに実用的ではありません。 名前だけでもピップの人気の一部を提供しているに違いない。



pipは毎回ソースからビルドします

pythonのはjavaのjarのようなものです
pipは、バイナリ(eggs)からパッケージをインストールするeasy_installの機能を意図的に奪われたようです。 バイナリの配布はpythonプラットフォームの重要な部分であり、ちなみに非常に機能的であるという事実にもかかわらず、誰かがこれは悪い考えだと判断しました。 もちろん、開発者の観点から見ると、ソースからパッケージをコンパイルすることは明らかな利点です。これにより、サポートされているすべてのプラットフォームごとにパッケージをプリコンパイルする必要がなくなります。 ただし、ターゲットプラットフォームがほとんどない場合はコンパイルが邪魔になります。ターゲットプラットフォームを確実に知っており、事前にパッケージをビルドしたい場合は、ターゲットコンピューターにコンパイラーを用意する必要がなくなります(.NETおよびJava開発者は再び問題を笑っています)。 しかし最大の馬鹿げたことは、-no-site-packagesオプションでvenvを使用すると、開発プロセス中にSOE内にvenvを展開するチームのすべてのメンバーが、 すべてのモジュールを再構築する必要があるたびにです。 そして、これは本当に馬鹿げています。なぜなら、あなたはそれらを開発すらしておらず、絶えず再組み立てするという意味ではまったくないからです。



このいまいましいrequirements.txt

パッケージに必要な依存関係を宣言するには、setup.pyのinstall_requiresでそれらを指定できます。 これがPythonの方法です。 setuptools / distributeはこのメカニズムを実装しており、easy_installとpipの両方で使用され、Pypiから自動的にダウンロードしてこれらの依存関係をインストールします。 説明に時間がかかりすぎるため、pipではテキストファイルで依存関係のリストを指定することもできます。 通常、requirements.txtと呼ばれます。 構文はsetup.pyとまったく同じですが、ファイルパス、 URI、さらにMercurial- / Gitリポジトリへのリンクとしても依存パスを指定できるファイルを追加添付する機能もあります(このすべてについて)次の段落で説明します)。



これらの機能が可能性を大きく広げることに同意しますが、requirements.txtが存在する理由だとは思いません。 私の意見では、本当の理由は、すべてのPythonプロジェクトが2つのクラスに分かれていることです。独立して使用されず、既存のプロジェクトにインポートされるだけのパッケージと、実際にはこれらのプロジェクト自体です。 アプリケーションのみを作成する開発者は、パッケージ作成のすべての機能を完全に理解していないため、よく考えることなく、使用するすべてのモジュールをアプリケーションに「ハードコーディング」し、requirements.txtにリストするだけです。 これらの開発者は、ほとんどの場合、単にvenvをインストールするようユーザーにアドバイスし、 pip install -r requirements.txtコマンドを使用してパッケージをロールします。



その結果、requirements.txtをすべての問題の万能薬と見なしている多くのPython開発者がいます。 彼らはsetuptoolsの存在についても知りません。 サイトやバージョン管理システムなど、インターネットのどこかにある必要なパッケージへのリンクの、一見単純な愚かな列挙に簡単に魅了されます。 このアプローチの「素晴らしい」プラグマティズムに対する彼らの神聖な自信と、すべての人にとって不可欠なツールのバンドルとしてvirtualenv + pipの使用を促進したいという欲求に失望しています。



依存関係のパスとしてのURI

setuptoolsを使用すると、パッケージの名前と必要なバージョンを指定できます。デフォルトでは、Pypiからダウンロードされます。 Pypiはインデックス付けを提供しますが、独自のインデックスを(単純なHTMLページの形式で)作成し、Pypi Webサイトからではなく、主にそれらから情報を抽出するように指示できます。 この技術を開発した人は誰でも、物理的な場所やWebプロトコルではなく、パッケージ名にバインドする機能を開発者に提供しようとしました。 そして彼は正しく考えました。



Requirements.txtでローカルファイルまたはWebサイトにあるtarballへのパスを指定する場合、実際にはこのリンクをハードコーディングします。 この場合、最善の解決策はパッケージリポジトリを使用することです。 これにより、たとえば、ローカルネットワークでミラーを構成できます。 さらに、最小バージョンを指定することはできません。 正確な現在のバージョンのみを指定してください。 そして、ある晴れた日には、パッケージと同じファイルが移動または削除され、一般的には消えてしまい、コードが突然機能しなくなります。 明らかに、これは必要ありませんよね?



さて、別の方法があります。 この方法で依存関係を指定しましょう:

git + https://github.org/my/stupid/fucking/package#egg=1.2.3



ただし、ユーザーがコンピューターにgitをインストールする必要があります。さらに、pipはリポジトリの完全なコピーをポンプアウトする必要があります。 そして、多くの場合、人々はバージョン付き表記をまったく使用しません(例では1.2.3-約Per。)。安定版はmasterブランチにあると仮定します。 これはすべて悲しいです。 バージョン管理システムから直接すべてを配置することが今では流行していることを知っていますが、これらのURLをプロジェクトに「ハードコア」しますか? すでに議論の余地のある決定であり、すべてが正しく行われれば、完全に不当なものになります。適切なsetup.pyのセットアップに少し汗をかきます。



ピップフリーズが好きなら、何かがおかしい

中毒の追跡と管理が得意です。 私はピップフリーズでこれを行います。 pip freezeコマンドは、開発サイクルの途中でPythonの依存関係が失われないようにするために使用されます。 pip freezeがrequirements.txtに挿入する依存関係のリストを提供すると信じている場合(これは必要ではないことを思い出します)-新しいvenvを作成するときに--no-site-packages(これも必要ありません)を使用しますまた、依存関係のセット全体は、Pythonではなくグローバルシステムで取得されます。 また、この方法では、どの依存関係が直接インストールされ、どの依存関係が他のユーザーによってプルアップされているかがわかりません。



一方、これらの依存関係が環境を破壊していることを発見したら、単純にそれを再作成してみてください。 しかし、venv + pipを使用すると、永遠にあなたを連れて行きます(私はあなたに、すべてを再構築する必要があることを思い出します)。 LXC CoWで既にバイナリeggパッケージにパッケージ化されている(現時点では作業していないすべての依存関係)が、システムレベルと直接pythonの両方で、不足している依存関係をすばやく見つけることができます。

一般的に、 ピップフリーズはそれほど悪いチームではありません。人々はそれをかけがえのないものとみなし、その欠点を考慮せずに他の目的に使用することがあまりにも多いということです。



おわりに

これは私の批評家ですが、完全に主観的であり、ある意味では、virtualenvとpipプログラムの両方の有用性とそれらを中心に開発されたプログラミング文化の論争的な分析です。 私は言語としてのpythonが本当に好きですが、パッケージ配布および開発プロセス標準のさまざまな標準によって断片化されているため、プラットフォームとしてはあまり好きではありません。 個人的に、私の場合、これは私がPythonと戦うよりもPythonと戦うことに多くの時間を費やすという事実につながります。 私は、venvとpipが既製のアプリケーションの開発、共同作業、デプロイに必要なすべてを提供すると心から信じているさまざまな賢い人々と定期的にコミュニケーションを取っています。 開発中にvenvまたはpipを使用しません。

そして、この記事が少なくともこれらのプログラムの動作原理を理解し、同時に批判することが可能であり、必要であることを読者に証明することを願っています。



翻訳者から:

Windowsで作業している開発者の場合:pipを放棄するか、すぐにパイプされたくないパッケージ(vcvarsall.batが見つからないというエラーが発生するパッケージなど)をインストールする方法を探しているかどうか、およびパッケージ開発者のサイトバージョンは提供されていません、私はその翼の下ですべての可能なバージョンでコンパイルされたすべての種類のパッケージを収集する素晴らしいサイトをアドバイスできます: Python拡張パッケージ用の非公式のWindowsバイナリ



All Articles