You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Snakemake规则在输入变更后未重新生成输出的问题

Snakemake compose规则不触发重跑的问题排查与解决

问题场景

我定义了如下Snakemake规则compose,用于处理预存在工作流中的XML文件、资源文件和转换脚本,输出一个标记运行成功的flag文件:

rule compose:
    input:
        manuscripts=[
            str(a)
            for a in Path(".").glob(f"./{config['series']}_*_*_*/tei/*.xml")
            if not (config["publication"] in str(a))
        ],
        assets=[str(a) for a in Path(".").glob(f"{config['series']}_*/assets/*.*")],
        script=expand("{dir}/other/compose.xsl", dir=config["transform"]),
    output:
        touch("composed.flag"),
    params:
        publication=config["publication"],
        saxon=config["saxon"],
    run:
        # 创建目录
        (Path(".") / "tei/media/").mkdir(parents=True, exist_ok=True)
        (Path(".") / "assets/").mkdir(parents=True, exist_ok=True)
        # 生成dummy docx
        shell("touch {params.publication}.docx")
        # 复制资源文件
        for f in input.assets:
            shell("cp {f} assets/")
        shell("cp -rf assets/* tei/media/")
        # 复制转换脚本
        shell("cp -a {input.script} tei/compose.xsl")
        # 生成手稿列表XML
        shell("echo '<collection/>' > tei/manuscripts.xml")
        for man in input.manuscripts:
            m = man.split("/")[-1].split(".")[0]
            shell(
                "xmlstarlet ed -L -s '/collection' -t elem -n 'doc' -v '' -i '/collection/doc[last()]' -t attr -n 'href' -v '../{m}/tei/{m}.xml' tei/manuscripts.xml"
            )
        # 执行XSLT转换
        shell(
            "java -jar {params.saxon} -o:tei/{params.publication}.xml tei/manuscripts.xml tei/compose.xsl projectfolder={params.publication}"
        )
        # 清理临时文件
        shell("rm -f tei/manuscripts.xml tei/compose.xsl")

首次调用命令snakemake -p -c1 compose --config workdir="/home/lector/manuscripts/ends-of-humanities/eoh_01_mein_eoh"可正常生成输出,但修改其中一个输入XML文件后,即使该文件时间戳晚于composed.flag,Snakemake仍提示"无任务需执行(所有请求文件已存在且为最新)",甚至添加-f参数强制重跑也无效。

原因分析

1. 静态输入列表导致依赖跟踪失效

规则input中的Path.glob()是在Snakemake启动时的规则解析阶段执行的,只会生成一次输入文件列表。后续修改文件时,Snakemake不会重新扫描路径更新列表:

  • 如果修改的文件不在初始扫描的列表中(比如第一次运行时未创建),Snakemake根本不会把它纳入依赖跟踪;
  • 即使文件在初始列表中,若Snakemake的元数据缓存(.snakemake/目录)记录的文件状态未更新,也会误判为输入无变化。

2. -f参数未生效的逻辑

-f参数强制重跑目标规则,但如果当前运行时解析的输入列表为空,或者Snakemake判定规则输出(composed.flag)无需更新,就不会执行规则。

解决方案

1. 改用动态输入函数延迟计算

将输入的glob操作改为自定义函数,确保每次运行Snakemake时都会重新扫描文件路径,生成最新的输入列表:

def get_manuscripts(wildcards, config):
    return [
        str(a)
        for a in Path(".").glob(f"./{config['series']}_*_*_*/tei/*.xml")
        if not (config["publication"] in str(a))
    ]

def get_assets(wildcards, config):
    return [str(a) for a in Path(".").glob(f"{config['series']}_*/assets/*.*")]

rule compose:
    input:
        manuscripts=get_manuscripts,
        assets=get_assets,
        script=expand("{dir}/other/compose.xsl", dir=config["transform"]),
    output:
        touch("composed.flag"),
    params:
        publication=config["publication"],
        saxon=config["saxon"],
    run:
        # 原run代码保持不变
        ...

2. 清理Snakemake缓存

如果元数据缓存导致异常,删除.snakemake/目录后重新运行,强制Snakemake重新计算所有依赖:

rm -rf .snakemake/
snakemake -p -c1 compose --config workdir="/home/lector/manuscripts/ends-of-humanities/eoh_01_mein_eoh"

3. 声明所有产物为输出(可选)

run代码中生成的tei/{params.publication}.xml、{params.publication}.docx等文件未被声明为output,Snakemake无法跟踪这些产物的变化。若需要维护工作流的完整性,建议将这些文件加入output:

output:
    touch("composed.flag"),
    "tei/{params.publication}.xml",
    "{params.publication}.docx",

内容的提问来源于stack exchange,提问作者Cutú Chiqueño

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 00:40:29