web-dev-qa-db-ja.com

distutils:ユーザー定義のパラメーターをsetup.pyに渡す方法は?

コマンドラインとsetup.cfg構成ファイルの両方からユーザー定義パラメーターをdistutilsのsetup.pyスクリプトに渡す方法を教えてください。パッケージ固有のパラメーターを受け入れるsetup.pyスクリプトを書きたいのですが。例えば:

python setup.py install -foo myfoo

ありがとうございました、

59
Mher

Setuptools/Distuilsがひどく文書化されているので、自分でこれに対する答えを見つけるのに問題がありました。しかし、最終的には this の例に出くわしました。また、 this 同様の質問が役に立ちました。基本的に、オプション付きのカスタムコマンドは次のようになります。

from distutils.core import setup, Command

class InstallCommand(Command):
    description = "Installs the foo."
    user_options = [
        ('foo=', None, 'Specify the foo to bar.'),
    ]
    def initialize_options(self):
        self.foo = None
    def finalize_options(self):
        assert self.foo in (None, 'myFoo', 'myFoo2'), 'Invalid foo!'
    def run(self):
        install_all_the_things()

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

これは非常にシンプルなソリューションです。_sys.argv_をフィルターで取り除き、distutils setup(..)を呼び出す前に自分で処理するだけです。このようなもの:

_if "--foo" in sys.argv:
    do_foo_stuff()
    sys.argv.remove("--foo")
...
setup(..)
_

Distutilsでこれを行う方法に関するドキュメントはひどいものですが、最終的に私はこれに遭遇しました: ヒッチハイカーのパッケージ化ガイドsdistとその_user_options_を使用します。 extending distutils の参照は特に役に立ちません。

これは、distutilsでそれを行う「適切な」方法のように見えますが(少なくとも、漠然と文書化されている唯一の方法です)。他の回答に記載されている_--with_および_--without_スイッチには何も見つかりませんでした。

このdistutilsソリューションの問題は、私が探しているものにはあまりにも複雑すぎることです(これはあなたにも当てはまる場合があります)。何十行も追加してsdistをサブクラス化するのは私にとっては間違っています。

26
totaam

はい、それは2015年であり、setuptoolsdistutilsの両方にコマンドとオプションを追加するためのドキュメントはまだほとんどありません。

イライラする数時間後、setup.pyinstallコマンドにカスタムオプションを追加するための次のコードを見つけました。

from setuptools.command.install import install


class InstallCommand(install):
    user_options = install.user_options + [
        ('custom_option=', None, 'Path to something')
    ]

    def initialize_options(self):
        install.initialize_options(self)
        self.custom_option = None

    def finalize_options(self):
        #print('The custom option for install is ', self.custom_option)
        install.finalize_options(self)

    def run(self):
        global my_custom_option
        my_custom_option = self.custom_option
        install.run(self)  # OR: install.do_Egg_install(self)

Install.run()が「ネイティブに」呼び出されたか、パッチが適用されたかどうかをチェックすることは言及する価値があります。

if not self._called_from_setup(inspect.currentframe()):
    orig.install.run(self)
else:
    self.do_Egg_install()

この時点で、コマンドをsetupに登録します。

setup(
    cmdclass={
        'install': InstallCommand,
    },
    :
16
Ronen Botzer

スクリプトにカスタムパラメータを渡すことはできません。ただし、次のことが可能であり、問​​題を解決できる可能性があります。

  • オプション機能は--with-featurenameを使用して有効にでき、標準機能は--without-featurenameを使用して無効にできます。 [これにはsetuptoolsが必要です]
  • 環境変数を使用できますが、これらはWindowsではsetである必要がありますが、Linux/OS X(FOO=bar python setup.py)では接頭辞が付きます。
  • 新しい機能を実装できる独自のcmd_classesでdistutilsを拡張できます。それらは連鎖可能でもあるので、それを使用してスクリプト内の変数を変更できます。 (python setup.py foo install)は、fooを実行する前にinstallコマンドを実行します。

何とかお役に立てば幸いです。一般的に言って、追加のパラメーターが正確に何をすべきかについて、もう少し情報を提供することをお勧めします。

11
Armin Ronacher

おそらく、あなたは上記のようなすべての答えを読んだ後もまだ苦労している私のような無作法なプログラマーです。したがって、別の例が役立つ可能性があります(およびコマンドライン引数の入力に関する以前の回答のコメント):

class RunClientCommand(Command):
    """
    A command class to runs the client GUI.
    """

    description = "runs client gui"

    # The format is (long option, short option, description).
    user_options = [
        ('socket=', None, 'The socket of the server to connect (e.g. '127.0.0.1:8000')',
    ]

    def initialize_options(self):
        """
        Sets the default value for the server socket.

        The method is responsible for setting default values for
        all the options that the command supports.

        Option dependencies should not be set here.
        """
        self.socket = '127.0.0.1:8000'

    def finalize_options(self):
        """
        Overriding a required abstract method.

        The method is responsible for setting and checking the 
        final values and option dependencies for all the options 
        just before the method run is executed.

        In practice, this is where the values are assigned and verified.
        """
        pass

    def run(self):
        """
        Semantically, runs 'python src/client/view.py SERVER_SOCKET' on the
        command line.
        """
        print(self.socket)
        errno = subprocess.call([sys.executable, 'src/client/view.py ' + self.socket])
        if errno != 0:
            raise SystemExit("Unable to run client GUI!")

setup(
    # Some other omitted details
    cmdclass={
        'runClient': RunClientCommand,
    },

上記は私が書いたいくつかのコードからテストされています。わかりやすくするために、もう少し詳細なdocstringも含めました。

コマンドラインの場合:python setup.py runClient --socket=127.0.0.1:7777。 printステートメントを使用した簡単なダブルチェックは、runメソッドによって実際に正しい引数が取得されていることを示しています。

その他の役立つリソース(moreおよびmore例):

カスタムdistutilsコマンド

https://seasonofcode.com/posts/how-to-add-custom-build-steps-and-commands-to-setuppy.html

5
OthmanEmpire

私はtotaamの提案に似たソリューションを使用するために回避策をうまく使用しました。 sys.argvリストから余分な引数をポップしてしまいました。

import sys
from distutils.core import setup
foo = 0
if '--foo' in sys.argv:
    index = sys.argv.index('--foo')
    sys.argv.pop(index)  # Removes the '--foo'
    foo = sys.argv.pop(index)  # Returns the element after the '--foo'
# The foo is now ready to use for the setup
setup(...)

入力が適切であることを確認するために追加の検証を追加できますが、これは私が行った方法です

4
Jodin

Totaamによって提供されるのと同様の迅速で簡単な方法は、argparseを使用して-foo引数を取得し、残りの引数をdistutils.setup()の呼び出しに残しておくことです。これにargparseを使用する方が、sys.argvを手動で繰り返すよりも優れています。たとえば、これをsetup.pyの最初に追加します。

argparser = argparse.ArgumentParser(add_help=False)
argparser.add_argument('--foo', help='required foo argument', required=True)
args, unknown = argparser.parse_known_args()
sys.argv = [sys.argv[0]] + unknown

add_help=False引数は、-hを使用して通常のsetup.pyヘルプを引き続き取得できることを意味します(--fooが指定されている場合)。

1
andrew

pipオプションpython setup.py installにはバグがあるため、pip install .--install-option=の両方と完全に互換性を保つには、環境変数を使用する必要があります。

  1. pip --install-option行を越えてリーク
  2. ホイールについて-(install | global)-optionについて何をすべきかを決定する
  3. pipがabi3ホイールに正しく名前を付けていない

これは、--install-optionを使用しない完全な例です。

import os
environment_variable_name = 'MY_ENVIRONMENT_VARIABLE'
environment_variable_value = os.environ.get( environment_variable_name, None )

if environment_variable_value is not None:
    sys.stderr.write( "Using '%s=%s' environment variable!\n" % (
            environment_variable_name, environment_variable_value ) )

setup(
        name = 'packagename',
        version = '1.0.0',
        ...
)

その後、Linuxで次のように実行できます。

MY_ENVIRONMENT_VARIABLE=1 pip install .
MY_ENVIRONMENT_VARIABLE=1 pip install -e .
MY_ENVIRONMENT_VARIABLE=1 python setup.py install
MY_ENVIRONMENT_VARIABLE=1 python setup.py develop

ただし、Windowsを使用している場合は、次のように実行します。

set "MY_ENVIRONMENT_VARIABLE=1" && pip install .
set "MY_ENVIRONMENT_VARIABLE=1" && pip install -e .
set "MY_ENVIRONMENT_VARIABLE=1" && python setup.py install
set "MY_ENVIRONMENT_VARIABLE=1" && python setup.py develop

参照:

  1. '-install-option'を使用して、pipからsetup.pyに渡された引数を取得するには?
  2. コマンドライン引数をpip installに渡す
  3. ライブラリパスをコマンドライン引数としてsetup.pyに渡す
0
user