web-dev-qa-db-ja.com

distutils / setuptoolsを使用してPythonスクリプトポストインストールを実行します。

Python distutilsに記載されているように 単純なポストインストールスクリプトでdistutilsを拡張する方法は? にポストインストールタスクを追加しようとしています。タスクはインストールされたlibディレクトリーでPythonスクリプトを実行します。このスクリプトは、追加のPythonインストールされたパッケージに必要なモジュールを生成します。

私の最初の試みは次のとおりです:

from distutils.core import setup
from distutils.command.install import install

class post_install(install):
    def run(self):
        install.run(self)
        from subprocess import call
        call(['python', 'scriptname.py'],
             cwd=self.install_lib + 'packagename')

setup(
 ...
 cmdclass={'install': post_install},
)

このアプローチは機能しますが、私の知る限り、2つの欠点があります。

  1. ユーザーがPATHから取得したもの以外のPythonインタープリターを使用した場合、ポストインストールスクリプトは異なる問題を引き起こす可能性のあるインタプリタ。
  2. 関数でラップしてdistutils.cmd.Command.executeで呼び出すことで解決できる可能性のある、模擬実行などに対して安全ではありません。

どうすればソリューションを改善できますか?これを行うための推奨される方法/ベストプラクティスはありますか?可能であれば、別の依存関係を引き込まないようにしたいと思います。

31
kynan

これらの欠陥に対処する方法は次のとおりです。

  1. setup.pyからsys.executableを実行するPythonインタプリタへの完全パスを取得します。
  2. distutils.cmd.Commandから継承するクラス(ここで使用するdistutils.command.install.installなど)は、executeメソッドを実装します。このメソッドは、特定の関数を「安全な方法」で実行します。つまり、ドライランフラグを尊重します。

    ただし、 --dry-runオプションは現在壊れている であり、意図したとおりに機能しないことに注意してください。

私は次の解決策に終わりました:

import os, sys
from distutils.core import setup
from distutils.command.install import install as _install


def _post_install(dir):
    from subprocess import call
    call([sys.executable, 'scriptname.py'],
         cwd=os.path.join(dir, 'packagename'))


class install(_install):
    def run(self):
        _install.run(self)
        self.execute(_post_install, (self.install_lib,),
                     msg="Running post install task")


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

python setup.py --help-commandsが使用するので、派生クラスにはクラス名installを使用していることに注意してください。

34
kynan

ポストインストールを実行し、要件を維持する最も簡単な方法は、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
Mbm