Create reports of the analyses

def reporter(self):
        """
        Create reports of the analyses
        """
        # Create a folder in which amplicons and raw BLAST results are to be stored
        detailed_reports = os.path.join(self.path, 'detailed_reports')
        make_path(detailed_reports)
        # Create the report path if necessary
        make_path(self.reportpath)
        with open(self.report, 'w') as report:
            # Initialise the header
            data = 'Sample,Gene,GenomeLocation,AmpliconSize,Contig,ForwardPrimers,ReversePrimers,' \
                   'ForwardMismatches,ReverseMismatches\n'
            for sample in self.metadata:
                # Initialise variables to convert attributes from set to list
                sample[self.analysistype].genes = dict()
                sample[self.analysistype].ntrange = dict()
                try:
                    # Check to ensure that there were amplicons present
                    if sample[self.analysistype].range:
                        # Iterate through each contig with genes present, and the list of genes on the contig
                        for contig, genes in sorted(sample[self.analysistype].genespresent.items()):
                            sample[self.analysistype].genes[contig] = list(genes)
                            # Iterate through the set of genes
                            for gene in sorted(genes):
                                # Determine which primers had the best lowest number of mismatches
                                # Create variables to store primer names, and number of mismatches
                                forward = list()
                                reverse = list()
                                forwardmismatches = int()
                                reversemismatches = int()
                                # Sort the dictionary of mismatches based on the number of mismatches
                                sorteddict = sorted(sample[self.analysistype].mismatches[contig][gene].items(),
                                                    key=operator.itemgetter(1))
                                # For every primer in the sorted dictionary, check to see if it is a forward or
                                # reverse primer, and determine the number of mismatches; if it is the first primer
                                # encountered for a gene, add it to the list, as because the dictionary is sorted,
                                # the number of mismatches should be the best. Additionally, if subsequent primer
                                # hits have the same number of mismatches, also add them to the list
                                for entry in sorteddict:
                                    # Add primer to the list if it is the first primer encountered
                                    if '-F' in entry[0] and not forward:
                                        forward.append(entry[0])
                                        forwardmismatches = entry[1]
                                    # Add the primer to the list if it has the same number of mismatches as a previous
                                    # primer in the list
                                    elif '-F' in entry[0] and entry[1] == forwardmismatches:
                                        forward.append(entry[0])
                                        forwardmismatches = entry[1]
                                    elif '-R' in entry[0] and not reverse:
                                        reverse.append(entry[0])
                                        reversemismatches = entry[1]
                                    elif '-R' in entry[0] and entry[1] == reversemismatches:
                                        reverse.append(entry[0])
                                        reversemismatches = entry[1]
                                # Make a variable to prevent writing out this long attribute name multiple times
                                ntrange = list(sample[self.analysistype].range[contig][gene])
                                sample[self.analysistype].ntrange[gene] = ntrange
                                # Extract the amplicons from the sequence file
                                self.ampliconfile(sample, contig, sorted(ntrange), forward, reverse)
                                # Copy the amplicons and raw BLAST outputs from FASTQ-formatted files to the
                                # detailed_reports folder
                                if sample[self.analysistype].filetype == 'fastq':
                                    try:
                                        shutil.copyfile(src=sample[self.analysistype].ampliconfile,
                                                        dst=os.path.join(detailed_reports,
                                                                         '{sn}_amplicons.fa'.format(sn=sample.name)))
                                        shutil.copyfile(src=sample[self.analysistype].report,
                                                        dst=os.path.join(detailed_reports,
                                                                         '{sn}_rawresults.csv'.format(sn=sample.name)))
                                    except FileNotFoundError:
                                        pass
                                # This first gene for a sample gets the sample name printed
                                data += '{sn},'.format(sn=sample.name)
                                # Populate the string with the gene name, properly formatted range, the length of
                                # the amplicon, and the name of the contig on which the gene was found
                                data += '{},{},{},{},{},{},{},{}\n'\
                                    .format(gene,
                                            '-'.join(str(x) for x in sorted(ntrange)),
                                            max(ntrange) - min(ntrange) + 1,
                                            contig,
                                            ';'.join(sorted(forward)),
                                            ';'.join(sorted(reverse)),
                                            forwardmismatches,
                                            reversemismatches)
                    # If there were no amplicons, add the sample name and nothing else
                    else:
                        data += '{sn}\n'.format(sn=sample.name)
                # If there were no BLAST hits, add the sample name, and nothing else
                except AttributeError:
                    data += '{sn}\n'.format(sn=sample.name)
                # Remove attributes that either take up too much room in the .json output, or are not JSON serializable
                try:
                    delattr(sample[self.analysistype], "blastresults")
                except AttributeError:
                    pass
                try:
                    delattr(sample[self.analysistype], "genespresent")
                except AttributeError:
                    pass
                try:
                    delattr(sample[self.analysistype], "contigs")
                except AttributeError:
                    pass
                try:
                    delattr(sample[self.analysistype], "range")
                except AttributeError:
                    pass
            # Write the string to the report
            report.write(data)
        # Clean up the BLAST database files
        db = os.path.splitext(self.formattedprimers)[0]
        # A list of all the file extensions associated with the BLASTdb
        dbextensions = ['.nhr', '.nin', '.nog', '.nsd', '.nsi', '.nsq']
        # Iterate through all the files, and delete each one - pass on IO errors
        for dbfile in zip(itertools.repeat(db), dbextensions):
            try:
                os.remove(''.join(dbfile))
            except IOError:
                pass
        try:
            os.remove(self.formattedprimers)  # Maybe want to keep this file?
        except IOError:
            pass