Python setuptoolsを使用したインストール後のスクリプト


97

ユーザーがコマンドを実行できるように、setuptools setup.pyファイルの一部としてインストール後のPythonスクリプトファイルを指定することは可能ですか?

python setup.py install

ローカルプロジェクトファイルアーカイブ上、または

pip install <name>

PyPIプロジェクトの場合、スクリプトは標準のsetuptoolsインストールの完了時に実行されますか?単一のPythonスクリプトファイルでコーディングできるポストインストールタスクを実行したいと考えています(たとえば、カスタムのポストインストールメッセージをユーザーに配信し、別のリモートソースリポジトリから追加のデータファイルをプルします)。

数年前からこのSOの回答に出くわしましたが、そのトピックに対応しており、その時点での合意は、インストールサブコマンドを作成する必要があるということのようです。それでもそうである場合、ユーザーがスクリプトを実行するために2番目のコマンドを入力する必要がないように、これを行う方法の例を誰かが提供することは可能ですか?


4
ユーザーに2番目のコマンドの入力を要求するのではなく、スクリプトの実行を自動化したいと思っています。何かご意見は?
Chris Simpkins 2013年

1
:これは、あなたが探しているものかもしれませんstackoverflow.com/questions/17806485/...
limp_chimp

1
ありがとうございました!私はそれをチェックします
Chris Simpkins 2014年

1
これが必要な場合は、簡単なグーグルで見つけたこのブログ投稿は便利だと思われます。(ドキュメントのSetuptoolsの拡張と再利用もご覧ください。)
abarnert '27

1
@Simonまあ、あなたはおそらくこの問題の誰かが望んでいないものについての4年前のコメントを見ているので、それが実際に監視され、最新の状態に保たれるとは期待できません。これが答えである場合、それらを置き換えるための新しいリソースを見つける努力の価値がありますが、そうではありません。古い情報が必要な場合は、常にウェイバックマシンを使用するか、現在のドキュメントで同等のセクションを検索できます。
abarnert

回答:


92

注:以下のソリューションは、ソース配布のzipまたはtarballをインストールする場合、またはソースツリーから編集可能なモードでインストールする場合にのみ機能します。バイナリホイールからインストールする場合は機能しません.whl


このソリューションはより透過的です。

にいくつか追加します setup.py行い、追加のファイルは必要ありません。

また、2つの異なるポストインストールを検討する必要があります。1つは開発/編集可能モード用で、もう1つはインストールモード用です。

インストール後のスクリプトを含むこれらの2つのクラスをに追加しますsetup.py

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install


class PostDevelopCommand(develop):
    """Post-installation for development mode."""
    def run(self):
        develop.run(self)
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION

class PostInstallCommand(install):
    """Post-installation for installation mode."""
    def run(self):
        install.run(self)
        # PUT YOUR POST-INSTALL SCRIPT HERE or CALL A FUNCTION

関数にcmdclass引数を挿入します:setup()setup.py

setup(
    ...

    cmdclass={
        'develop': PostDevelopCommand,
        'install': PostInstallCommand,
    },

    ...
)

インストール前の準備を行う次の例のように、インストール中にシェルコマンドを呼び出すこともできます。

from setuptools import setup
from setuptools.command.develop import develop
from setuptools.command.install import install
from subprocess import check_call


class PreDevelopCommand(develop):
    """Pre-installation for development mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        develop.run(self)

class PreInstallCommand(install):
    """Pre-installation for installation mode."""
    def run(self):
        check_call("apt-get install this-package".split())
        install.run(self)


setup(
    ...

PS setuptoolsで利用可能なインストール前のエントリポイントはありません。なぜ何もないのか疑問に思っているなら、この議論を読んでください。


他よりきれいに見えますが、これは実際のコマンドの前にカスタムコードを実行しませんinstallか?
ラフィネス2016年

7
それはあなた次第です。最初runに親を呼び出す場合、コマンドはポストインストールです。それ以外の場合は、プレインストールです。これを反映するように答えを更新しました。
kynan

1
このソリューションを使用すると、install_requires依存関係が無視されるようです
ealfonso

6
これは私にとってはうまくいきませんでしたpip3。インストールスクリプトは、パッケージの公開時に実行されましたが、インストール時には実行されませんでした。
Eric Wiener

1
@JuanAntonioOrozco Wayback Machineを使用してリンク切れを更新しました。この瞬間になぜ壊れたのかわかりません。たぶん今、bugs.python.orgに何か問題があります。
mertyildiran

13

注:以下のソリューションは、ソース配布のzipまたはtarballをインストールする場合、またはソースツリーから編集可能なモードでインストールする場合にのみ機能します。バイナリホイールからインストールする場合は機能しません.whl


これは、インストール後のスクリプトでパッケージの依存関係が既にインストールされている必要がある場合に機能する唯一の方法です。

import atexit
from setuptools.command.install import install


def _post_install():
    print('POST INSTALL')


class new_install(install):
    def __init__(self, *args, **kwargs):
        super(new_install, self).__init__(*args, **kwargs)
        atexit.register(_post_install)


setuptools.setup(
    cmdclass={'install': new_install},

atexitインストール手順の後に単にインストール後の関数を呼び出すのではなく、なぜハンドラーを登録するのですか?
キナン

1
@kynan setuptoolsかなり文書化されていないので。他の人たちはすでに、このQ&Aに対する回答を正しい解決策で修正しています。
アパラーラ

3
さて、他の答えは私にはうまくいきません:インストール後のスクリプトが実行されないか、依存関係がもう処理されません。これまでのところ、私はに固執するだろうatexitし、ない再定義するinstall.run()(これは、依存関係がもはや処理されない理由です)。さらに、インストールディレクトリを知るために、私は_post_install()のメソッドとしてnew_install、何にアクセスして何にアクセスできるかself.install_purelibを示しましたself.install_platlib(どちらを使用するかわかりませんがself.install_lib、奇妙ですが間違っています)。
zezollo 2017年

2
私も依存関係に問題があり、atexitがうまく
いき

7
ここでの方法はどれも、ホイールでは機能しないようです。ホイールはsetup.pyを実行しないため、メッセージはビルド時にのみ表示され、パッケージのインストール時には表示されません。
JCGB 2019年

7

注:以下のソリューションは、ソース配布のzipまたはtarballをインストールする場合、またはソースツリーから編集可能なモードでインストールする場合にのみ機能します。バイナリホイールからインストールする場合は機能しません.whl


解決策は、することができpost_setup.pysetup.pyのディレクトリ。post_setup.pyポストインストールを行う関数を含み、setup.py、適切な時にそれをインポートして起動するだけです。

setup.py

from distutils.core import setup
from distutils.command.install_data import install_data

try:
    from post_setup import main as post_install
except ImportError:
    post_install = lambda: None

class my_install(install_data):
    def run(self):
        install_data.run(self)
        post_install()

if __name__ == '__main__':
    setup(
        ...
        cmdclass={'install_data': my_install},
        ...
    )

post_setup.py

def main():
    """Do here your post-install"""
    pass

if __name__ == '__main__':
    main()

setup.pyそのディレクトリから起動するという一般的な考えでは、インポートすることができますpost_setup.py、空の関数を起動します。

ではpost_setup.py、このif __name__ == '__main__':ステートメントにより、コマンドラインからポストインストールを手動で起動できます。


4
私の場合、オーバーライドするrun()とパッケージの依存関係がインストールされません。
Apalala

1
@Apalalaは、間違ったものcmdclassが交換されたため、これを修正しました。
キナン

1
ああ、最後に、私たちは正しい答えを見つけます。なぜ間違った答えがStackOverflowで非常に多くの票を獲得するのですか?確かに、あなたはあなたを実行する必要がpost_install() 後にinstall_data.run(self)そうでなければ、いくつかのものが欠落することがあります。data_files少なくとも好きです。キナンありがとうございます。
personal_cloud

1
私にはうまくいきません。どういうわけか、install_data私の場合、コマンドは実行されていません。では、atexitどのような状況でも、インストール後のスクリプトが最後に実行されることを確実にする利点はありませんか?
zezollo 2017年

3

@ Apalala、@ Zulu、@ mertyildiranの回答を組み合わせる。これはPython 3.5環境で私のために働きました:

import atexit
import os
import sys
from setuptools import setup
from setuptools.command.install import install

class CustomInstall(install):
    def run(self):
        def _post_install():
            def find_module_path():
                for p in sys.path:
                    if os.path.isdir(p) and my_name in os.listdir(p):
                        return os.path.join(p, my_name)
            install_path = find_module_path()

            # Add your post install code here

        atexit.register(_post_install)
        install.run(self)

setup(
    cmdclass={'install': CustomInstall},
...

これにより、でパッケージのインストールパスにアクセスして、install_pathシェル作業を行うこともできます。


2

ポストインストールを実行し、要件を維持する最も簡単な方法は、次の呼び出しを装飾することだと思いますsetup(...)

from setup tools import setup


def _post_install(setup):
    def _post_actions():
        do_things()
    _post_actions()
    return setup

setup = _post_install(
    setup(
        name='NAME',
        install_requires=['...
    )
)

これはsetup()宣言時に実行されsetupます。要件のインストールが完了すると、_post_install()関数が実行され、内部関数が実行されます_post_actions()


1
やってみましたか?私はPython 3.4で試しており、インストールは正常に動作しますが、post_actionsは実行されません...
dojuba

1

atexitを使用する場合、新しいcmdclassを作成する必要はありません。setup()呼び出しの直前にatexitレジスタを作成するだけです。同じことをします。

また、最初に依存関係をインストールする必要がある場合、pipがパッケージを移動する前にatexitハンドラーが呼び出されるため、これはpip install では機能しませ


ここに投稿されたいくつかの提案のように、これは「インストール」モードで実行しているかどうかを考慮していません。これが、カスタムの「コマンド」クラスが採用されている理由です。
BuvinJ

0

提示された推奨事項で問題を解決できなかったので、ここで私を助けました。

次のようsetup()setup.py、インストール直後に実行したい関数を呼び出すことができます:

from setuptools import setup

def _post_install():
    <your code>

setup(...)

_post_install()
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.