Snakemake输出规则通配符{outf}与{sample}值不匹配排查
故障根因
问题出在两个对Snakemake机制的核心误用,没有特殊玄学因素:
expand函数默认对传入的多组列表做笛卡尔积全组合,不会按列表索引一一配对。你当前写的expand(os.path.join("{outf}","{sample}","methods.txt"), outf=OUTPREFIXES, sample=SAMPLES)会生成「所有输出前缀×所有样本」的全量路径,其中绝大多数都是SampleA配输出目录B、SampleB配输出目录A这类你根本不需要的无效错配路径,这也是日志里会出现不存在的目标路径的直接原因。- 你在
copy_folders规则里同时定义了{outf}和{sample}两个完全独立的通配符,却没有加任何配对约束。Snakemake解析通配符是靠目标路径字符串做正则匹配拆分的,它本身不知道“某一个样本必须对应固定输出前缀”的映射规则,自然会出现两个通配符的值乱搭的情况。 - 你观察到shell里执行的路径是对的,是因为
get_input_folder、get_output_folder两个函数只取了wildcards.sample的值查映射表,从头到尾没用到wildcards.outf的值——等于{outf}这个通配符从定义开始就是多余的,和你实际的业务逻辑完全脱钩,才会出现“input路径对、output路径错”的分裂情况。 - 之前小样本测试能跑通只是巧合:样本量少的时候Snakemake的正则匹配刚好撞上了正确的配对,属于概率性通过,不是逻辑本身正确。
修复步骤
直接删掉多余的{outf}通配符,从根源上消除双通配符错配的可能,同时修正路径生成逻辑:
- 替换
rule all里的expand写法,不要生成全组合路径,直接按映射表逐行生成你真实需要的目标文件列表:# 逐行读取映射表,按一一对应关系生成目标路径,从入口就杜绝错配路径 TARGETS = [] for _, row in data.iterrows(): TARGETS.append(os.path.join(row["Output"], row["Subfolder"], "methods.txt")) rule all: input: TARGETS - 精简
copy_folders规则,移除多余的{outf}通配符,把输出路径和sample强绑定,不要留不受控的通配符:# 输入函数保持不变,通过sample值直接查映射表 def get_input_folder(wildcards): return data.loc[wildcards.sample]["Input"] def get_output_folder(wildcards): return data.loc[wildcards.sample]["Output"] # 新增:直接通过sample值返回唯一对应的标记文件路径,锁死输出路径 def get_flag_path(wildcards): out_prefix = data.loc[wildcards.sample]["Output"] return os.path.join(out_prefix, wildcards.sample, "methods.txt") rule copy_folders: input: infolder = directory(get_input_folder), output: flag_file = get_flag_path, params: outfolder = get_output_folder, resources: mem_mb=2000, cpus=1 shell: ''' cp -R {input.infolder} {params.outfolder} TEMPSAMPLE=$(basename {input.infolder}) cp ../methods.txt {params.outfolder}/$TEMPSAMPLE/ ''' - 删掉原来规则input里多余的
outfolder = directory(get_output_folder)项——这一项本身是目录类型输入,Snakemake会提前检查这个目录是否存在,但这个目录是你当前规则要创建的,提前检查反而会触发不必要的报错。
额外注意事项
- shell块里不要用
local修饰变量,Snakemake每个作业的shell块是独立启动的非交互进程,不是函数作用域,直接给变量赋值即可,加local必然会触发语法报错。 - 用
methods.txt作为作业完成标记的思路是对的,Snakemake对纯目录输出的修改时间判定不稳定,很容易出现作业跑完但判定输出缺失的问题,固定的标记文件可靠性高很多。 - 如果后续确实需要在规则里用多个通配符,要么提前在
rule all阶段就生成严格配对的目标路径列表,要么通过wildcard_constraints给通配符加正则约束,或者在输入函数里对错配的通配符组合直接抛异常阻断,不要让Snakemake自由组合通配符值。
内容的提问来源于stack exchange,提问作者Charles W
相关产品推荐
相关产品推荐

