如何让Snakemake的glob_wildcards遵循全局通配符约束?
如何让Snakemake的glob_wildcards遵循全局通配符约束?
问题描述
在大型Snakemake工作流中,已定义全局通配符约束,这些约束在规则的输入输出路径处理中正常生效,但使用glob_wildcards解析磁盘路径时,全局约束并未被应用。
示例Snakefile:
from pathlib import Path Path("inputs").mkdir(exist_ok=True) for name in [1, 2, 3, "other"]: (Path("inputs")/f"{name}.txt").touch() wildcard_constraints: number="[0-9]+" # 硬编码约束,结果符合预期 print(glob_wildcards("inputs/{number,[0-9]+}.txt")) # 使用全局约束,结果不符合预期(包含非数字的"other") print(glob_wildcards("inputs/{number}.txt"))
运行结果:
Wildcards(number=['1', '2', '3']) Wildcards(number=['1', '2', '3', 'other'])
解决方案
glob_wildcards默认不会自动读取全局通配符约束,需要手动将全局约束关联到通配符模式中,以下是两种可行方法:
方法1:动态引用全局约束构建模式
直接从wildcard_constraints字典中提取正则表达式,动态生成带约束的glob模式:
from pathlib import Path Path("inputs").mkdir(exist_ok=True) for name in [1, 2, 3, "other"]: (Path("inputs")/f"{name}.txt").touch() wildcard_constraints: number="[0-9]+" # 利用全局约束字典构建带约束的模式 constrained_pattern = f"inputs/{{number,{wildcard_constraints['number']}}}.txt" print(glob_wildcards(constrained_pattern))
运行结果:
Wildcards(number=['1', '2', '3'])
方法2:封装工具函数(适合大型工作流)
如果需要频繁使用,可以封装一个函数自动替换模式中的通配符为带全局约束的格式:
from pathlib import Path Path("inputs").mkdir(exist_ok=True) for name in [1, 2, 3, "other"]: (Path("inputs")/f"{name}.txt").touch() wildcard_constraints: number="[0-9]+" def glob_with_constraints(pattern): """自动将全局通配符约束应用到glob模式""" for wc_name, regex in wildcard_constraints.items(): pattern = pattern.replace(f"{{{wc_name}}}", f"{{{wc_name},{regex}}}") return glob_wildcards(pattern) # 使用工具函数 print(glob_with_constraints("inputs/{number}.txt"))
原理说明
全局wildcard_constraints主要用于校验规则输入输出路径中的通配符,而glob_wildcards是独立的路径匹配工具,默认不继承这些约束。通过手动将全局约束的正则表达式注入到glob模式中,就能让两者的匹配逻辑保持一致。
内容的提问来源于stack exchange,提问作者Jesse
相关产品推荐
相关产品推荐

