distutils:如何将用户定义的参数传递给setup.py?

时间:2009-03-24 14:12:04

标签: python distutils setup.py

请提示我如何将命令行和setup.cfg配置文件中的用户定义参数传递给distutils的setup.py脚本。我想编写一个setup.py脚本,它接受我的包特定参数。例如:

python setup.py install -foo myfoo

谢谢你,
Mher

8 个答案:

答案 0 :(得分:55)

由于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,
    }
)

答案 1 :(得分:23)

这是一个非常简单的解决方案,您只需过滤掉sys.argv并在调用distutils setup(..)之前自行处理。 像这样:

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

关于如何使用distutils执行此操作的文档非常糟糕,最终我遇到了这个:the hitchhikers guide to packaging,它使用sdist及其user_options。 我发现extending distutils引用不是特别有帮助。

虽然这看起来像是使用distutils的“正确”方式(至少我能找到的唯一一个模糊记录的方法)。我在其他答案中提到的--with--without开关上找不到任何内容。

这个distutils解决方案的问题在于它只是涉及我正在寻找的东西(这也可能是你的情况)。 添加几十行和子类化sdist对我来说是错误的。

答案 2 :(得分:15)

是的,它是2015年,setuptoolsdistutils中添加命令和选项的文档仍然很大程度上缺失。

经过几个令人沮丧的时间后,我想出了以下代码,用于向install的{​​{1}}命令添加自定义选项:

setup.py

值得一提的是,install.run()检查它是否被称为"本地"或者已经修补过:

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)

此时,您使用if not self._called_from_setup(inspect.currentframe()): orig.install.run(self) else: self.do_egg_install() 注册命令:

setup

答案 3 :(得分:10)

您无法将自定义参数传递给脚本。但是,以下事情是可能的,可以解决您的问题:

  • 可以使用--with-featurename启用可选功能,可以使用--without-featurename禁用标准功能。 [AFAIR这需要setuptools]
  • 你可以使用环境变量,但这些变量需要在Windows上set,而前缀可以在linux / OS X上运行(FOO=bar python setup.py)。
  • 您可以使用自己的cmd_class es扩展distutils,这可以实现新功能。它们也是可链接的,因此您可以使用它来更改脚本中的变量。 (python setup.py foo install)将在执行foo之前执行install命令。

希望以某种方式有所帮助。一般来说,我建议您提供更多信息,确切了解您的额外参数应该做些什么,也许有更好的解决方案。

答案 4 :(得分:4)

也许你是一个喜欢我的未经季节的程序员,在阅读完上面的所有答案之后仍然在努力。因此,您可能会发现另一个可能有用的示例(并解决有关输入命令行参数的先前答案中的注释):

setup(
    # Some other omitted details
    cmdclass={
        'runClient': RunClientCommand,
    },
python setup.py runClient --socket=127.0.0.1:7777

上面的测试和我写的一些代码。我还提供了更详细的文档字符串,以便于理解。

至于命令行:Preference。使用print语句进行快速双重检查表明,run方法确实选择了正确的参数。

我觉得有用的其他资源( 更多更多 示例):

Custom distutils commands

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

答案 5 :(得分:3)

我成功地使用了一种解决方法来使用类似于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(...)

可以添加一些额外的验证以确保输入良好,但这就是我做的方式

答案 6 :(得分:0)

类似于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)。

答案 7 :(得分:-1)

要与python setup.py installpip install .完全兼容,您需要使用环境变量,因为pip选项--install-option=有问题:

  1. pip --install-option leaks across lines
  2. Determine what should be done about --(install|global)-option with Wheels
  3. pip not naming abi3 wheels correctly

这是不使用--install-option的完整示例:

import os
environment_variable_name = 'USE_STD_GETLINE'
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. How to obtain arguments passed to setup.py from pip with '--install-option'?
  2. Passing command line arguments to pip install
  3. Passing the library path as a command line argument to setup.py