Comment rendre l'entrée Snakemake facultative mais pas vide?

Dec 10 2020

Je construis un script SQL à partir de données texte. La (partie de) script doit être constituée d'une CREATE TABLEinstruction et d'une INSERT INTOinstruction facultative . Les valeurs de INSERT INTOstatement sont tirées de la liste des fichiers, chacun peut exister ou non; toutes les valeurs des fichiers existants sont fusionnées. La partie cruciale est que la INSERT INTOdéclaration doit être ignorée chaque fois qu'aucun fichier de données n'existe.

J'ai créé un script dans Snakemake qui fait cela. Il existe deux règles ambiguës qui créent un script: celle qui crée un script pour les données vides et celle qui crée une table mais insère des données (l'ambiguïté est résolue avec une ruleorderinstruction).

La partie intéressante est la règle qui fusionne les valeurs des fichiers de données. Il doit créer la sortie chaque fois qu'au moins une entrée est présente, et cette règle ne doit pas être considérée autrement. Il y a deux difficultés: rendre chaque entrée facultative et empêcher Snakemake d'utiliser cette règle chaque fois qu'aucun fichier n'existe. J'ai fait ça avec un truc:

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: ...

La require_at_least_onefonction prend une liste de noms de fichiers et filtre les noms de fichiers qui ne représentent pas un fichier. Cela permet de rendre chaque entrée facultative. Pour le cas d'angle où aucun fichier n'existe, cette fonction renvoie une valeur spéciale qui représente un fichier inexistant. Cela permet d'élaguer cette branche et de préférer celle qui crée un script sans INSERTdéclaration.

J'ai envie de réinventer la roue, d'ailleurs le truc "non_existing_file" a l'air un peu sale. Y a-t-il des moyens meilleurs et idiomatiques de faire cela dans Snakemake?

Réponses

silence Feb 11 2021 at 16:24

ma solution serait quelque chose du genre que vous ne devriez pas forcer snakemake à utiliser ou à ne pas utiliser une règle à l'intérieur de la règle, mais spécifier les sorties dont vous avez besoin et snakemake décidera s'il doit utiliser la règle. Donc, pour votre exemple, je ferais quelque chose comme:

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: ...

Cela exécutera la règle merge_values ​​uniquement si required_files n'est pas vide.