gpt4 book ai didi

python - 通过 Snakemake 进行符号链接(symbolic link)(自动生成)目录

转载 作者:行者123 更新时间:2023-12-03 14:42:08 25 4
gpt4 key购买 nike

我正在尝试为 Snakemake 工作流程中的别名输出目录创建一个符号链接(symbolic link)目录结构。
让我们考虑以下示例:
很久以前,在一个遥远的星系中,有人想找到宇宙中最好的冰淇淋口味,并进行了一项调查。我们的示例工作流程旨在通过目录结构表示投票。该调查是用英语进行的(因为在那个外国星系中他们都说英语),但结果也应该被非英语人士理解。符号链接(symbolic link)来救援。
为了让我们人类和 Snakemake 可以解析输入,我们将它们粘贴到 YAML 文件中:

cat config.yaml
flavours:
chocolate:
- vader
- luke
- han
vanilla:
- yoda
- leia
berry:
- windu
translations:
french:
chocolat: chocolate
vanille: vanilla
baie: berry
german:
schokolade: chocolate
vanille: vanilla
beere: berry
为了创建相应的目录树,我从这个简单的 Snakefile 开始:
### Setup ###

configfile: "config.yaml"


### Targets ###

votes = ["english/" + flavour + "/" + voter
for flavour, voters in config["flavours"].items()
for voter in voters]

translations = {language + "_translation/" + translation
for language, translations in config["translations"].items()
for translation in translations.keys()}


### Commands ###

create_file_cmd = "touch '{output}'"

relative_symlink_cmd = "ln --symbolic --relative '{input}' '{output}'"


### Rules ###

rule all:
input: votes, translations

rule english:
output: "english/{flavour}/{voter}"
shell: create_file_cmd

rule translation:
input: lambda wc: "english/" + config["translations"][wc.lang][wc.trans]
output: "{lang}_translation/{trans}"
shell: relative_symlink_cmd
我相信还有更多的“pythonic”方法可以实现我想要的,但这只是一个简单的例子来说明我的问题。
使用 snakemake 运行上述工作流程,我收到以下错误:
Building DAG of jobs...
MissingInputException in line 33 of /tmp/snakemake.test/Snakefile
Missing input files for rule translation:
english/vanilla
因此,虽然 Snakemake 足够聪明地创建了 english/<flavour>尝试创建 english/<flavour>/<voter> 时的目录文件,当使用它作为输入来创建 <language>_translation/<flavour> 时,它似乎“忘记”了该目录的存在。符号链接(symbolic link)。
作为中间步骤,我将以下补丁应用于 Snakefile:
27c27
< input: votes, translations
---
> input: votes#, translations
现在,工作流运行并创建了 english预期的目录( snakemake -q 仅输出):
Job counts:
count jobs
1 all
6 english
7
现在创建了目标目录,我回到了 Snakefile 的初始版本并重新运行它:
Job counts:
count jobs
1 all
6 translation
7
ImproperOutputException in line 33 of /tmp/snakemake.test/Snakefile
Outputs of incorrect type (directories when expecting files or vice versa). Output directories must be flagged with directory(). for rule translation:
french_translation/chocolat
Exiting because a job execution failed. Look above for error message
虽然我不确定指向目录的符号链接(symbolic link)是否符合目录的条件,但我继续并应用了一个新补丁来遵循建议:
35c35
< output: "{lang}_translation/{trans}"
---
> output: directory("{lang}_translation/{trans}")
有了这个, snakemake最后创建了符号链接(symbolic link):
Job counts:
count jobs
1 all
6 translation
7
作为确认,这是生成的目录结构:
english
├── berry
│   └── windu
├── chocolate
│   ├── han
│   ├── luke
│   └── vader
└── vanilla
├── leia
└── yoda
french_translation
├── baie -> ../english/berry
├── chocolat -> ../english/chocolate
└── vanille -> ../english/vanilla
german_translation
├── beere -> ../english/berry
├── schokolade -> ../english/chocolate
└── vanille -> ../english/vanilla

9 directories, 6 files
但是,除了不运行 snakemake 就无法创建此结构。两次(并在两者之间修改目标),即使只是重新运行工作流也会导致错误:
Building DAG of jobs...
ChildIOException:
File/directory is a child to another output:
/tmp/snakemake.test/english/berry
/tmp/snakemake.test/english/berry/windu
所以我的问题是: 如何在工作的 Snakefile 中实现上述逻辑?
请注意,我不是在寻求更改 YAML 文件和/或 Snakefile 中的数据表示的建议。这只是一个突出(和隔离)我在更复杂场景中遇到的问题的示例。
可悲的是,虽然到目前为止我自己无法解决这个问题,但我设法获得了一个可以工作的 GNU make 版本(即使“YAML 解析”充其量是 hackish):
### Setup ###

configfile := config.yaml


### Targets ###

votes := $(shell awk ' \
NR == 1 { next } \
/^[^ ]/ { exit } \
NF == 1 { sub(":", "", $$1); dir = "english/" $$1 "/"; next } \
{ print dir $$2 } \
' '$(configfile)')

translations := $(shell awk ' \
NR == 1 { next } \
/^[^ ]/ { trans = 1; next } \
! trans { next } \
{ sub(":", "", $$1) } \
NF == 1 { dir = $$1 "_translation/"; next } \
{ print dir $$1 } \
' '$(configfile)')


### Commands ###

create_file_cmd = touch '$@'

create_dir_cmd = mkdir --parent '$@'

relative_symlink_cmd = ln --symbolic --relative '$<' '$@'


### Rules ###

all : $(votes) $(translations)

$(sort $(dir $(votes) $(translations))) : % :
$(create_dir_cmd)
$(foreach vote, $(votes), $(eval $(vote) : | $(dir $(vote))))
$(votes) : % :
$(create_file_cmd)

translation_targets := $(shell awk ' \
NR == 1 { next } \
/^[^ ]/ { trans = 1; next } \
! trans { next } \
NF != 1 { print "english/" $$2 "/"} \
' '$(configfile)')
define translation
$(word $(1), $(translations)) : $(word $(1), $(translation_targets)) | $(dir $(word $(1), $(translations)))
$$(relative_symlink_cmd)
endef
$(foreach i, $(shell seq 1 $(words $(translations))), $(eval $(call translation, $(i))))
运行 make这工作得很好:
mkdir --parent 'english/chocolate/'
touch 'english/chocolate/vader'
touch 'english/chocolate/luke'
touch 'english/chocolate/han'
mkdir --parent 'english/vanilla/'
touch 'english/vanilla/yoda'
touch 'english/vanilla/leia'
mkdir --parent 'english/berry/'
touch 'english/berry/windu'
mkdir --parent 'french_translation/'
ln --symbolic --relative 'english/chocolate/' 'french_translation/chocolat'
ln --symbolic --relative 'english/vanilla/' 'french_translation/vanille'
ln --symbolic --relative 'english/berry/' 'french_translation/baie'
mkdir --parent 'german_translation/'
ln --symbolic --relative 'english/chocolate/' 'german_translation/schokolade'
ln --symbolic --relative 'english/vanilla/' 'german_translation/vanille'
ln --symbolic --relative 'english/berry/' 'german_translation/beere'
生成的树与上面显示的树相同。
此外,运行 make再次起作用:
make: Nothing to be done for 'all'.
所以我真的希望解决方案不是回到老式的 GNU make 以及我多年来内化的所有不可读的黑客,而是有一种方法可以说服 Snakemake 也按照我的要求去做。 ;-)
以防万一:这是使用 Snakemake 版本 5.7.1 测试的。

编辑:
  • 根据 @MadScientist 修复了 GNU make 警告的comment .
  • 由于目前的一般反馈表明 Snakemake 无法做到这一点,I cross-posted this as a feature request over on Snakemake's GitHub (在赏金到期之前)。
  • 简体 relative_symlink_cmd根据 @Nickcomment .
  • 最佳答案

    这是解决您的第一个问题的一种方法(即,只运行一次snakemake 以获得所有所需的输出)。我使用规则 english 的输出文件作为规则的输入 translation , 并修改后一条规则的 shell 命令以反射(reflect)这一点。根据我的经验,使用目录作为输入并不适用于snakemake,如果我没记错的话,directory()标记 input被忽略。
    相关代码更改:

    relative_symlink_cmd = """ln -s \
    "$(realpath --relative-to="$(dirname '{output}')" "$(dirname {input[0]})")" \
    '{output}'"""

    rule translation:
    input: lambda wc: ["english/" + config["translations"][wc.lang][wc.trans] + "/" + voter for voter in config['flavours'][config["translations"][wc.lang][wc.trans]]]
    output: directory("{lang}_translation/{trans}")
    shell: relative_symlink_cmd
    您的第二个问题很棘手,因为当您再次运行snakemake 时,它​​会将符号链接(symbolic link)解析为相应的源文件,这会导致 ChildIOException错误。这可以通过替换 relative_symlink_cmd 来验证制作自己的目录而不是符号链接(symbolic link),如下所示。在这种情况下,snakemake 按预期工作。
    relative_symlink_cmd = """mkdir -p '{output}'"""
    我不知道如何解决这个问题。

    关于python - 通过 Snakemake 进行符号链接(symbolic link)(自动生成)目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62818855/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com