在Luigi中重用通用任务

时间:2017-09-28 02:22:31

标签: python luigi

我无法理解如何在Luigi中制作可重复使用的任务,然后在具体情况下使用它们。

例如。我有两个通用任务对文件执行某些操作然后输出结果:

class GffFilter(luigi.Task):
    "Filters a GFF file to only one feature"
    feature = luigi.Parameter()
    out_file = luigi.Parameter()
    in_file = luigi.Parameter()
    ...

class BgZip(luigi.Task):
    "bgZips a file"
    out_file = luigi.Parameter()
    in_file = luigi.Parameter()
    ...

现在,我想要一个首先过滤的工作流,然后使用这些任务bgzips一个特定的文件:

class FilterSomeFile(luigi.WrapperTask):
    def requires(self):
        return GffFilter(in_file='some.gff3', out_file='some.genes.gff3', filter='gene')

    def output(self):
        return self.inputs()

class BgZipSomeFile(luigi.Task):
    def run(self):
        filtered = FilterSomeFile()
        BzZip(filtered)

但这很尴尬。在第一个任务中,我没有run方法,我只是使用依赖项来使用通用任务。它是否正确?我应该在这里使用继承吗?

然后在第二个任务中,我无法使用依赖项,因为我需要FilterSomeFile的输出才能使用BgZip。但是使用动态依赖似乎是错误的,因为luigi无法构建适当的依赖图。

应该如何我从通用任务中创建Luigi工作流程?

1 个答案:

答案 0 :(得分:0)

  

但这很尴尬。在第一个任务中,我没有运行方法,而我只是使用依赖项来使用通用任务。这是对的吗?

是的,根据this pageWrapperTask是一个虚拟任务,其目的是定义任务的工作流程,因此它不会自行执行任何操作。相反,通过定义多个需求,当requires方法中列出的每个需求都已完成时,此任务将完成。此WrapperTask与常规Task的主要区别在于,您不需要定义输出方法来表示此任务已成功,可以看作here

  

然后在第二个任务中,我不能使用依赖项,因为我需要FilterSomeFile的输出才能使用BgZip。但是使用动态依赖似乎是错误的,因为luigi无法构建适当的依赖图。

从理论上讲,您可以使FilterSomeFile与[{1}}具有相同的输出,使GffFilter需要BgZipSomeFile,然后使用FilterSomeFile FilterSomeFile.output() 1}}访问压缩文件。但是,这个解决方案有点奇怪,因为:

  • 包装器任务仅“运行”另一个任务,因此可以直接使用包装的任务,而无需创建BgZipSomeFile.run。更好地使用WrapperTask会将WrapperTaskBgZipSomeFile合并到FilterSomeFile的单个子类中

  • 正在运行方法中实例化WrapperTask。这会产生动态依赖关系,但在此问题中不需要这样做。

  • 最后,Task的输入在GffFilter任务中进行了硬编码,这使得工作流程变得不那么有用。这可以通过使FilterSomeFile仍然接收参数,并将这些参数传递给其要求来避免。

更好的解决方案是:

WrapperClass

此代码可以在命令行中运行:

import luigi as lg

class A(lg.Task):
    inFile = lg.Parameter()
    outFile = lg.Parameter()

    def run(self,):
        with open(self.inFile, "r") as oldFile:
            text = oldFile.read()

        text  += "*" * 10 + "\n" + "This text was added by task A.\n" + "*" * 10 + "\n"
        print(text)
        with open(self.outFile, "w") as newFile:
            newFile.write(text)

    def output(self,):
        return lg.LocalTarget(self.outFile)

class B(lg.Task):
    inFile = lg.Parameter()
    outFile = lg.Parameter()

    def run(self,):
        with open(self.inFile, "r") as oldFile:
            text = oldFile.read()

        text  += "*" * 10 + "\n" + "This text was added by task B.\n" + "*" * 10 + "\n"

        with open(self.outFile, "w") as newFile:
            newFile.write(text)

    def output(self,):
        return lg.LocalTarget(self.outFile)

class CustomWorkflow(lg.WrapperTask):
    mainOutFile = lg.Parameter()
    mainInFile = lg.Parameter()
    tempFile = "/tmp/myTempFile.txt"
    def requires(self,):
        return [    A(inFile = self.mainInFile, outFile = self.tempFile),
                    B(inFile = self.tempFile, outFile = self.mainOutFile)
                ]