import sys
import os
import subprocess
import shutil
import time
import logging
from Bio import SeqIO
from multiprocessing import Pool
import pysam
from telr.TELR_utility import mkdir, check_exist, format_time


def get_local_contigs(
    assembler,
    polisher,
    contig_dir,
    vcf_parsed,
    out,
    sample_name,
    bam,
    raw_reads,
    thread,
    presets,
    polish_iterations,
):
    """Perform local assembly using reads from parsed VCF file in parallel"""

    # Prepare reads used for local assembly and polishing
    sv_reads_dir = os.path.join(out, "sv_reads")

    try:
        prep_assembly_inputs(
            vcf_parsed, out, sample_name, bam, raw_reads, sv_reads_dir, read_type="sv"
        )
    except Exception as e:
        print(e)
        print("Prepare local assembly input data failed, exiting...")
        sys.exit(1)

    mkdir(contig_dir)

    k = 0
    asm_pa_list = []
    with open(vcf_parsed, "r") as input:
        for line in input:
            entry = line.replace("\n", "").split("\t")
            contig_name = "_".join([entry[0], entry[1], entry[2]])
            # rename variant reads
            sv_reads = sv_reads_dir + "/contig" + str(k)
            sv_reads_rename = sv_reads_dir + "/" + contig_name + ".reads.fa"
            os.rename(sv_reads, sv_reads_rename)
            thread_asm = 1
            asm_pa = [
                sv_reads_rename,
                contig_dir,
                contig_name,
                thread_asm,
                presets,
                assembler,
                polisher,
                polish_iterations,
            ]
            asm_pa_list.append(asm_pa)
            k = k + 1
    # run assembly in parallel
    logging.info("Perform local assembly of non-reference TE loci...")
    start_time = time.time()

    try:
        pool = Pool(processes=thread)
        contig_list = pool.map(run_assembly_polishing, asm_pa_list)
        pool.close()
        pool.join()
    except Exception as e:
        print(e)
        print("Local assembly failed, exiting...")
        sys.exit(1)

    proc_time = time.time() - start_time

    # merge all contigs
    assembly_passed_loci = set()
    merged_contigs = os.path.join(out, sample_name + ".contigs.fa")
    with open(merged_contigs, "w") as merged_output_handle:
        for contig in contig_list:
            if check_exist(contig):
                contig_name = os.path.basename(contig).replace(".cns.fa", "")
                assembly_passed_loci.add(contig_name)
                parsed_contig = os.path.join(contig_dir, contig_name + ".cns.ctg1.fa")
                with open(contig, "r") as input:
                    records = SeqIO.parse(input, "fasta")
                    for record in records:
                        if record.id == "ctg1" or record.id == "contig_1":
                            record.id = contig_name
                            record.description = "len=" + str(len(record.seq))
                            SeqIO.write(record, merged_output_handle, "fasta")
                            with open(parsed_contig, "w") as parsed_output_handle:
                                SeqIO.write(record, parsed_output_handle, "fasta")

    logging.info("Local assembly finished in " + format_time(proc_time))
    return merged_contigs, assembly_passed_loci


def run_assembly_polishing(args):
    reads = args[0]
    asm_dir = args[1]
    contig_name = args[2]
    thread = args[3]
    presets = args[4]
    assembler = args[5]
    polisher = args[6]
    polish_iterations = args[7]

    # run assembly
    if assembler == "wtdbg2":
        asm_cns = run_wtdbg2_assembly(reads, asm_dir, contig_name, thread, presets)
    else:
        asm_cns = run_flye_assembly(reads, asm_dir, contig_name, thread, presets)

    if not check_exist(asm_cns):
        print("assembly failed")
        return None

    # run polishing
    if polish_iterations > 0:
        if polisher == "wtdbg2":
            asm_cns = run_wtdbg2_polishing(
                asm_cns, reads, thread, polish_iterations, presets
            )
        else:
            asm_cns = run_flye_polishing(
                asm_cns, reads, asm_dir, contig_name, thread, polish_iterations, presets
            )

    if check_exist(asm_cns):
        return asm_cns
    else:
        return None


def run_flye_polishing(
    asm_cns, reads, asm_dir, contig_name, thread, polish_iterations, presets
):
    """Run Flye polishing"""
    if presets == "pacbio":
        presets_flye = "--pacbio-raw"
    else:
        presets_flye = "--nano-raw"

    tmp_out_dir = os.path.join(asm_dir, contig_name)
    mkdir(tmp_out_dir)
    try:
        subprocess.call(
            [
                "flye",
                "--polish-target",
                asm_cns,
                presets_flye,
                reads,
                "--out-dir",
                tmp_out_dir,
                "--thread",
                str(thread),
                "--iterations",
                str(polish_iterations),
            ]
        )
    except Exception as e:
        print(e)
        print("Polishing failed, exiting...")
        return None

    # rename contig file
    polished_contig = os.path.join(
        tmp_out_dir, "polished_" + str(polish_iterations) + ".fasta"
    )
    if check_exist(polished_contig):
        os.rename(polished_contig, asm_cns)
        shutil.rmtree(tmp_out_dir)
        return asm_cns
    else:
        return None


def run_wtdbg2_polishing(asm_cns, reads, threads, polish_iterations, presets):
    """Run wtdbg2 polishing"""
    if presets == "pacbio":
        presets_minimap2 = "map-pb"
    else:
        presets_minimap2 = "map-ont"

    # polish consensus
    threads = str(min(threads, 4))
    bam = asm_cns + ".bam"
    k = 0
    while True:
        # align reads to contigs

        command = (
            "minimap2 -t "
            + threads
            + " -ax "
            + presets_minimap2
            + " -r2k "
            + asm_cns
            + " "
            + reads
            + " | samtools sort -@"
            + threads
            + " > "
            + bam
        )
        try:
            subprocess.run(
                command,
                shell=True,
                timeout=300,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.STDOUT,
            )
        except subprocess.TimeoutExpired:
            print("fail to map reads to contig: " + asm_cns)
            return

        # run wtpoa-cns to get polished contig
        cns_tmp = asm_cns + ".tmp"
        command = (
            "samtools view -F0x900 "
            + bam
            + " | wtpoa-cns -t "
            + threads
            + " -d "
            + asm_cns
            + " -i - -fo "
            + cns_tmp
        )
        try:
            subprocess.run(
                command,
                shell=True,
                timeout=300,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.STDOUT,
            )
        except subprocess.TimeoutExpired:
            print("fail to polish contig: " + asm_cns)
            return
        if check_exist(cns_tmp):
            os.rename(cns_tmp, asm_cns)
            os.remove(bam)
        else:
            break
        k = k + 1
        if k >= polish_iterations:
            break
    if check_exist(asm_cns):
        return asm_cns
    else:
        print("polishing failed for " + asm_cns + "\n")
    return None


def run_flye_assembly(sv_reads, asm_dir, contig_name, thread, presets):
    """Run Flye assembly"""
    if presets == "pacbio":
        presets_flye = "--pacbio-raw"
    else:
        presets_flye = "--nano-raw"

    tmp_out_dir = os.path.join(asm_dir, contig_name)
    mkdir(tmp_out_dir)
    try:
        subprocess.call(
            [
                "flye",
                presets_flye,
                sv_reads,
                "--out-dir",
                tmp_out_dir,
                "--thread",
                str(thread),
                "--iterations",
                "0",
            ]
        )
    except Exception as e:
        print(e)
        print("Assembly failed, exiting...")
        return
    # rename contigs
    contig_path = os.path.join(tmp_out_dir, "assembly.fasta")
    contig_path_new = os.path.join(asm_dir, contig_name + ".cns.fa")
    if check_exist(contig_path):
        os.rename(contig_path, contig_path_new)
        # remove tmp files
        shutil.rmtree(tmp_out_dir)
        return contig_path_new
    else:
        print("assembly failed")
        return None


def run_wtdbg2_assembly(sv_reads, asm_dir, contig_name, thread, presets):
    """Run wtdbg2 assembly"""
    if presets == "pacbio":
        presets_wtdbg2 = "rs"
    else:
        presets_wtdbg2 = "ont"
    prefix = sv_reads.replace(".reads.fa", "")
    try:
        subprocess.run(
            [
                "wtdbg2",
                "-x",
                presets_wtdbg2,
                "-q",
                "-AS",
                "1",
                "-g",
                "30k",
                "-t",
                str(thread),
                "-i",
                sv_reads,
                "-fo",
                prefix,
            ],
            timeout=300,
        )
    except subprocess.TimeoutExpired:
        print("fail to build contig layout for contig: " + contig_name)
        return
    except Exception as e:
        print(e)
        print("wtdbg2 failed, exiting...")
        return None

    # derive consensus
    contig_layout = prefix + ".ctg.lay.gz"
    if check_exist(contig_layout):
        cns_thread = str(min(thread, 4))
        consensus = prefix + ".cns.fa"
        try:
            subprocess.run(
                [
                    "wtpoa-cns",
                    "-q",
                    "-t",
                    cns_thread,
                    "-i",
                    contig_layout,
                    "-fo",
                    consensus,
                ],
                timeout=300,
            )
        except subprocess.TimeoutExpired:
            print("fail to assemble contig: " + contig_name)
            return None

    if check_exist(consensus):
        consensus_rename = os.path.join(asm_dir, contig_name + ".cns.fa")
        os.rename(consensus, consensus_rename)
        return consensus_rename
    else:
        return None


def prep_assembly_inputs(
    vcf_parsed, out, sample_name, bam, raw_reads, reads_dir, read_type="sv"
):
    """Prepare reads for local assembly"""
    # logging.info("Prepare reads for local assembly")

    if read_type == "sv":  # TODO: figure out what this does
        # extract read IDs
        read_ids = os.path.join(out, sample_name + ".id")
        with open(vcf_parsed, "r") as input, open(read_ids, "w") as output:
            for line in input:
                entry = line.replace("\n", "").split("\t")
                read_list = entry[8].split(",")
                for read in read_list:
                    output.write(read + "\n")
    else:  # TODO: think about using this for assembly, filter for cigar reads
        window = 1000
        samfile = pysam.AlignmentFile(bam, "rb")
        read_ids = os.path.join(out, sample_name + ".id")
        vcf_parsed_new = vcf_parsed + ".new"
        with open(vcf_parsed, "r") as input, open(read_ids, "w") as output, open(
            vcf_parsed_new, "w"
        ) as VCF:
            for line in input:
                entry = line.replace("\n", "").split("\t")

                # get sniffles read list
                read_list = entry[8].split(",")
                reads_sniffles = set(read_list)

                ins_chr = entry[0]
                ins_breakpoint = round((int(entry[1]) + int(entry[2])) / 2)
                start = ins_breakpoint - window
                end = ins_breakpoint + window
                reads = set()
                # coverage = 0
                for read in samfile.fetch(ins_chr, start, end):
                    reads.add(read.query_name)
                for read in reads:
                    output.write(read + "\n")

                # write
                out_line = line.replace("\n", "") + "\t" + str(len(reads))
                VCF.write(out_line + "\n")
                vcf_parsed = vcf_parsed_new

    # generate unique ID list
    read_ids_unique = read_ids + ".unique"
    command = "cat " + read_ids + " | sort | uniq"
    with open(read_ids_unique, "w") as output:
        subprocess.call(command, stdout=output, shell=True)

    # filter raw reads using read list
    subset_fa = os.path.join(out, sample_name + ".subset.fa")
    command = "seqtk subseq " + raw_reads + " " + read_ids_unique + " | seqtk seq -a"
    with open(subset_fa, "w") as output:
        subprocess.call(command, stdout=output, shell=True)

    # reorder reads
    subset_fa_reorder = out + "/" + sample_name + ".subset.reorder.fa"
    extract_reads(subset_fa, read_ids, subset_fa_reorder)

    # separate reads into multiple files, using csplit
    mkdir(reads_dir)
    csplit_prefix = reads_dir + "/contig"
    m = []
    k = 1
    with open(vcf_parsed, "r") as input:
        for line in input:
            entry = line.replace("\n", "").split("\t")
            if read_type == "sv":
                k = k + 2 * (len(entry[8].split(",")))
            else:
                k = k + 2 * int(entry[14])
            m.append(k)
    if len(m) == 1:
        subprocess.call(["cp", subset_fa_reorder, reads_dir + "/contig0"])
    elif len(m) == 0:
        print("No insertion detected, exiting...")
    else:
        m = m[:-1]
        index = " ".join(str(i) for i in m)
        command = (
            "csplit -s -f " + csplit_prefix + " -n 1 " + subset_fa_reorder + " " + index
        )
        subprocess.call(command, shell=True)

    # remove tmp files
    os.remove(read_ids)
    os.remove(read_ids_unique)
    os.remove(subset_fa)
    os.remove(subset_fa_reorder)


def extract_reads(reads, list, out):
    """Extract reads from fasta using read ID list"""
    record_dict = SeqIO.index(reads, "fasta")
    with open(out, "wb") as output_handle, open(list, "r") as ID:
        for entry in ID:
            entry = entry.replace("\n", "")
            output_handle.write(record_dict.get_raw(entry))

[((29, 19, 29, 48), 'os.path.join', 'os.path.join', ({(29, 32, 29, 35): 'out', (29, 37, 29, 47): '"""sv_reads"""'}, {}), "(out, 'sv_reads')", False, 'import os\n'), ((40, 4, 40, 21), 'telr.TELR_utility.mkdir', 'mkdir', ({(40, 10, 40, 20): 'contig_dir'}, {}), '(contig_dir)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((66, 4, 66, 70), 'logging.info', 'logging.info', ({(66, 17, 66, 69): '"""Perform local assembly of non-reference TE loci..."""'}, {}), "('Perform local assembly of non-reference TE loci...')", False, 'import logging\n'), ((67, 17, 67, 28), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((83, 21, 83, 67), 'os.path.join', 'os.path.join', ({(83, 34, 83, 37): 'out', (83, 39, 83, 66): "sample_name + '.contigs.fa'"}, {}), "(out, sample_name + '.contigs.fa')", False, 'import os\n'), ((135, 7, 135, 27), 'telr.TELR_utility.check_exist', 'check_exist', ({(135, 19, 135, 26): 'asm_cns'}, {}), '(asm_cns)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((150, 18, 150, 52), 'os.path.join', 'os.path.join', ({(150, 31, 150, 38): 'asm_dir', (150, 40, 150, 51): 'contig_name'}, {}), '(asm_dir, contig_name)', False, 'import os\n'), ((151, 4, 151, 22), 'telr.TELR_utility.mkdir', 'mkdir', ({(151, 10, 151, 21): 'tmp_out_dir'}, {}), '(tmp_out_dir)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((177, 7, 177, 35), 'telr.TELR_utility.check_exist', 'check_exist', ({(177, 19, 177, 34): 'polished_contig'}, {}), '(polished_contig)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((256, 7, 256, 27), 'telr.TELR_utility.check_exist', 'check_exist', ({(256, 19, 256, 26): 'asm_cns'}, {}), '(asm_cns)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((270, 18, 270, 52), 'os.path.join', 'os.path.join', ({(270, 31, 270, 38): 'asm_dir', (270, 40, 270, 51): 'contig_name'}, {}), '(asm_dir, contig_name)', False, 'import os\n'), ((271, 4, 271, 22), 'telr.TELR_utility.mkdir', 'mkdir', ({(271, 10, 271, 21): 'tmp_out_dir'}, {}), '(tmp_out_dir)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((291, 18, 291, 61), 'os.path.join', 'os.path.join', ({(291, 31, 291, 42): 'tmp_out_dir', (291, 44, 291, 60): '"""assembly.fasta"""'}, {}), "(tmp_out_dir, 'assembly.fasta')", False, 'import os\n'), ((292, 22, 292, 68), 'os.path.join', 'os.path.join', ({(292, 35, 292, 42): 'asm_dir', (292, 44, 292, 67): "contig_name + '.cns.fa'"}, {}), "(asm_dir, contig_name + '.cns.fa')", False, 'import os\n'), ((293, 7, 293, 31), 'telr.TELR_utility.check_exist', 'check_exist', ({(293, 19, 293, 30): 'contig_path'}, {}), '(contig_path)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((340, 7, 340, 33), 'telr.TELR_utility.check_exist', 'check_exist', ({(340, 19, 340, 32): 'contig_layout'}, {}), '(contig_layout)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((361, 7, 361, 29), 'telr.TELR_utility.check_exist', 'check_exist', ({(361, 19, 361, 28): 'consensus'}, {}), '(consensus)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((422, 16, 422, 61), 'os.path.join', 'os.path.join', ({(422, 29, 422, 32): 'out', (422, 34, 422, 60): "sample_name + '.subset.fa'"}, {}), "(out, sample_name + '.subset.fa')", False, 'import os\n'), ((432, 4, 432, 20), 'telr.TELR_utility.mkdir', 'mkdir', ({(432, 10, 432, 19): 'reads_dir'}, {}), '(reads_dir)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((457, 4, 457, 23), 'os.remove', 'os.remove', ({(457, 14, 457, 22): 'read_ids'}, {}), '(read_ids)', False, 'import os\n'), ((458, 4, 458, 30), 'os.remove', 'os.remove', ({(458, 14, 458, 29): 'read_ids_unique'}, {}), '(read_ids_unique)', False, 'import os\n'), ((459, 4, 459, 24), 'os.remove', 'os.remove', ({(459, 14, 459, 23): 'subset_fa'}, {}), '(subset_fa)', False, 'import os\n'), ((460, 4, 460, 32), 'os.remove', 'os.remove', ({(460, 14, 460, 31): 'subset_fa_reorder'}, {}), '(subset_fa_reorder)', False, 'import os\n'), ((465, 18, 465, 45), 'Bio.SeqIO.index', 'SeqIO.index', ({(465, 30, 465, 35): 'reads', (465, 37, 465, 44): '"""fasta"""'}, {}), "(reads, 'fasta')", False, 'from Bio import SeqIO\n'), ((70, 15, 70, 37), 'multiprocessing.Pool', 'Pool', (), '', False, 'from multiprocessing import Pool\n'), ((79, 16, 79, 27), 'time.time', 'time.time', ({}, {}), '()', False, 'import time\n'), ((120, 11, 120, 31), 'telr.TELR_utility.check_exist', 'check_exist', ({(120, 23, 120, 30): 'asm_cns'}, {}), '(asm_cns)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((178, 8, 178, 43), 'os.rename', 'os.rename', ({(178, 18, 178, 33): 'polished_contig', (178, 35, 178, 42): 'asm_cns'}, {}), '(polished_contig, asm_cns)', False, 'import os\n'), ((179, 8, 179, 34), 'shutil.rmtree', 'shutil.rmtree', ({(179, 22, 179, 33): 'tmp_out_dir'}, {}), '(tmp_out_dir)', False, 'import shutil\n'), ((248, 11, 248, 31), 'telr.TELR_utility.check_exist', 'check_exist', ({(248, 23, 248, 30): 'cns_tmp'}, {}), '(cns_tmp)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((294, 8, 294, 47), 'os.rename', 'os.rename', ({(294, 18, 294, 29): 'contig_path', (294, 31, 294, 46): 'contig_path_new'}, {}), '(contig_path, contig_path_new)', False, 'import os\n'), ((296, 8, 296, 34), 'shutil.rmtree', 'shutil.rmtree', ({(296, 22, 296, 33): 'tmp_out_dir'}, {}), '(tmp_out_dir)', False, 'import shutil\n'), ((362, 27, 362, 73), 'os.path.join', 'os.path.join', ({(362, 40, 362, 47): 'asm_dir', (362, 49, 362, 72): "contig_name + '.cns.fa'"}, {}), "(asm_dir, contig_name + '.cns.fa')", False, 'import os\n'), ((363, 8, 363, 46), 'os.rename', 'os.rename', ({(363, 18, 363, 27): 'consensus', (363, 29, 363, 45): 'consensus_rename'}, {}), '(consensus, consensus_rename)', False, 'import os\n'), ((377, 19, 377, 57), 'os.path.join', 'os.path.join', ({(377, 32, 377, 35): 'out', (377, 37, 377, 56): "sample_name + '.id'"}, {}), "(out, sample_name + '.id')", False, 'import os\n'), ((386, 18, 386, 48), 'pysam.AlignmentFile', 'pysam.AlignmentFile', ({(386, 38, 386, 41): 'bam', (386, 43, 386, 47): '"""rb"""'}, {}), "(bam, 'rb')", False, 'import pysam\n'), ((387, 19, 387, 57), 'os.path.join', 'os.path.join', ({(387, 32, 387, 35): 'out', (387, 37, 387, 56): "sample_name + '.id'"}, {}), "(out, sample_name + '.id')", False, 'import os\n'), ((419, 8, 419, 59), 'subprocess.call', 'subprocess.call', (), '', False, 'import subprocess\n'), ((425, 8, 425, 59), 'subprocess.call', 'subprocess.call', (), '', False, 'import subprocess\n'), ((445, 8, 445, 74), 'subprocess.call', 'subprocess.call', ({(445, 24, 445, 73): "['cp', subset_fa_reorder, reads_dir + '/contig0']"}, {}), "(['cp', subset_fa_reorder, reads_dir + '/contig0'])", False, 'import subprocess\n'), ((38, 8, 38, 19), 'sys.exit', 'sys.exit', ({(38, 17, 38, 18): '(1)'}, {}), '(1)', False, 'import sys\n'), ((51, 12, 51, 48), 'os.rename', 'os.rename', ({(51, 22, 51, 30): 'sv_reads', (51, 32, 51, 47): 'sv_reads_rename'}, {}), '(sv_reads, sv_reads_rename)', False, 'import os\n'), ((77, 8, 77, 19), 'sys.exit', 'sys.exit', ({(77, 17, 77, 18): '(1)'}, {}), '(1)', False, 'import sys\n'), ((86, 15, 86, 34), 'telr.TELR_utility.check_exist', 'check_exist', ({(86, 27, 86, 33): 'contig'}, {}), '(contig)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((100, 49, 100, 71), 'telr.TELR_utility.format_time', 'format_time', ({(100, 61, 100, 70): 'proc_time'}, {}), '(proc_time)', False, 'from telr.TELR_utility import mkdir, check_exist, format_time\n'), ((214, 12, 220, 13), 'subprocess.run', 'subprocess.run', (), '', False, 'import subprocess\n'), ((238, 12, 244, 13), 'subprocess.run', 'subprocess.run', (), '', False, 'import subprocess\n'), ((249, 12, 249, 39), 'os.rename', 'os.rename', ({(249, 22, 249, 29): 'cns_tmp', (249, 31, 249, 38): 'asm_cns'}, {}), '(cns_tmp, asm_cns)', False, 'import os\n'), ((250, 12, 250, 26), 'os.remove', 'os.remove', ({(250, 22, 250, 25): 'bam'}, {}), '(bam)', False, 'import os\n'), ((344, 12, 356, 13), 'subprocess.run', 'subprocess.run', (), '', False, 'import subprocess\n'), ((454, 8, 454, 44), 'subprocess.call', 'subprocess.call', (), '', False, 'import subprocess\n'), ((89, 32, 89, 86), 'os.path.join', 'os.path.join', ({(89, 45, 89, 55): 'contig_dir', (89, 57, 89, 85): "contig_name + '.cns.ctg1.fa'"}, {}), "(contig_dir, contig_name + '.cns.ctg1.fa')", False, 'import os\n'), ((91, 30, 91, 57), 'Bio.SeqIO.parse', 'SeqIO.parse', ({(91, 42, 91, 47): 'input', (91, 49, 91, 56): '"""fasta"""'}, {}), "(input, 'fasta')", False, 'from Bio import SeqIO\n'), ((87, 30, 87, 54), 'os.path.basename', 'os.path.basename', ({(87, 47, 87, 53): 'contig'}, {}), '(contig)', False, 'import os\n'), ((96, 28, 96, 78), 'Bio.SeqIO.write', 'SeqIO.write', ({(96, 40, 96, 46): 'record', (96, 48, 96, 68): 'merged_output_handle', (96, 70, 96, 77): '"""fasta"""'}, {}), "(record, merged_output_handle, 'fasta')", False, 'from Bio import SeqIO\n'), ((98, 32, 98, 82), 'Bio.SeqIO.write', 'SeqIO.write', ({(98, 44, 98, 50): 'record', (98, 52, 98, 72): 'parsed_output_handle', (98, 74, 98, 81): '"""fasta"""'}, {}), "(record, parsed_output_handle, 'fasta')", False, 'from Bio import SeqIO\n')]