# HG changeset patch # User Jan Kanis # Date 1403101305 -7200 # Node ID 67b1a319c6dca81f6432d97038feafe186c1a0d3 # Parent 6ecbfebb9dd93d4a524581f36e8b9f92d31c0a21 First go at 2.6 compatibility The tests are running without errors, but they don't produce the same output as python3 diff -r 6ecbfebb9dd9 -r 67b1a319c6dc blast2html.html.jinja --- a/blast2html.html.jinja Wed Jun 18 14:33:12 2014 +0200 +++ b/blast2html.html.jinja Wed Jun 18 16:21:45 2014 +0200 @@ -1,3 +1,4 @@ +{# -*- coding: utf-8 -*- #} diff -r 6ecbfebb9dd9 -r 67b1a319c6dc blast2html.py --- a/blast2html.py Wed Jun 18 14:33:12 2014 +0200 +++ b/blast2html.py Wed Jun 18 16:21:45 2014 +0200 @@ -1,14 +1,17 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- +# Actually this program works with both python 2 and 3 + # Copyright The Hyve B.V. 2014 # License: GPL version 3 or (at your option) any higher version -from __future__ import unicode_literals +from __future__ import unicode_literals, division import sys import math import warnings +import six, codecs from os import path from itertools import repeat import argparse @@ -17,10 +20,10 @@ -_filters = {} +_filters = dict() def filter(func_or_name): "Decorator to register a function as filter in the current jinja environment" - if isinstance(func_or_name, str): + if isinstance(func_or_name, six.string_types): def inner(func): _filters[func_or_name] = func.__name__ return func @@ -100,10 +103,10 @@ hseq = hsp.Hsp_hseq.text if not qframe in (1, -1): - warnings.warn("Error in BlastXML input: Hsp node {} has a Hsp_query-frame of {}. (should be 1 or -1)".format(nodeid(hsp), qframe)) + warnings.warn("Error in BlastXML input: Hsp node {0} has a Hsp_query-frame of {1}. (should be 1 or -1)".format(nodeid(hsp), qframe)) qframe = -1 if qframe < 0 else 1 if not hframe in (1, -1): - warnings.warn("Error in BlastXML input: Hsp node {} has a Hsp_hit-frame of {}. (should be 1 or -1)".format(nodeid(hsp), hframe)) + warnings.warn("Error in BlastXML input: Hsp node {0} has a Hsp_hit-frame of {1}. (should be 1 or -1)".format(nodeid(hsp), hframe)) hframe = -1 if hframe < 0 else 1 def split(txt): @@ -111,16 +114,16 @@ for qs, mid, hs, offset in zip(split(qseq), split(midline), split(hseq), range(0, len(qseq), linewidth)): yield ( - "Query {:>7} {} {}\n".format(qfrom+offset*qframe, qs, qfrom+(offset+len(qs)-1)*qframe) + - " {:7} {}\n".format('', mid) + - "Subject{:>7} {} {}".format(hfrom+offset*hframe, hs, hfrom+(offset+len(hs)-1)*hframe) + "Query {0:>7} {1} {2}\n".format(qfrom+offset*qframe, qs, qfrom+(offset+len(qs)-1)*qframe) + + " {0:7} {1}\n".format('', mid) + + "Subject{0:>7} {1} {2}".format(hfrom+offset*hframe, hs, hfrom+(offset+len(hs)-1)*hframe) ) if qfrom+(len(qseq)-1)*qframe != qto: - warnings.warn("Error in BlastXML input: Hsp node {} qseq length mismatch: from {} to {} length {}".format( + warnings.warn("Error in BlastXML input: Hsp node {0} qseq length mismatch: from {1} to {2} length {3}".format( nodeid(hsp), qfrom, qto, len(qseq))) if hfrom+(len(hseq)-1)*hframe != hto: - warnings.warn("Error in BlastXML input: Hsp node {} hseq length mismatch: from {} to {} length {}".format( + warnings.warn("Error in BlastXML input: Hsp node {0} hseq length mismatch: from {1} to {2} length {3}".format( nodeid(hsp), hfrom, hto, len(hseq))) @@ -159,11 +162,11 @@ raise Exception("frame should be either +1 or -1") def genelink(hit, type='genbank', hsp=None): - if not isinstance(hit, str): + if not isinstance(hit, six.string_types): hit = hitid(hit) - link = "http://www.ncbi.nlm.nih.gov/nucleotide/{}?report={}&log$=nuclalign".format(hit, type) + link = "http://www.ncbi.nlm.nih.gov/nucleotide/{0}?report={1}&log$=nuclalign".format(hit, type) if hsp != None: - link += "&from={}&to={}".format(hsp['Hsp_hit-from'], hsp['Hsp_hit-to']) + link += "&from={0}&to={1}".format(hsp['Hsp_hit-from'], hsp['Hsp_hit-to']) return link @@ -198,7 +201,7 @@ javascript snippets. """ - value = str(value) + value = six.text_type(value) for bad, good in _js_escapes: value = value.replace(bad, good) @@ -225,7 +228,7 @@ self.templatename = templatename self.blast = objectify.parse(self.input).getroot() - self.loader = jinja2.FileSystemLoader(searchpath=templatedir) + self.loader = jinja2.FileSystemLoader(searchpath=templatedir, encoding='utf-8') self.environment = jinja2.Environment(loader=self.loader, lstrip_blocks=True, trim_blocks=True, autoescape=True) @@ -249,13 +252,16 @@ ('Database', self.blast.BlastOutput_db), ) - output.write(template.render(blast=self.blast, - iterations=self.blast.BlastOutput_iterations.Iteration, - colors=self.colors, - # match_colors=self.match_colors(), - # hit_info=self.hit_info(), - genelink=genelink, - params=params)) + result = template.render(blast=self.blast, + iterations=self.blast.BlastOutput_iterations.Iteration, + colors=self.colors, + # match_colors=self.match_colors(), + # hit_info=self.hit_info(), + genelink=genelink, + params=params) + if six.PY2: + result = result.encode('utf-8') + output.write(result) @filter def match_colors(self, result): @@ -321,20 +327,21 @@ yield dict(hit = hit, title = firsttitle(hit), - maxscore = "{:.1f}".format(max(hsp_val('Hsp_bit-score'))), - totalscore = "{:.1f}".format(sum(hsp_val('Hsp_bit-score'))), - cover = "{:.0%}".format(cover_count / query_length), - e_value = "{:.4g}".format(min(hsp_val('Hsp_evalue'))), + maxscore = "{0:.1f}".format(max(hsp_val('Hsp_bit-score'))), + totalscore = "{0:.1f}".format(sum(hsp_val('Hsp_bit-score'))), + cover = "{0:.0%}".format(cover_count / query_length), + e_value = "{0:.4g}".format(min(hsp_val('Hsp_evalue'))), # FIXME: is this the correct formula vv? - ident = "{:.0%}".format(float(min(hsp.Hsp_identity / blastxml_len(hsp) for hsp in hsps))), + ident = "{0:.0%}".format(float(min(hsp.Hsp_identity / blastxml_len(hsp) for hsp in hsps))), accession = hit.Hit_accession) def main(): + #import pdb; pdb.set_trace() default_template = path.join(path.dirname(__file__), 'blast2html.html.jinja') - + parser = argparse.ArgumentParser(description="Convert a BLAST XML result into a nicely readable html page", - usage="{} [-i] INPUT [-o OUTPUT]".format(sys.argv[0])) + usage="{0} [-i] INPUT [-o OUTPUT]".format(sys.argv[0])) input_group = parser.add_mutually_exclusive_group(required=True) input_group.add_argument('positional_arg', metavar='INPUT', nargs='?', type=argparse.FileType(mode='r'), help='The input Blast XML file, same as -i/--input')