Bagaimana cara membuat input Snakemake opsional tetapi tidak kosong?

Dec 10 2020

Saya sedang membangun skrip SQL dari data teks. Skrip (bagian dari) harus terdiri dari CREATE TABLEpernyataan dan INSERT INTOpernyataan opsional . Nilai INSERT INTOpernyataan diambil dari daftar file, masing-masing mungkin ada atau mungkin tidak; semua nilai file yang ada digabungkan. Bagian terpenting adalah bahwa INSERT INTOpernyataan tersebut harus dilewati setiap kali tidak ada file data yang ada.

Saya telah membuat skrip di Snakemake yang melakukan itu. Ada dua aturan ambigu yang membuat skrip: aturan yang membuat skrip untuk data kosong, dan aturan yang membuat tabel tetapi menyisipkan data (ambiguitas diselesaikan dengan ruleorderpernyataan).

Bagian yang menarik adalah aturan yang menggabungkan nilai dari file data. Ini akan membuat keluaran setiap kali ada setidaknya satu masukan, dan aturan ini tidak akan dianggap sebaliknya. Ada dua kesulitan: membuat setiap masukan opsional, dan untuk mencegah Snakemake menggunakan aturan ini setiap kali tidak ada file. Saya telah melakukannya dengan sebuah trik:

def require_at_least_one(filelist):
    existing = [file for file in filelist if os.path.isfile(file)]
    return existing if len(existing) else "non_existing_file"

rule merge_values:
    input: require_at_least_one(expand("path_to_data/{dataset}/values", dataset=["A", "B", "C"]))
    output: ...
    shell: ...

The require_at_least_onefungsi mengambil daftar nama file, dan menyaring mereka nama file yang tidak mewakili sebuah file. Ini memungkinkan untuk membuat setiap masukan opsional. Untuk kasus sudut ketika tidak ada satu file pun, fungsi ini mengembalikan nilai khusus yang mewakili file yang tidak ada. Ini memungkinkan untuk memangkas cabang ini dan memilih cabang yang membuat skrip tanpa INSERTpernyataan.

Saya merasa ingin menemukan kembali roda, apalagi trik "non_existing_file" terlihat sedikit kotor. Apakah ada cara yang lebih baik dan idiomatis untuk melakukan itu di Snakemake?

Jawaban

silence Feb 11 2021 at 16:24

solusi saya akan menjadi sesuatu di sepanjang garis yang Anda tidak boleh memaksa snakemake untuk menggunakan atau tidak menggunakan aturan di dalam aturan tetapi tentukan output mana yang Anda butuhkan dan snakemake akan memutuskan apakah perlu menggunakan aturan tersebut. Jadi untuk contoh Anda, saya akan melakukan sesuatu sebagai:

def required_files(filelist):
    return [file for file in filelist if os.path.isfile(file)]

rule what_to_gen:
    input: 
        merged = [] if required_files(expand("path_to_data/{dataset}/values", dataset=["A", "B", "C"])) else 'merged_files.txt'

rule merge_values:
    input: required_files(expand("path_to_data/{dataset}/values", dataset=["A", "B", "C"]))
    output: 'merged_files.txt'
    shell: ...

Ini akan menjalankan aturan merge_values ​​hanya jika required_files tidak kosong.