直接调用distutils或setuptools的setup()函数,传入命令名称/选项,而无需解析命令行?
我想用一种稍微不寻常的方式来调用Python的distutils或setuptools的setup()函数,但我不确定distutils是否适合这样使用。
举个例子,我现在有一个'setup.py'文件,它的内容是这样的(直接从distutils文档中复制的,setuptools的用法几乎一样):
from distutils.core import setup
setup(name='Distutils',
version='1.0',
description='Python Distribution Utilities',
author='Greg Ward',
author_email='gward@python.net',
url='http://www.python.org/sigs/distutils-sig/',
packages=['distutils', 'distutils.command'],
)
通常情况下,如果我想为这个模块构建一个RPM的.spec文件,我可以运行 python setup.py bdist_rpm --spec-only
,这个命令会解析命令行并调用'bdist_rpm'的代码来处理与RPM相关的内容。最后,.spec文件会放在'./dist'文件夹里。
我该如何修改我的setup()调用,让它在不解析命令行参数的情况下,运行'bdist_rpm'命令并带上'--spec-only'选项呢?我可以把命令名和选项作为参数传给setup()吗?或者我可以手动构造一个命令行,然后把它作为参数传递过去吗?
注意:我已经知道我可以用os.system()或subprocess模块等方法,在一个单独的进程中调用这个脚本,并使用实际的命令行。我想避免使用任何外部命令调用。我特别想要一个在当前解释器中运行setup()的解决方案。
背景是,我正在把一些发布管理的shell脚本转换成一个单独的Python程序。其中一个任务是运行'setup.py'来生成一个.spec文件,以便进行进一步的预发布测试。把'setup.py'当作外部命令来运行,并带上自己的命令行选项,感觉有点笨拙,而且会让程序的其他部分变得复杂。我觉得可能有更符合Python风格的方法。
2 个回答
你可以“伪造”命令行参数,比如说,启动你的脚本时可以这样做:
import sys
sys.argv[1:] = ['bdist_rpm', '--spec-only']
from distutils.core import setup
setup(name='Distutils',
等等。毕竟,distutils
获取命令行参数的方式就是查看 sys.argv
!所以,你只需要把 sys.argv
设置成你想要的样子,这样用户输入的任何命令行内容就会被完全忽略。
其实,你可能还想检查一下用户是否真的输入了你打算忽略的参数——在修改 sys.argv
之前可以用 len(sys.argv) > 1
来判断一下——然后给出警告,或者不修改 sys.argv
,或者“合并”用户输入的内容等等……不过这和你问的问题有点不同,所以我就不多说了;-)。
我之前没试过这个,但我偶然查看了distutils/core.py文件,发现setup()
函数开头附近有这些内容:
if 'script_name' not in attrs:
attrs['script_name'] = os.path.basename(sys.argv[0])
if 'script_args' not in attrs:
attrs['script_args'] = sys.argv[1:]
所以,看起来你可以通过添加以下内容来“伪装”setup()
函数:
setup(
...
script_name = 'setup.py',
script_args = ['bdist_rpm', '--spec-only']
)