diff --git a/changelog.md b/changelog.md index 135e7274..7762a005 100644 --- a/changelog.md +++ b/changelog.md @@ -39,7 +39,9 @@ resolution - Added seed parameter to `downsample_fastq` component. - Added bacmet database to `abricate` component. - Added default docker option to avoid docker permission errors. -- Changed the default URL generated by inspect and report commands. +- Added tests for `mash_screen`, `mash_dist`, `mapping_patlas` python +templates +- Changed the default URL generated by inspect and report commands. - Added directives to `-L` parameter of build module. ### Bug fixes diff --git a/docs/dev/create_template.rst b/docs/dev/create_template.rst index 473d37c2..47615571 100644 --- a/docs/dev/create_template.rst +++ b/docs/dev/create_template.rst @@ -85,13 +85,16 @@ Versioning and logging FlowCraft has a specific ``logger`` (:func:`~flowcraft.templates.flowcraft_utils.flowcraft_base.get_logger`) and versioning system that can be imported from -:mod:`flowcraft.templates.flowcraft_utils`: :: +:mod:`flowcraft.templates.flowcraft_utils` as follows: :: # the module that imports the logger and the decorator class for versioning # of the script itself and other software used in the script - from flowcraft_utils.flowcraft_base import get_logger, MainWrapper - + try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper + except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, MainWrapper +The ``try/except`` is used for test purposes. Logger ^^^^^^ diff --git a/flowcraft/templates/assembly_report.py b/flowcraft/templates/assembly_report.py index 9f790ef0..867fa5b1 100644 --- a/flowcraft/templates/assembly_report.py +++ b/flowcraft/templates/assembly_report.py @@ -43,7 +43,11 @@ from collections import OrderedDict from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/downsample_fastq.py b/flowcraft/templates/downsample_fastq.py index 3f7bf746..d44acbcb 100755 --- a/flowcraft/templates/downsample_fastq.py +++ b/flowcraft/templates/downsample_fastq.py @@ -47,7 +47,11 @@ from os.path import basename -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/fastqc.py b/flowcraft/templates/fastqc.py index 30144b0d..b2d56fac 100644 --- a/flowcraft/templates/fastqc.py +++ b/flowcraft/templates/fastqc.py @@ -42,7 +42,11 @@ from subprocess import PIPE from os.path import exists, join -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/fastqc_report.py b/flowcraft/templates/fastqc_report.py index debe03d1..38df5252 100644 --- a/flowcraft/templates/fastqc_report.py +++ b/flowcraft/templates/fastqc_report.py @@ -58,7 +58,11 @@ from collections import OrderedDict -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/integrity_coverage.py b/flowcraft/templates/integrity_coverage.py index 71007ba6..3a70a6cf 100755 --- a/flowcraft/templates/integrity_coverage.py +++ b/flowcraft/templates/integrity_coverage.py @@ -86,7 +86,11 @@ from itertools import chain -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/mapping2json.py b/flowcraft/templates/mapping2json.py index cf9c220f..dd729b2d 100755 --- a/flowcraft/templates/mapping2json.py +++ b/flowcraft/templates/mapping2json.py @@ -37,7 +37,11 @@ import sys from pympler.asizeof import asizeof -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) @@ -46,18 +50,21 @@ JSON_LENGTH = '$lengthJson' CUTOFF = '$cov_cutoff' SAMPLE_ID = '$sample_id' -else: - DEPTH_TXT = sys.argv[1] - JSON_LENGTH = sys.argv[2] - CUTOFF = sys.argv[3] - SAMPLE_ID = sys.argv[4] - -logger.debug("List of arguments given: {}".format([ - DEPTH_TXT, - JSON_LENGTH, - CUTOFF, - SAMPLE_ID -])) + +try: + logger.debug("List of arguments given: {}".format([ + DEPTH_TXT, + JSON_LENGTH, + CUTOFF, + SAMPLE_ID + ])) +except NameError: + # this is used for unit tests where this variables are not required to + # test some of the functions within this script + DEPTH_TXT, JSON_LENGTH, CUTOFF, SAMPLE_ID = None, None, None, None + logger.debug("Input variables 'DEPTH_TXT, JSON_LENGTH, CUTOFF and " + "SAMPLE_ID' are not defined. Are you using this for " + "unit tests?") # check if all variables are assigned if DEPTH_TXT and JSON_LENGTH and SAMPLE_ID and CUTOFF: @@ -119,6 +126,12 @@ def generate_jsons(depth_dic_coverage, plasmid_length, cutoff): ---------- depth_dic_coverage: dict dictionary with the coverage per position for each plasmid + plasmid_length: dict + dictionary with the correspondence between each reference plasmid and + its length + cutoff: float + the value of percentage identity that is used to discard entries in + the txt file generated by mash screen. Returns ------- @@ -161,14 +174,16 @@ def generate_jsons(depth_dic_coverage, plasmid_length, cutoff): # array to store the values of coverage for each interval array_of_cov = [] # the counter that is used to output the values per interval - reset_counter = 0 + reset_counter = 1 # loop to generate dict_cov logger.info("Generating plot data for plasmid: {}".format(ref)) for i in range(int(plasmid_length[ref])): # checks if key for a given position is in dict and if so # adds it to array of cov, otherwise it will add a 0 try: - array_of_cov.append(int(depth_dic_coverage[ref][str(i)])) + array_of_cov.append(int( + depth_dic_coverage[ref][str(i + 1)] + )) except KeyError: array_of_cov.append(0) @@ -178,7 +193,8 @@ def generate_jsons(depth_dic_coverage, plasmid_length, cutoff): int(sum(array_of_cov)/len(array_of_cov)) ) # reset counter - reset_counter = 0 + reset_counter = 1 + array_of_cov = [] else: # if counter is less than interval then sums 1 reset_counter += 1 diff --git a/flowcraft/templates/mashdist2json.py b/flowcraft/templates/mashdist2json.py index c066c837..f4023034 100644 --- a/flowcraft/templates/mashdist2json.py +++ b/flowcraft/templates/mashdist2json.py @@ -29,7 +29,11 @@ import json import os -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) @@ -56,10 +60,8 @@ def send_to_output(master_dict, mash_output, sample_id, assembly_file): master_dict: dict dictionary that stores all entries for a specific query sequence in multi-fasta given to mash dist as input against patlas database - last_seq: str - string that stores the last sequence that was parsed before writing to - file and therefore after the change of query sequence between different - rows on the input file + assembly_file: str + the string with the assembly file name mash_output: str the name/path of input file to main function, i.e., the name/path of the mash dist output txt file. @@ -129,6 +131,8 @@ def main(mash_output, hash_cutoff, sample_id, assembly_file): to the results outputs sample_id: str The name of the sample. + assembly_file: str + The name of the assembly file """ input_f = open(mash_output, "r") diff --git a/flowcraft/templates/mashscreen2json.py b/flowcraft/templates/mashscreen2json.py index 75d10148..b2f206a6 100644 --- a/flowcraft/templates/mashscreen2json.py +++ b/flowcraft/templates/mashscreen2json.py @@ -30,7 +30,11 @@ import os import json -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) @@ -42,9 +46,10 @@ logger.debug("MASH_TXT: {}".format(MASH_TXT)) logger.debug("SAMPLE_ID: {}".format(MASH_TXT)) + @MainWrapper def main(mash_output, sample_id): - ''' + """ converts top results from mash screen txt output to json format Parameters @@ -55,7 +60,7 @@ def main(mash_output, sample_id): sample_id: str sample name - ''' + """ logger.info("Reading file : {}".format(mash_output)) read_mash_output = open(mash_output) @@ -94,7 +99,7 @@ def main(mash_output, sample_id): # estimated copy number copy_number = int(float(v[1]) / median_cutoff) # assure that plasmid as at least twice the median coverage depth - if float(v[1]) > median_cutoff: + if float(v[1]) >= median_cutoff: filtered_dic["_".join(k.split("_")[0:3])] = [ round(float(v[0]),2), copy_number @@ -103,7 +108,8 @@ def main(mash_output, sample_id): "Exported dictionary has {} entries".format(len(filtered_dic))) else: # if no entries were found raise an error - logger.error("No matches were found using mash screen for the queried reads") + logger.error("No matches were found using mash screen for the queried " + "reads") output_json.write(json.dumps(filtered_dic)) output_json.close() diff --git a/flowcraft/templates/megahit.py b/flowcraft/templates/megahit.py index 6f7cefda..fe093a40 100644 --- a/flowcraft/templates/megahit.py +++ b/flowcraft/templates/megahit.py @@ -47,7 +47,11 @@ from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/metaspades.py b/flowcraft/templates/metaspades.py index 80a4d4db..bf8140a1 100644 --- a/flowcraft/templates/metaspades.py +++ b/flowcraft/templates/metaspades.py @@ -45,7 +45,11 @@ from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/pATLAS_consensus_json.py b/flowcraft/templates/pATLAS_consensus_json.py index 19e96a2c..fa925b89 100644 --- a/flowcraft/templates/pATLAS_consensus_json.py +++ b/flowcraft/templates/pATLAS_consensus_json.py @@ -33,7 +33,10 @@ import os import json -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, MainWrapper logger = get_logger(__file__) @@ -80,7 +83,6 @@ def main(list_of_jsons): json_dic = { "patlas_mashscreen": json_dict - # TODO add information for report webapp } with open(".report.json", "w") as json_report: @@ -88,4 +90,4 @@ def main(list_of_jsons): if __name__ == "__main__": - main(LIST_OF_FILES) \ No newline at end of file + main(LIST_OF_FILES) diff --git a/flowcraft/templates/pipeline_status.py b/flowcraft/templates/pipeline_status.py index ee7eb3fb..26122251 100644 --- a/flowcraft/templates/pipeline_status.py +++ b/flowcraft/templates/pipeline_status.py @@ -29,7 +29,11 @@ from os.path import join -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/process_abricate.py b/flowcraft/templates/process_abricate.py index 605d0b49..ac3d41b7 100755 --- a/flowcraft/templates/process_abricate.py +++ b/flowcraft/templates/process_abricate.py @@ -39,7 +39,11 @@ from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/process_assembly.py b/flowcraft/templates/process_assembly.py index 23aab3e5..6f574c53 100644 --- a/flowcraft/templates/process_assembly.py +++ b/flowcraft/templates/process_assembly.py @@ -53,7 +53,11 @@ import json import operator -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/process_assembly_mapping.py b/flowcraft/templates/process_assembly_mapping.py index 6e892341..8408ebcc 100644 --- a/flowcraft/templates/process_assembly_mapping.py +++ b/flowcraft/templates/process_assembly_mapping.py @@ -59,7 +59,11 @@ from subprocess import PIPE from collections import OrderedDict -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/process_mapping.py b/flowcraft/templates/process_mapping.py index 9e97d990..53860cb2 100644 --- a/flowcraft/templates/process_mapping.py +++ b/flowcraft/templates/process_mapping.py @@ -1,13 +1,5 @@ #!/usr/bin/env python3 -import re -import os -import json - -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper - - - """ Purpose ------- @@ -36,6 +28,16 @@ """ +import re +import os +import json + +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper + __version__ = "1.0.1" __build__ = "10.09.2018" __template__ = "remove_host-nf" diff --git a/flowcraft/templates/process_newick.py b/flowcraft/templates/process_newick.py index 942cbe72..74bb3827 100644 --- a/flowcraft/templates/process_newick.py +++ b/flowcraft/templates/process_newick.py @@ -1,22 +1,14 @@ #!/usr/bin/env python3 -import os -import json -import dendropy - -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper - - - """ Purpose ------- This module is intended to process the newick generated by - a proces to generate a report. The newick tree will be - rooted (midpoint). - - + a proces to generate a report. The newick tree will be + rooted (midpoint). + + Expected input -------------- @@ -34,6 +26,16 @@ """ +import os +import json +import dendropy + +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper + __version__ = "1.0.1" __build__ = "20.09.2018" __template__ = "raxml-nf" diff --git a/flowcraft/templates/process_viral_assembly.py b/flowcraft/templates/process_viral_assembly.py index 0f2dc882..780817d6 100644 --- a/flowcraft/templates/process_viral_assembly.py +++ b/flowcraft/templates/process_viral_assembly.py @@ -1,14 +1,5 @@ #!/usr/bin/env python3 -import os -import json -import operator -from itertools import groupby - -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper - - - """ Purpose ------- @@ -38,6 +29,17 @@ """ +import os +import json +import operator +from itertools import groupby + +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper + __version__ = "1.0.1" __build__ = "11.09.2018" __template__ = "viral_assembly-nf" diff --git a/flowcraft/templates/skesa.py b/flowcraft/templates/skesa.py index b03b2585..2130dd69 100644 --- a/flowcraft/templates/skesa.py +++ b/flowcraft/templates/skesa.py @@ -42,7 +42,11 @@ from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/spades.py b/flowcraft/templates/spades.py index 130172de..5fc3ef02 100644 --- a/flowcraft/templates/spades.py +++ b/flowcraft/templates/spades.py @@ -54,7 +54,11 @@ from subprocess import PIPE -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/split_fasta.py b/flowcraft/templates/split_fasta.py index 04b57f99..96ffc2b2 100755 --- a/flowcraft/templates/split_fasta.py +++ b/flowcraft/templates/split_fasta.py @@ -32,7 +32,11 @@ import os from itertools import groupby -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) @@ -86,4 +90,4 @@ def main(sample_id, assembly, min_size): if __name__ == '__main__': - main(SAMPLE_ID, ASSEMBLY, MIN_SIZE) \ No newline at end of file + main(SAMPLE_ID, ASSEMBLY, MIN_SIZE) diff --git a/flowcraft/templates/trimmomatic.py b/flowcraft/templates/trimmomatic.py index 0ddc28fb..a03cc2ca 100644 --- a/flowcraft/templates/trimmomatic.py +++ b/flowcraft/templates/trimmomatic.py @@ -61,7 +61,11 @@ from subprocess import PIPE from collections import OrderedDict -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/templates/trimmomatic_report.py b/flowcraft/templates/trimmomatic_report.py index bcb9aa95..11ec2cd5 100644 --- a/flowcraft/templates/trimmomatic_report.py +++ b/flowcraft/templates/trimmomatic_report.py @@ -36,7 +36,11 @@ from collections import OrderedDict -from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +try: + from flowcraft_utils.flowcraft_base import get_logger, MainWrapper +except ImportError: + from flowcraft.templates.flowcraft_utils.flowcraft_base import get_logger, \ + MainWrapper logger = get_logger(__file__) diff --git a/flowcraft/tests/data/adapters.fasta b/flowcraft/tests/data/adapters.fasta new file mode 100644 index 00000000..8ed684aa --- /dev/null +++ b/flowcraft/tests/data/adapters.fasta @@ -0,0 +1,4 @@ +>TruSeq_Universal_Adapter +AATGATACGGCGACCACCGAGATCTACACTCTTTCCCTACACGACGCTCTTCCGATCT +>TruSeq_Adapter_Index 1 +GATCGGAAGAGCACACGTCTGAACTCCAGTCACATCACGATCTCGTATGCCGTCTTCTGCTTG \ No newline at end of file diff --git a/flowcraft/tests/data/sample.fastq b/flowcraft/tests/data/sample.fastq new file mode 100644 index 00000000..f363457a --- /dev/null +++ b/flowcraft/tests/data/sample.fastq @@ -0,0 +1,4 @@ +@NB501861:13:HKFHCAFXX:1:11101:23469:1072 2:N:0:CCTAAGAC+NTAGTCGA +GGATAATCTACCTTGACGATTTGTACTGGCGTTGGTTTCTTATGAATGACAGCTAATTCGTGAGACAAATAGTAGTCATTGGTTGCATTGATAGCAGCTTCAAATGACATACCACGGTTGGCAAAATCGATTTTCTTTTTCTTTGATTTTG ++ +AAAA/EEEEEEEEEEE?@ABCDEFGHIJKLMNOPQRSTUVWXYZ' \ + '[\]^_`abcdefghijklmnopqrstuvwxyz{|}~' + + assert ic.get_qual_range(qual_str) == (33, 126) + + +def test_sanger_range(): + + sanger_quals = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHI" + + assert ic.get_qual_range(sanger_quals) == ic.RANGES["Sanger"][1] + + +def test_solexa_range(): + + solexa_quals = ";<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh" + + assert ic.get_qual_range(solexa_quals) == ic.RANGES["Solexa"][1] + + +def test_illumina13_range(): + + illumina13_quals = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh" + + assert ic.get_qual_range(illumina13_quals) == ic.RANGES["Illumina-1.3"][1] + + +def test_illumina15_range(): + + illumina15_quals = "BCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghi" + + assert ic.get_qual_range(illumina15_quals) == ic.RANGES["Illumina-1.5"][1] + + +def test_illumina18_range(): + + illumina18_quals = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ" + + assert ic.get_qual_range(illumina18_quals) == ic.RANGES["Illumina-1.8"][1] + + +def test_get_encoding_solexa(): + + solexa_quals = "=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefgh" + + quals = ic.get_qual_range(solexa_quals) + + assert ic.get_encodings_in_range(*quals) == (["Solexa"], [64]) + + +def test_get_encoding_illumina18(): + + illumina18_quals = "&'()*+,-./0123456789:;<=>?@ABCDEFGHIJ" + + quals = ic.get_qual_range(illumina18_quals) + + assert ic.get_encodings_in_range(*quals) == (["Illumina-1.8"], [33]) + + +def test_get_ambiguous_encoding(): + + sanger_illumina = "&'()*+,-./0123456789:;<=>?@ABCDEFGHI" + + quals = ic.get_qual_range(sanger_illumina) + + assert ic.get_encodings_in_range(*quals) == (["Sanger", "Illumina-1.8"], + [33, 33]) + + +@pytest.fixture +def temp_env(): + # Create a temporary directory and move there + tmp_dir = ".temp" + if not os.path.exists(tmp_dir): + os.makedirs(tmp_dir) + os.chdir(tmp_dir) + yield + # Exit and remove temporary directory + os.chdir(os.pardir) + shutil.rmtree(tmp_dir) + + +def test_full_run_files(temp_env): + + opts = [ + "sample", + ["../flowcraft/tests/data/sample_1.fastq.gz", + "../flowcraft/tests/data/sample_2.fastq.gz"], + 2.1, + 15, + "" + ] + + ic.MAGIC_DICT = MAGIC_DICT + ic.main(*opts) + + assert sorted(os.listdir(".")) == [ + '.fail', '.report.json', '.status', '.versions', 'sample_coverage', + 'sample_encoding', 'sample_max_len','sample_phred', 'sample_report' + ] + + +def test_full_run_success(temp_env): + + opts = [ + "sample", + ["../flowcraft/tests/data/sample_1.fastq.gz", + "../flowcraft/tests/data/sample_2.fastq.gz"], + 2.1, + 15, + "" + ] + + ic.MAGIC_DICT = MAGIC_DICT + ic.main(*opts) + + with open("sample_encoding") as fh: + res = sorted(fh.read().split(",")) + + assert res == ["Illumina-1.8", "Sanger"] + + +def test_low_coverage(temp_env): + + opts = [ + "sample", + ["../flowcraft/tests/data/sample_1.fastq.gz", "../flowcraft/tests/data/sample_2.fastq.gz"], + 2.1, + 15, + "" + ] + + ic.MAGIC_DICT = MAGIC_DICT + ic.main(*opts) + + with open("sample_coverage") as fh: + res = fh.read() + + assert res == "fail" + + +def test_coverage_pass(temp_env): + + opts = [ + "sample", + ["../flowcraft/tests/data/sample_1.fastq.gz", "../flowcraft/tests/data/sample_2.fastq.gz"], + 2.1e-7, + 15, + "" + ] + + ic.MAGIC_DICT = MAGIC_DICT + ic.main(*opts) + + with open("sample_coverage") as fh: + res = fh.read() + + assert res == "1438.1" diff --git a/flowcraft/tests/template_tests/test_mapping2json.py b/flowcraft/tests/template_tests/test_mapping2json.py new file mode 100644 index 00000000..0af93e43 --- /dev/null +++ b/flowcraft/tests/template_tests/test_mapping2json.py @@ -0,0 +1,127 @@ +import os +import json +import pytest +import flowcraft.templates.mapping2json as mapping2json + +depth_dict_coverage = { + "ACC1": { + "1": 20, + "2": 30, + "3": 50, + "4": 40, + "5": 30, + "6": 20, + "7": 20, + "8": 40, + "9": 30, + "10": 20 + }, + "ACC2": { + "1": 20, + "2": 30, + "3": 50, + "4": 40, + "7": 20, + "8": 40, + "9": 30, + "10": 20 + } +} + +plasmid_length = { + "ACC1": "10", + "ACC2": "10" +} + + +@pytest.fixture +def fetch_file(tmpdir, request): + # create a temporary file depth txt file + depth_file = tmpdir.join("test_depth_file.txt") + depth_file.write("ACC1\t1\t30") + # creates a temporary file with the json_dict + json_dict = tmpdir.join("test_json_dict.json") + json_dict.write('{"ACC1": 2000}') + + # finalizer statement that removes .report.json + def remove_test_files(): + os.remove(".report.json") + request.addfinalizer(remove_test_files) + + return json_dict, str(depth_file) + + +def test_depth_file_reader(tmpdir): + """ + test the output of depth_file_reader_function to be a given dict + """ + + # create a temporary file to make a dict from + file_handle = tmpdir.join("test_depth_file.txt") + file_handle.write("seq1\t1\t30") + + # execute the function to get the dict + result_dict = mapping2json.depth_file_reader(open(str(file_handle))) + + assert result_dict == {"seq1": {"1": 30}} + + +def test_generate_jsons(): + """ + Test if the returns from this function are the expected results + """ + perc_bases_cov, dict_cov = mapping2json.generate_jsons(depth_dict_coverage, + plasmid_length, 0.9) + + # asserts if all the returned values are the expected ones + assert (perc_bases_cov, dict_cov) == ( + {"ACC1": 1.0}, + {"ACC1": { + "length": 10, + "interval": 1, + "values": [20, 30, 50, 40, 30, 20, 20, 40, 30, 20] + }} + ) + + +def test_generate_file(fetch_file): + """ + This function tests if the output json file is generated + """ + json_dict, depth_file = fetch_file + # executes the function to be tested + mapping2json.main(str(depth_file), str(json_dict), "0", "test") + assert os.path.isfile("{}_mapping.json".format(depth_file)) + + +def test_generate_report(fetch_file): + """ + This tests if the report.json file is generated + """ + json_dict, depth_file = fetch_file + # executes the function to be tested + mapping2json.main(str(depth_file), str(json_dict), "0", "test") + assert os.path.isfile(".report.json") + + +def test_generated_dict(fetch_file): + """ + This function checks if the file contains a dict + """ + json_dict, depth_file = fetch_file + # executes the function to be tested + mapping2json.main(str(depth_file), str(json_dict), "0", "test") + result_dict = json.load(open("{}_mapping.json".format(str(depth_file)))) + assert isinstance(result_dict, dict) + + +def test_generated_dict_contents(fetch_file): + """ + This function tests if the dictionary in the file has the required fields + """ + expected_dict = {"ACC1": 0.0} + json_dict, depth_file = fetch_file + # executes the function to be tested + mapping2json.main(str(depth_file), str(json_dict), "0", "test") + result_dict = json.load(open("{}_mapping.json".format(str(depth_file)))) + assert result_dict == expected_dict diff --git a/flowcraft/tests/template_tests/test_mashdist2json.py b/flowcraft/tests/template_tests/test_mashdist2json.py new file mode 100644 index 00000000..5278db8c --- /dev/null +++ b/flowcraft/tests/template_tests/test_mashdist2json.py @@ -0,0 +1,58 @@ +import os +import json +import pytest +import flowcraft.templates.mashdist2json as mashdist2json + + +@pytest.fixture +def fetch_file(tmpdir, request): + # create a temporary file mash screen txt file + mash_file = tmpdir.join("test_depth_file.txt") + mash_file.write("ACC1\tseq1\t0\t900/1000") + + # finalizer statement that removes .report.json + def remove_test_files(): + os.remove(".report.json") + request.addfinalizer(remove_test_files) + + return str(mash_file) + + +def test_generate_file(fetch_file): + """ + This function tests if the files generated by this template script are + created + """ + mash_file = fetch_file + mashdist2json.main(str(mash_file), "0.5", "test", "assembly_file") + assert os.path.isfile("{}.json".format(mash_file.split(".")[0])) + + +def test_generate_report(fetch_file): + """ + This tests if the report.json file is generated + """ + mash_file = fetch_file + mashdist2json.main(str(mash_file), "0.5", "test", "assembly_file") + assert os.path.isfile(".report.json") + + +def test_generated_dict(fetch_file): + """ + This function checks if the file contains a dict + """ + mash_file = fetch_file + mashdist2json.main(str(mash_file), "0.5", "test", "assembly_file") + result_dict = json.load(open("{}.json".format( + str(mash_file).split(".")[0]))) + assert isinstance(result_dict, dict) + + +def test_generated_dict_contents(fetch_file): + # the expected result from loading the dictionary in the generated file + expected_dict = {"ACC1": [1.0, 0.9, "seq1"]} + mash_file = fetch_file + mashdist2json.main(str(mash_file), "0.5", "test", "assembly_file") + result_dict = json.load(open("{}.json".format( + str(mash_file).split(".")[0]))) + assert result_dict == expected_dict diff --git a/flowcraft/tests/template_tests/test_mashscreen2json.py b/flowcraft/tests/template_tests/test_mashscreen2json.py new file mode 100644 index 00000000..6df5b96b --- /dev/null +++ b/flowcraft/tests/template_tests/test_mashscreen2json.py @@ -0,0 +1,58 @@ +import os +import json +import pytest +import flowcraft.templates.mashscreen2json as mashscreen2json + + +@pytest.fixture +def fetch_file(tmpdir, request): + # create a temporary file mash screen txt file + mash_file = tmpdir.join("test_depth_file.txt") + mash_file.write("100\tNA\t30\tNA\tACC1") + + # finalizer statement that removes .report.json + def remove_test_files(): + os.remove(".report.json") + request.addfinalizer(remove_test_files) + + return str(mash_file) + + +def test_generate_file(fetch_file): + """ + This function tests if the files generated by this template script are + created + """ + mash_file = fetch_file + mashscreen2json.main(str(mash_file), "test") + assert os.path.isfile("{}.json".format(mash_file.split(".")[0])) + + +def test_generate_report(fetch_file): + """ + This tests if the report.json file is generated + """ + mash_file = fetch_file + mashscreen2json.main(str(mash_file), "test") + assert os.path.isfile(".report.json") + + +def test_generated_dict(fetch_file): + """ + This function checks if the file contains a dict + """ + mash_file = fetch_file + mashscreen2json.main(str(mash_file), "test") + result_dict = json.load(open("{}.json".format( + str(mash_file).split(".")[0]))) + assert isinstance(result_dict, dict) + + +def test_generated_dict_contents(fetch_file): + # the expected result from loading the dictionary in the generated file + expected_dict = {"ACC1": [100.0, 1]} + mash_file = fetch_file + mashscreen2json.main(str(mash_file), "test") + result_dict = json.load(open("{}.json".format( + str(mash_file).split(".")[0]))) + assert result_dict == expected_dict diff --git a/flowcraft/tests/template_tests/test_pATLAS_consensus_json.py b/flowcraft/tests/template_tests/test_pATLAS_consensus_json.py new file mode 100644 index 00000000..b0239d5f --- /dev/null +++ b/flowcraft/tests/template_tests/test_pATLAS_consensus_json.py @@ -0,0 +1,87 @@ +import os +import json +import pytest +import flowcraft.templates.pATLAS_consensus_json as pATLAS_consensus_json + + +@pytest.fixture +def fetch_file(tmpdir, request): + # create a temporary file mash screen txt file + mash_file = tmpdir.join("mash_file.txt") + depth_file = tmpdir.join("test_depth_file.txt") + mash_file.write('{"ACC1": ["0.9", "1"]}') + depth_file.write('{"ACC1": 0.9}') + + list_of_files = [str(mash_file), str(depth_file)] + + # finalizer statement that removes .report.json + def remove_test_files(): + os.remove(".report.json") + request.addfinalizer(remove_test_files) + + return list_of_files + + +def test_generate_file(fetch_file): + """ + Check if consensus output file is generated + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + assert os.path.isfile("consensus_file.json") + + +def test_generate_report(fetch_file): + """ + This tests if the report.json file is generated + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + assert os.path.isfile(".report.json") + + +def test_generated_dict(fetch_file): + """ + This function checks if the file contains a dict + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + result_dict = json.load(open("consensus_file.json")) + assert isinstance(result_dict, dict) + + +def test_generated_dict_contents1(fetch_file): + """ + Checks if accession in both expected and result dict is the same + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + result_dict = json.load(open("consensus_file.json")) + assert list(result_dict.keys())[0] == "ACC1" + + +def test_generated_dict_contents2(fetch_file): + """ + checks if the resulting values for each type of file are the proper type + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + result_dict = json.load(open("consensus_file.json")) + first_file_values = list(result_dict[ + list(result_dict.keys())[0]].values())[0] + second_file_values = list(result_dict[ + list(result_dict.keys())[0]].values())[1] + list_of_checks = [isinstance(first_file_values, list), + isinstance(second_file_values, float)] + + assert all(list_of_checks) + + +def test_generated_dict_contents3(fetch_file): + """ + checks that the accession in dict must have two keys + """ + list_of_files = fetch_file + pATLAS_consensus_json.main(list_of_files) + result_dict = json.load(open("consensus_file.json")) + assert len(list(result_dict[list(result_dict.keys())[0]].keys())) == 2 diff --git a/flowcraft/tests/test_pipeline_parser.py b/flowcraft/tests/test_pipeline_parser.py index e45fe6b3..20f7f53c 100644 --- a/flowcraft/tests/test_pipeline_parser.py +++ b/flowcraft/tests/test_pipeline_parser.py @@ -281,6 +281,7 @@ def test_unique_id_len(): res_str, res_ids = ps.add_unique_identifiers(pip_str) assert res_str.replace(" ", "") == res_list[x].replace(" ", "") + def test_remove_id(): pip_list = [ @@ -345,4 +346,4 @@ def test_remove_id(): for x, pip_str in enumerate(pip_list): res_str, res_ids = ps.add_unique_identifiers(pip_str) res = ps.remove_unique_identifiers(res_ids, pipeline_mod_links[x]) - assert json.dumps(res) == json.dumps(pipeline_exp_links[x]) \ No newline at end of file + assert json.dumps(res) == json.dumps(pipeline_exp_links[x]) diff --git a/flowcraft/tests/test_sanity.py b/flowcraft/tests/test_sanity.py index 06e188c0..0deff508 100644 --- a/flowcraft/tests/test_sanity.py +++ b/flowcraft/tests/test_sanity.py @@ -16,6 +16,7 @@ def not_raises(exception, msg): except exception: raise pytest.fail(msg) + def test_empty_tasks(): pipeline_strs = [ " ",