どのように、私は詩パッケージマネージャーのバイナリ版を作りましたか


ほぼ1年前、私はバイナリの実行可能ファイルを生産し始めたPoetry , Python用のパッケージマネージャ.ここでどのように、どのように私はそれを作った技術的な深いダイビングです.

詩パッケージマネージャー
Started by Sébastien Eustace , 詩はすぐに開始された-良い理由-人気のパッケージと依存関係の管理ツールPythonシーンでは、おかげでPEP 518 と標準化されたpyproject.toml マニフェスト.

python-poetry / poetry
Python依存関係の管理と包装が容易になりました.
詩は本当に彼らの依存性から、出版物への依存性から、彼らのPythonプロジェクトを管理する開発者の何千人も役立ちます.
そして、同じ文脈の中でそこに多くのプロジェクトとして、詩はPythonで書かれています.これは本当に意味を持ちます:Pythonコードと依存関係に対処しなければなりません、そして、詩で働くことは明らかにあなたがすでに完全に働くPython環境を持っていることを意味します.
しかし、常に-しかし、-これはまた、詩自体はほとんどあなたのマシン、VMやあなたのコードを実行しているDockerコンテナに持っているPython環境に引き締めることを意味します.そして、これは必ずしもそれ自体で問題ではありませんが、それはまだいくつかのケースで問題を生成することができます.

問題
そして、ここではまた、詩のバイナリバージョンを作成するという考えの背後にある理論的根拠があります.
私がいくつかのラインを返したので、詩はあなたのマシンでセットアップ環境に依存します.もちろん、詩の背後のチームは、Pythonパッケージの観点からすべてを修正しましたvirtual environment プロジェクトとパッケージの残りの部分から詩を分離するために作成されます.しかし、Pythonの仮想環境はまだPythonの実行可能なライブラリと環境が構築されたライブラリにリンクされています.そしてなぜこれは問題ですか?いくつかのプラットフォームでは、Pythonディストリビューションのアップグレードは、そのディストリビューションから生成された仮想環境を壊します.
例えばMacOSでは、Pythonのインストールを扱う典型的な方法はHomebrew . しかし、BusinessがあなたのPythonバージョンをあなたの詩インストールにアップグレードするとき、何が起こりますか?それはおそらく壊れます.そして、あなたは詩を再インストールする必要があります.
また、Pythonのインストールを管理する方法の変更点は、あなたの詩のインスタンスに影響を与えます.
では、どうやってこれを解決しますか?我々は完全にシステムの1つの詩の環境を分離する方法が必要です.

Pyoxidizerプロジェクト
今のところ、詩はCLIですので、すべての相互作用は、コードにアクセスする必要はありません、私たちはただ、詩コード、その依存関係のすべて、およびPythonインタプリタを含むいくつかの実行可能ファイルを生成する方法が必要です.
ここでどこPyOxidizer プロジェクトGregory Szorc スーパーハンディ.プロジェクトの説明を引用するには、次の手順に従います.

PyOxidizer is a utility for producing binaries that embed Python [...] PyOxidizer is capable of producing a single file executable - with a copy of Python and all its dependencies statically linked and all resources (like .pyc files) embedded in the executable. You can copy a single executable file to another machine and run a Python application contained within. It just works.



indygreg / PyOxidizer
最新のPythonアプリケーションパッケージと配布ツール
しかし、どのように動作しますか?一旦あなたのシステムにPyoxidizerをインストールしたら、すべてはStarlark ファイル
def make_exe():
    dist = default_python_distribution(python_version="3.9")

    policy = dist.make_python_packaging_policy()
    policy.resources_location_fallback = "filesystem-relative:lib"

    config = dist.make_python_interpreter_config()
    config.module_search_paths = ["$ORIGIN/lib"]
    config.run_module = "poetry.console.application"

    exe = dist.to_python_executable(
        name="poetry",
        packaging_policy=policy,
        config=config,
    )
    exe.add_python_resources(exe.pip_install(["./poetry"]))

def make_install(exe):
    files = FileManifest()
    files.add_python_resource(".", exe)
    return files

register_target("exe", make_exe)
register_target("install", make_install, depends=["exe"], default=True)

resolve_targets()
この内容でpyoxidizer.bzlpoetry ソースコードフォルダpyoxidizer build --release バイナリファイルがビルドフォルダの下で生成されます.
そうですか.まあ実際にはNo .

コード化酸化
Pyoxidizerプロジェクトを使用する際には、いくつかの警告があります.主な理由は、輸入業者がPythonで提供された標準的なものではなく、Pyoxidizerプロジェクトによって提供されるカスタムのものです.これは完全に意味を持ちます:通常、あなたのPythonコードで何かを輸入することは、Aを探すことを意味します.ファイルシステムのPYファイルですが、バイナリ実行可能ファイルを作成しているので、Pythonファイルの内容はファイルシステムには存在しません.
さて、ここでの主な問題は、Pythonコミュニティの長い歴史があることです__file__ リソースにアクセスするか、パッケージを動的にインポートする変数です.この変数は、一致するPythonソースファイルのパスが存在しないため、PyoxIdizerで値を保持しません.
これを考えるthe compliance of the oxidized importer 一般的にPyoxidizerでいくつかのオプションがあります:
  • すべてのコードを変換するコードをパッチします__file__ 何か他のものへのインスタンスimportlib.resources 図書館
  • 強制的にこれらの内容をファイルとして保存し、元のPythonの輸入業者に戻る
  • つのアプローチの違いは全く明らかです.後者はあまり努力を必要としませんが、それを実行するときに実行可能ファイルがその周辺の他のファイルを必要とすることも意味します.そして、それらのファイルが誰でも編集可能であることを意味します.
    そして、これは私が詩コードとその依存性をパッチするのを選んだ理由です.

    すべてのパッチ
    あなたが見るならばthe patches in my repository , いくつかの観測を行うことができます.
  • があるimportlib_metadata パッチは、埋め込まれたPythonのバージョンが3.9であってもimportlib.metadata モジュールです.これはimportlib.metadata PyoxIdizerプロジェクトでの実装は、完全実装しませんDistribution インターフェースと、いくつかの依存関係がそのインターフェースへの呼び出しを行う
  • そのためのパッチがあるrequests パッケージ.これはrequests パッケージはSSL証明書をcertifi リソースローダの代わりにパスを使う
  • the virtualenv パッチは巨大です.これは、詩が非常に多くのvirtualenv パッケージ、そしてこれはファイルシステムでたくさん働くように設計されています
  • the poetry-core パッチは主にファイルシステムにいくつかのリソースファイルが存在することを期待する外部依存関係に準拠する必要があります
  • 我々が見るならばpoetry パッチファイルは、Python環境を処理する際に、いくつかの詩の振る舞いを変更するために多数のコードが含まれていることがわかります.具体的に言えば、詩の環境処理は標準的な「システム」Python配布物を持つことを期待します.
    さて、詩は、この環境をプロジェクトVirtualEnvを構築するための可能な実装の一つとして使用しているので、“外部”Pythonディストリビューションを常に見るようにロジックを変更する必要がありました.

    すべてをまとめる
    最終的には、最終的なバイナリを生成するステップは以下の通りです.

  • forking the code パッチを必要とする
  • 適用するpatches
  • にPyoxidizerを教えてくださいinstall the patched code pypiで利用できる標準パッケージの代わりに
  • 追加some magic ファイルシステム上で必要な特別なリソースを扱うには
  • それならばwriting the Github workflow すべての異なるプラットフォームのバイナリを生成するには.

    gi0baro / poetry-bin
    詩バイナリビルド
    といくつかのボーナスポイントを追加します.
  • Homebrew formula
  • いくつかDocker images 詩に
  • エーGithub action 詩のバイナリ版を設定するには

  • 最後の考察
    プロセスに関係するすべてを振り返って、私はちょうどいくつかの最終的な考えを残したいです.
    まず第一に、詩プロジェクトは確かにPython依存関係の管理シーンでゲームチェンジャーだったので、バティエンとその努力のためのすべてのチームを教えてください!
    第二に、Pyoxidizerプロジェクトは、少なくともPythonコードからバイナリを生成する方法です.このプロジェクトをすべての利用可能なソリューションに比較すると、疑いのない私を残します:デザイン、原則、正確さとPyoxidizerのドキュメントは、単に競争と比較して異なるレベルにあります.グレゴリーへの功績
    では、Pythonコードをバイナリにコンパイルしてください.そして、さらに重要なこと-それは面倒な価値がありますか?
    もちろん、それはもちろん異なります.
    Python CLIプロジェクトが既にある場合は、Python環境を必要としてPyoxIdizerで配布するのをやめることができます.これはまた、互換性コードを回避する利点を与えます.サポートする必要がある唯一のPythonバージョンは、プロジェクトで埋め込むものです.
    場合は、新しいプロジェクトを起動している場合は、Pythonと一緒に、さびのようなコンパイルされた言語では快適ですし、行ゼロから、Pyoxidizerの要件を尊重するコードを書くことができます、確かに、なぜですか?これは私がしたことですnoir .
    しかし、依存関係やコードの数十を持っている場合は、制御できません.あなたのコントロールのあまりにも多くのことは、不要なバグを生成することができます、今日はまだ非常にあなたの酸化した唯一のコードがどのように動作するかをテストするのは難しいです.そして、あなたがまだそれを作りたい場合には、私はあなたに少なくとも__file__ 使用するので、次の人がこれをしようとすると再全体のパッチプロセスを歩く必要はありません.
    そして、覚えておいてください:バイナリを作ることはあなたが特定のアーキテクチャとプラットホームを目標とすることを意味します、したがって、インタプリタを持つすべてのシステムで働いたPythonコードは全く同じアーキテクチャとプラットホームでコンパイルされません.
    最後に、私はあなたの使用ケースとあなたの聴衆を正確に定義することを提案することができます.“私はこれをコンパイルする必要がありますか?”簡単になります.
    歓声
    //