diff --git a/wdl2cwl/main.py b/wdl2cwl/main.py index a56b5300..083cc539 100644 --- a/wdl2cwl/main.py +++ b/wdl2cwl/main.py @@ -727,7 +727,11 @@ def get_workflow_outputs( with WDLSourceLine(item.info, ConversionException): output_name = item.name item_expr = item.info.expr - output_source = item_expr.expr.name[::-1].replace(".", "/", 1)[::-1] + if isinstance(item_expr, WDL.Expr.Get): + output_source = item_expr.expr.name[::-1].replace(".", "/", 1)[::-1] + else: + output_source = f"$({self.get_expr(item_expr)})" + # replace just the last occurrence of a period with a slash # by first reversing the string and the replace the first occurrence # then reversing the result @@ -1024,16 +1028,20 @@ def get_expr_get(self, wdl_get_expr: WDL.Expr.Get) -> str: def get_expr_ident(self, wdl_ident_expr: WDL.Expr.Ident) -> str: """Translate WDL Ident Expressions.""" - id_name = wdl_ident_expr.name + id_name: str = wdl_ident_expr.name referee = wdl_ident_expr.referee optional = wdl_ident_expr.type.optional if referee: with WDLSourceLine(referee, ConversionException): if isinstance(referee, WDL.Tree.Call): return id_name - if referee.expr and ( - wdl_ident_expr.name in self.optional_cwl_null - or wdl_ident_expr.name not in self.non_static_values + if ( + hasattr(referee, "expr") + and referee.expr is not None + and ( + wdl_ident_expr.name in self.optional_cwl_null + or wdl_ident_expr.name not in self.non_static_values + ) ): return self.get_expr(referee.expr) ident_name = get_input(id_name) diff --git a/wdl2cwl/tests/cwl_files/blast.cwl b/wdl2cwl/tests/cwl_files/blast.cwl new file mode 100644 index 00000000..fb588a4f --- /dev/null +++ b/wdl2cwl/tests/cwl_files/blast.cwl @@ -0,0 +1,335 @@ +cwlVersion: v1.2 +$graph: +- class: Workflow + id: main + inputs: + - id: blast_docker_override + type: + - string + - 'null' + - id: blast_docker + type: string + # TODO: how to translate the original? + # String blast_docker = select_first([blast_docker_override,"swr.cn-south-1.myhuaweicloud.com/cngbdb/blast:1.2"]) + - id: queryfa + type: File + - id: fname + type: string + default: '/sfs/blastdb/2019_ncov/nucl/v6/ncov' + - id: method + type: string + default: 'blastn' + - id: outfmt + type: int + default: 7 + - id: evalue + type: float + default: 10 + # TODO: how to translate the original? + # String Outfile = basename(queryfa)+'.blast_result.txt' + - id: Outfile + type: string + # runblastn task inputs, to be linked from workflow -> tool + - id: runblastn.docker + type: string + - id: runblastn.Queryfa + type: File + - id: runblastn.Fname + type: string + - id: runblastn.max_target_seqs + default: 100 + type: int + - id: runblastn.word_size + default: 28 + type: int + - id: runblastn.reward + default: 1 + type: int + - id: runblastn.penalty + default: -2 + type: int + - id: runblastn.strand + default: both + type: string + - id: runblastn.gapopen + default: 0 + type: int + - id: runblastn.gapextend + default: 0 + type: int + - id: runblastn.dust + default: "'20 64 1'" + type: string + - id: runblastn.max_hsps + type: + - int + - 'null' + - id: runblastn.tasks + default: megablast + type: string + - id: runblastn.taxids + type: + - string + - 'null' + - id: runblastn.negative_taxids + type: + - string + - 'null' + - id: runblastn.lcase_masking + default: false + type: boolean + # runblastp task inputs, to be linked from workflow -> tool + - id: runblastp.docker + type: string + - id: runblastp.Queryfa + type: File + - id: runblastp.Fname + type: string + - id: runblastp.max_target_seqs + default: 100 + type: int + - id: runblastp.word_size + default: 6 + type: int + - id: runblastp.seg + default: no + type: string + - id: runblastp.comp_based_stats + default: '2' + type: string + - id: runblastp.matrix + default: BLOSUM62 + type: string + - id: runblastp.gapopen + default: 11 + type: int + - id: runblastp.gapextend + default: 1 + type: int + - id: runblastp.max_hsps + type: + - int + - 'null' + - id: runblastp.taxids + type: + - string + - 'null' + - id: runblastp.negative_taxids + type: + - string + - 'null' + - id: runblastp.lcase_masking + default: false + type: boolean + steps: + - id: runblastp + in: + Fname: fname + Queryfa: queryfa + docker: blast_docker + outfmt: outfmt + Outfile: Outfile + threads: threads + run: runblastp + when: $(inputs.method == 'blastp') + out: [out] + - id: runblastn + in: + Fname: fname + Queryfa: queryfa + docker: blast_docker + outfmt: outfmt + evalue: evalue + Outfile: Outfile + threads: threads + run: runblastn + when: $(inputs.method == 'blastn') + out: [out] + outputs: + - id: fina_output + type: File + outputSource: + - runblastp/out + - runblastn/out + pickValue: first_non_null + +- class: CommandLineTool + id: runblastn + requirements: + - class: InitialWorkDirRequirement + listing: + - entryname: script.bash + entry: |4 + set -e + blastn -db "$(inputs.Fname)" \ + -show_gis \ + -query $(inputs.QueryFa) \ + -outfmt $(inputs.outfmt) \ + -out $(inputs.Outfile) \ + -max_target_seqs $(inputs.max_target_seqs) \ + -evalue $(inputs.evalue) \ + -word_size $(inputs.word_size) \ + -penalty $(inputs.penalty) \ + -reward $(inputs.reward) \ + -dust $(inputs.dust) \ + -gapopen $(inputs.gapopen) \ + -gapextend $(inputs.gapextend) \ + -task $(inputs.tasks) \ + -strand $(inputs.strand) \ + -num_threads $(inputs.threads) \ + $(true='-lcase_masking' false='' inputs.lcase_masking) $("-max_hsps "+ inputs.max_hsps) $("-taxids " +inputs.taxids) $("-negative_taxids " +inputs.negative_taxids)\ + hints: + - class: DockerRequirement + - class: ResourceRequirement + coresMin: 8 + ramMin: 16384 + inputs: + - id: docker + type: string + - id: Queryfa + type: File + - id: Fname + type: string + - id: Outfile + type: string + - id: threads + type: int + - id: outfmt + type: int + - id: max_target_seqs + default: 100 + type: int + - id: word_size + default: 28 + type: int + - id: reward + default: 1 + type: int + - id: penalty + default: -2 + type: int + - id: strand + default: both + type: string + - id: gapopen + default: 0 + type: int + - id: gapextend + default: 0 + type: int + - id: dust + default: "'20 64 1'" + type: string + - id: max_hsps + type: + - int + - 'null' + - id: tasks + default: megablast + type: string + - id: taxids + type: + - string + - 'null' + - id: negative_taxids + type: + - string + - 'null' + - id: lcase_masking + default: false + type: boolean + baseCommand: + - bash + - script.bash + outputs: + - id: out + type: File + outputBinding: + glob: $(inputs.Outfile) + +- class: CommandLineTool + id: runblastp + requirements: + - class: InitialWorkDirRequirement + listing: + - entryname: script.bash + entry: |4 + set -e + blastp -db "$(inputs.Fname)" \ + -query $(inputs.Queryfa) \ + -outfmt $(inputs.outfmt) \ + -out $(inputs.Outfile) \ + -max_target_seqs $(inputs.max_target_seqs) \ + -comp_based_stats $(inputs.comp_based_stats) \ + -evalue $(inputs.evalue) \ + -word_size $(inputs.word_size) \ + -matrix $(inputs.matrix) \ + -seg $(inputs.seg) \ + -gapopen $(inputs.gapopen) \ + -gapextend $(inputs.gapextend) \ + -num_threads $(inputs.threads) \ + $(true='-lcase_masking' false='' inputs.lcase_masking) $("-max_hsps "+inputs.max_hsps) $("-taxids " +inputs.taxids) $("-negative_taxids " +inputs.negative_taxids) \ + hints: + - class: DockerRequirement + - class: ResourceRequirement + coresMin: 8 + ramMin: 16384 + inputs: + - id: docker + type: string + - id: Queryfa + type: File + - id: Fname + type: string + - id: outfmt + type: string + - id: Outfile + type: string + - id: evalue + type: float + - id: threads + type: int + - id: max_target_seqs + default: 100 + type: int + - id: word_size + default: 6 + type: int + - id: seg + default: no + type: string + - id: comp_based_stats + default: '2' + type: string + - id: matrix + default: BLOSUM62 + type: string + - id: gapopen + default: 11 + type: int + - id: gapextend + default: 1 + type: int + - id: max_hsps + type: + - int + - 'null' + - id: taxids + type: + - string + - 'null' + - id: negative_taxids + type: + - string + - 'null' + - id: lcase_masking + default: false + type: boolean + baseCommand: + - bash + - script.bash + outputs: + - id: out + type: File + outputBinding: + glob: $(inputs.Outfile) diff --git a/wdl2cwl/tests/test_cwl.py b/wdl2cwl/tests/test_cwl.py index b2bd91a1..b1407df4 100644 --- a/wdl2cwl/tests/test_cwl.py +++ b/wdl2cwl/tests/test_cwl.py @@ -69,6 +69,7 @@ def test_meta(caplog: pytest.LogCaptureFixture) -> None: ("vt.wdl"), ("whatshap.wdl"), ("workflow_inputs.wdl"), + ("blast.wdl"), ], ) def test_wdls(description_name: str) -> None: diff --git a/wdl2cwl/tests/wdl_files/blast.wdl b/wdl2cwl/tests/wdl_files/blast.wdl new file mode 100644 index 00000000..450c1661 --- /dev/null +++ b/wdl2cwl/tests/wdl_files/blast.wdl @@ -0,0 +1,325 @@ +version 1.0 + +workflow blast { + input { + String? blast_docker_override + String blast_docker= select_first([blast_docker_override,"swr.cn-south-1.myhuaweicloud.com/cngbdb/blast:1.2"]) + File queryfa + String fname = '/sfs/blastdb/2019_ncov/nucl/v6/ncov' + String method = 'blastn' + Int outfmt = 7 + Float evalue = 10 + String Outfile = basename(queryfa)+'.blast_result.txt' + Int threads = 8 + } + if (method == 'blastp') { + call runblastp{ + input: + Fname = fname, + Queryfa = queryfa, + docker = blast_docker, + outfmt = outfmt, + evalue = evalue, + Outfile = Outfile, + threads = threads + } + } + if ( method == 'blastn'){ + call runblastn{ + input: + Fname = fname, + Queryfa = queryfa, + docker = blast_docker, + outfmt = outfmt, + evalue = evalue, + Outfile = Outfile, + threads = threads + } + } + if ( method == 'blastx'){ + call runblastx{ + input: + Fname = fname, + Queryfa = queryfa, + docker = blast_docker, + outfmt = outfmt, + evalue = evalue, + Outfile = Outfile, + threads = threads + } + } + if ( method == 'queryfa'){ + call runtblastn{ + input: + Fname = fname, + Queryfa = queryfa, + docker = blast_docker, + outfmt = outfmt, + evalue = evalue, + Outfile = Outfile, + threads = threads + } + } + if ( method == 'tblastx'){ + call runtblastx{ + input: + Fname = fname, + Queryfa = queryfa, + docker = blast_docker, + outfmt = outfmt, + evalue = evalue, + Outfile = Outfile, + threads = threads + } + } + output { + File fina_output =select_first([runtblastx.out,runblastp.out,runblastn.out,runblastx.out,runtblastn.out]) + } +} + +task runblastn { + input { + String docker + File Queryfa + String Fname + String Outfile + Int threads + #blast optional + Int outfmt + Int max_target_seqs = 100 + Float evalue + Int word_size = 28 + Int reward = 1 + Int penalty = -2 + String strand = 'both' + Int gapopen = 0 + Int gapextend = 0 + String dust = "'20 64 1'" + Int? max_hsps + String tasks = "megablast" + String? taxids + String? negative_taxids + Boolean lcase_masking = false + } + runtime{ + docker : docker + cpu : "8" + memory : "16G" + } + command { + set -e + blastn -db "${Fname}" \ + -show_gis \ + -query ${Queryfa} \ + -outfmt ${outfmt} \ + -out ${Outfile} \ + -max_target_seqs ${max_target_seqs} \ + -evalue ${evalue} \ + -word_size ${word_size} \ + -penalty ${penalty} \ + -reward ${reward} \ + -dust ${dust} \ + -gapopen ${gapopen} \ + -gapextend ${gapextend} \ + -task ${tasks} \ + -strand ${strand} \ + -num_threads ${threads} \ + ${true='-lcase_masking' false='' lcase_masking} ${"-max_hsps "+max_hsps} ${"-taxids " +taxids} ${"-negative_taxids " +negative_taxids}\ + + } + output { + File out = "${Outfile}" + } +} + +task runblastp { + input { + String docker + File Queryfa + String Fname + #blast optional + Int outfmt + String Outfile + Float evalue + Int threads + Int max_target_seqs = 100 + Int word_size = 6 + String seg = "no" + String comp_based_stats = "2" + String matrix = "BLOSUM62" + Int gapopen = 11 + Int gapextend = 1 + Int? max_hsps + String? taxids + String? negative_taxids + Boolean lcase_masking = false + } + runtime{ + docker : docker + cpu : "8" + memory : "16G" + } + command { + set -e + blastp -db "${Fname}" \ + -query ${Queryfa} \ + -outfmt ${outfmt} \ + -out ${Outfile} \ + -max_target_seqs ${max_target_seqs} \ + -comp_based_stats ${comp_based_stats} \ + -evalue ${evalue} \ + -word_size ${word_size} \ + -matrix ${matrix} \ + -seg ${seg} \ + -gapopen ${gapopen} \ + -gapextend ${gapextend} \ + -num_threads ${threads} \ + ${true='-lcase_masking' false='' lcase_masking} ${"-max_hsps "+max_hsps} ${"-taxids " +taxids} ${"-negative_taxids " +negative_taxids} \ + + } + output { + File out = "${Outfile}" + } +} + +task runblastx { + input { + File Queryfa + String Fname + Int outfmt + Float evalue + String Outfile + String docker + Int threads + Int max_target_seqs = 100 + Int word_size = 6 + String seg = "'12 2.2 2.5'" + String comp_based_stats = "2" + String matrix = "BLOSUM62" + Int gapopen = 11 + Int gapextend = 1 + String? taxids + String? negative_taxids + Int? max_hsps + Boolean lcase_masking = false + } + runtime{ + docker : docker + cpu : "8" + memory : "16G" + } + command { + set -e + blastx -db "${Fname}" \ + -query ${Queryfa} \ + -outfmt ${outfmt} \ + -out ${Outfile} \ + -max_target_seqs ${max_target_seqs} \ + -comp_based_stats ${comp_based_stats} \ + -evalue ${evalue} \ + -word_size ${word_size} \ + -matrix ${matrix} \ + -seg ${seg} \ + -gapopen ${gapopen} \ + -gapextend ${gapextend} \ + -num_threads ${threads} \ + ${true='-lcase_masking' false='' lcase_masking} ${"-max_hsps "+max_hsps} ${"-taxids " +taxids} ${"-negative_taxids " +negative_taxids}\ + + } + output { + File out = "$${Outfile}" + } +} + +task runtblastn { + input { + File Queryfa + String Fname + Int outfmt + Float evalue + String Outfile + String docker + Int threads + Int max_target_seqs = 100 + Int word_size = 6 + String seg = "'12 2.2 2.5'" + String comp_based_stats = "2" + String matrix = "BLOSUM62" + Int gapopen = 11 + Int gapextend = 1 + Boolean lcase_masking = false + Int? max_hsps + String? taxids + String? negative_taxids + } + runtime{ + docker :docker + cpu : "8" + memory : "16G" + } + command { + set -e + tblastn -db "${Fname}" \ + -query ${Queryfa} \ + -outfmt ${outfmt} \ + -out ${Outfile} \ + -max_target_seqs ${max_target_seqs} \ + -comp_based_stats ${comp_based_stats} \ + -evalue ${evalue} \ + -word_size ${word_size} \ + -matrix ${matrix} \ + -seg ${seg} \ + -gapopen ${gapopen} \ + -gapextend ${gapextend} \ + -num_threads ${threads} \ + ${true='-lcase_masking' false='' lcase_masking} ${"-max_hsps "+max_hsps} ${"-taxids " +taxids} ${"-negative_taxids " +negative_taxids}\ + + } + output { + File out = "${Outfile}" + } +} + +task runtblastx { + input { + File Queryfa + String Fname + Int outfmt + String Outfile + Int threads + Float evalue + String docker + String? taxids + Int word_size = 3 + Int max_target_seqs = 100 + String seg = "'12 2.2 2.5'" + String matrix = "BLOSUM62" + Boolean lcase_masking = false + String? negative_taxids + Int? max_hsps + } + runtime{ + docker :docker + cpu : "8" + memory : "16G" + } + command { + set -e + tblastx -db "${Fname}" \ + -query ${Queryfa} \ + -outfmt ${outfmt} \ + -out ${Outfile} \ + -max_target_seqs ${max_target_seqs} \ + -evalue ${evalue} \ + -word_size ${word_size} \ + -matrix ${matrix} \ + -seg ${seg} \ + -num_threads ${threads} \ + ${true='-lcase_masking' false='' lcase_masking} ${"-max_hsps "+max_hsps} ${"-taxids " +taxids} ${"-negative_taxids " +negative_taxids}\ + } + output { + File out = "${Outfile}" + } +} + +