如何在setuptools上使用选项运行run_command?

时间:2014-06-22 17:30:06

标签: python setuptools distutils

我在my setup.py file: create_tablesdrop_tables有两个自定义命令:

class create_tables(command):
    description = 'create DB tables'

    user_options = [
        ('database=', 'd', 'which database configuration use'),
        ('reset', 'r', 'reset all data previously'),
    ]

    def initialize_options(self):
        command.initialize_options(self)
        self.reset = False

    def run(self):
        if self.reset:
            self.run_command('drop_tables')
        else:
            command.run(self)
        from vk_relations import models
        models.create_tables()
        print 'Tables were created successfully'


class drop_tables(command):
    description = 'drop all created DB tables'

    user_options = [
        ('database=', 'd', 'which database configuration use'),
    ]

    def run(self):
        command.run(self)
        answer = raw_input('Are you sure you want to clear all VK Relations data? (y/n): ')
        if 'y' == answer:
            from vk_relations import models
            models.drop_tables()
            print 'Tables were dropped successfully'
        elif 'n' == answer:
            quit()
        else:
            sys.exit()

命令$ setup.py create_tables -r -dmain应运行命令drop_tables并在main数据库创建新表,但run_command方法不允许为命令提供选项。如何在database命令中为drop_tables指定选项create_tables

2 个答案:

答案 0 :(得分:1)

现在我用过这个黑客:

cmd_obj = self.distribution.get_command_obj('drop_tables')
cmd_obj.database = self.database
self.run_command('drop_tables')

答案 1 :(得分:1)

“适当”的解决方案

对于诸如build之类的预定义目标,在对象上设置属性将失败。 您可以在这里找到最合适的解决方案的最接近的是:

class drop_tables(command): # <-- Note this should come from drop_tables command

    def finalize_options(self):
        self.set_undefined_options("create_tables", ("database", "database"))

这是一种用于将参数从build继承到build_py和其他子命令的方法。

使用build命令

我不喜欢build命令中引入的distutils包的作者的循环引用。 执行顺序如下:build命令调用build_py子命令。子命令返回到build命令,并获取未定义的参数。这使得紧密耦合,因为两个命令都需要彼此了解。 同样,如果要添加另一个聚合命令,则会引入歧义-build_py将具有两个要继承的参数源。

减少耦合的方法应该有所不同。 如果build命令是一个聚合命令,因此它应该处理传递给其子命令的所有参数。

class build(command):
    ...
    def finalize_options(self):
        for cmd_name in self.get_sub_commands():
            cmd_obj = self.distribution.get_command_obj(cmd_name)
            cmd_obj.set_undefined_options("build", ("build_lib", "build_lib"), ...)

现在,无需按名称传递命令,我们可以使用instance代替。这还将解决set_undefined_options> ensure_finalized> finalize_options> set_undefined_options

中的无限递归

正确的解决方案

鉴于当前的状况,针对您的问题的更好解决方案是:

class create_tables(command):

    def run(self):
        cmd_obj = self.distribution.get_command_obj("drop_tables")
        cmd_obj.set_undefined_options("create_tables", ("database", "database"))
        self.run_command("drop_tables")