distutils/setuptools 提供了一个抽象的Command 类,用户可以使用该类将自定义命令添加到他们的包的设置过程中。这是与build 和install 等内置设置命令的子类相同的类。
作为抽象Command 类的子类的每个类都必须实现initialize_options、finalize_options 和run 方法。这些方法名称所指的“选项”是从用户提供的命令行参数派生的类属性(它们也可以具有默认值)。 initialize_options 方法是定义类的选项的地方,finalize_options 方法是分配类的选项值的地方,run 方法是使用类的选项值来执行命令功能的地方。
由于命令行参数可能影响多个命令,一些命令类可能与其他命令类共享选项。例如,所有 distutils/setuptools 构建命令(build、build_py、build_clib、build_ext 和 build_scripts)和 install 命令都需要知道构建目录的位置。 build 命令是所有这些命令中的第一个要执行的命令,而不是让这些命令类中的每一个定义和解析相同的命令行参数到相同的选项中,它定义并解析命令行参数和选项,而所有其他类在其finalize_options 方法中从build 命令获取选项值。
例如,build 类在其initialize_options 方法中定义build_base 和build_lib 选项,然后从其finalize_options method 中的命令行参数计算它们的值。 install 类还在其 initialize_options 方法中定义了 build_base 和 build_lib 选项,但它在其 finalize_options 方法中获取这些选项 from the build command 的值。
您可以使用相同的模式向build 命令添加自定义子命令,如下所示(install 类似)
import setuptools
from distutils.command.build import build
class BuildSomething(setuptools.Command):
def initialize_options(self):
# define the command's options
self.build_base = None
self.build_lib = None
def finalize_options(self):
# get the option values from the build command
self.set_undefined_options('build',
('build_base', 'build_base'),
('build_lib', 'build_lib'))
def run(self):
# do something with the option values
print(self.build_base) # defaults to 'build'
print(self.build_lib)
build_something_command = 'build_something'
class Build(build):
def has_something(self):
# update this to check if your build should run
return True
sub_commands = [(build_something_command, has_something)] + build.sub_commands
COMMAND_CLASS = {
build_something_command: BuildSomething, # custom command
'build': Build # override distutils/setuptools build command
}
setuptools.setup(cmdclass=COMMAND_CLASS)
或者,如果您只是想扩展 distutils/setuptools 类之一,并且它已经具有您需要的选项,您可以将其子类化
import setuptools
from setuptools.command.build_py import build_py
class BuildPy(build_py):
def initialize_options(self):
pass
def finalize_options(self):
pass
def run(self):
# do something with the option values
print(self.build_lib) # inherited from build_py
build_py.run(self) # make sure the regular build_py still runs
COMMAND_CLASS = {
'build_py': BuildPy # override distutils/setuptools build_py command
}
setuptools.setup(cmdclass=COMMAND_CLASS)
不幸的是,这些都没有在任何地方得到很好的记录。我从阅读distutils 和setuptools 源代码中学到了大部分内容。任一存储库的command 目录中的任何build*.py 和install*.py 文件都提供信息。抽象的Command 类是defined in distutils。