diff --git a/mutalyzer/Crossmap.py b/mutalyzer/Crossmap.py index a78a3f2530c659688505d1e4711d895a7f88f54d..cd289e3ebd5e558886bc1204401f4e81cb759847 100644 --- a/mutalyzer/Crossmap.py +++ b/mutalyzer/Crossmap.py @@ -435,7 +435,7 @@ class Crossmap() : return int(s) #main2int - def int2offset(self, t) : + def int2offset(self, t, fuzzy=False): """ Convert a tuple of integers to offset-notation. This adds a `+', and `u' or `d' to the offset when appropriate. The main value is @@ -443,17 +443,22 @@ class Crossmap() : @arg t: A tuple of integers: (main, offset) in __STOP notation @type t: tuple + @kwarg fuzzy: Denotes that the coordinate is fuzzy (i.e. offset is + unknown). + @type fuzzy: bool @return: The offset in HGVS notation @rtype: string """ if t[1] > 0 : # The exon boundary is downstream. + if fuzzy: return '+?' if t[0] >= self.__trans_end : # It is downstream of the last exon. return "+d" + str(t[1]) return '+' + str(t[1]) #if if t[1] < 0 : # The exon boundary is uptream. + if fuzzy: return '-?' if t[0] <= self.__trans_start : # It is upstream of the first exon. return "-u" + str(-t[1]) return str(t[1]) @@ -490,32 +495,38 @@ class Crossmap() : return int(s[1:]) #offset2int - def tuple2string(self, t) : + def tuple2string(self, t, fuzzy=False) : """ Convert a tuple (main, offset) in __STOP notation to I{c.} notation. @arg t: A tuple (main, offset) in __STOP notation @type t: tuple + @kwarg fuzzy: Denotes that the coordinate is fuzzy (i.e. offset is + unknown). + @type fuzzy: bool @return: The position in HGVS notation @rtype: string """ - return str(self.int2main(t[0])) + str(self.int2offset(t)) + return str(self.int2main(t[0])) + str(self.int2offset(t, fuzzy)) #tuple2string - def g2c(self, a) : + def g2c(self, a, fuzzy=False) : """ Uses both g2x() and tuple2string() to translate a genomic position to __STOP notation to I{c.} notation. @arg a: The genomic position that must be translated @type a: integer + @kwarg fuzzy: Denotes that the coordinate is fuzzy (i.e. offset is + unknown). + @type fuzzy: bool @return: The position in HGVS notation @rtype: string """ - return self.tuple2string(self.g2x(a)) + return self.tuple2string(self.g2x(a), fuzzy) #g2c def info(self) : diff --git a/mutalyzer/GenRecord.py b/mutalyzer/GenRecord.py index 4f3b1559822cdbf3292fe825cb4b94e865111dc0..3c96487220f582f3f076ed45151dda011194faf4 100644 --- a/mutalyzer/GenRecord.py +++ b/mutalyzer/GenRecord.py @@ -81,7 +81,7 @@ class Locus(object) : - exon ; A position list object. - txTable ; The translation table. - CM ; A Crossmap object. - + @arg name: identifier of the locus @type name: string """ @@ -110,21 +110,37 @@ class Locus(object) : self.proteinProduct = None #__init__ - def addToDescription(self, rawVariant) : + def cancelDescription(self): + """ + Set the description on this locus to 'unknown'. + + This can be used if at some point we give up creating a sensible + description on this locus. It also makes sure future additions to + the description are ignored and it keeps the 'unknown' value. + + @note: This depends on the check for the unknown value in the + addToDescription method. This is a not a beatiful solution. + """ + self.description = '?' + #cancelDescription + + def addToDescription(self, rawVariant): """ Expands the DNA description with a new raw variant. - + @arg rawVariant: description of a single mutation @type rawVariant: string """ - if self.description: - self.description = "%s;%s" % (self.description, rawVariant) - else : + # Don't change anything if we already have an unknown value. + if self.description != '?': + self.description = "%s;%s" % (self.description, rawVariant) + else: self.description = rawVariant #addToDescription #Locus + class Gene(object) : """ A Gene object, to store a list of Locus objects and the orientation of @@ -150,7 +166,7 @@ class Gene(object) : - longName ; Private variables (altered): - __locusTag ; - + @arg name: gene name @type name: string """ @@ -166,7 +182,7 @@ class Gene(object) : def newLocusTag(self) : """ Generates a new Locus tag. - + @return: Locus tag @rtype: integer (3 digits, if < 100 preceeded with 0's) """ @@ -179,10 +195,10 @@ class Gene(object) : def findLocus(self, name) : """ Find a transcript, given its name. - + @arg name: transcript variant number @type name: string - + @return: transcript @rtype: object """ @@ -196,7 +212,7 @@ class Gene(object) : def listLoci(self) : """ Provides a list of transcript variant numbers - + @return: list of transcript variant numbers @rtype: list """ @@ -210,10 +226,10 @@ class Gene(object) : def findLink(self, protAcc) : """ Look in the list of transcripts for a given protein accession number. - + @arg protAcc: protein accession number @type protAcc: string - + @return: transcript @rtype: object """ @@ -280,10 +296,10 @@ class Record(object) : def findGene(self, name) : """ Returns a Gene object, given its name. - + @arg name: Gene name @type name: string - + @return: Gene object @rtype: object """ @@ -297,10 +313,10 @@ class Record(object) : def listGenes(self) : """ List the names of all genes found in this record. - + @return: Genes list @rtype: list - + """ ret = [] @@ -312,7 +328,7 @@ class Record(object) : def addToDescription(self, rawVariant) : """ Expands the DNA description with a new raw variant. - + @arg rawVariant: description of a single mutation @type rawVariant: string """ @@ -326,11 +342,11 @@ class Record(object) : def toChromPos(self, i) : """ Converts a g. position (relative to the start of the record) to a - chromosomal g. position - + chromosomal g. position + @arg i: g. position (relative to the start of the record) @type i: integer - + @return: chromosomal g. position @rtype: integer """ @@ -366,10 +382,10 @@ class GenRecord() : def __init__(self, output, config) : """ Initialise the class. - + Public variable: - record ; A record object - + @arg output: an output object @type output: object @arg config: a config object @@ -384,13 +400,13 @@ class GenRecord() : def __checkExonList(self, exonList, CDSpos) : """ @todo document me - + @arg exonList: list of splice sites @type exonList: list (object) @arg CDSpos: location of the CDS @type CDSpos: object - - @return: + + @return: @rtype: boolean """ @@ -414,12 +430,12 @@ class GenRecord() : return True return False #__checkExonList - + def __constructCDS(self, mRNA, CDSpos) : """ - Construct a list of coordinates that contains CDS start and stop and + Construct a list of coordinates that contains CDS start and stop and the internal splice sites. - + @arg mRNA: mRNA positions/coordinates list @type mRNA: list (integer) @arg CDSpos: coding DNA positions/coordinates @@ -449,14 +465,14 @@ class GenRecord() : """ Return the reverse-complement of a DNA sequence if the gene is in the reverse orientation. - - @arg gene: Gene + + @arg gene: Gene @type gene: object @arg string: DNA sequence @type string: string @kwarg string_reverse: DNA sequence to use (if not None) for the reverse complement. - + @return: reverse-complement (if applicable), otherwise return the original. @rtype: string @@ -472,7 +488,7 @@ class GenRecord() : """ Check if the record in self.record is compatible with mutalyzer. Update the mRNA PList with the exon and CDS data. - + @todo: This function should really check the record for minimal requirements """ @@ -602,7 +618,8 @@ class GenRecord() : return None #current_transcript - def name(self, start_g, stop_g, varType, arg1, arg2, roll, arg1_reverse=None): + def name(self, start_g, stop_g, varType, arg1, arg2, roll, arg1_reverse=None, + start_fuzzy=False, stop_fuzzy=False): """ Generate variant descriptions for all genes, transcripts, etc. @@ -620,6 +637,10 @@ class GenRecord() : @type roll: tuple (integer, integer) @kwarg arg1_reverse: argument 1 to be used on reverse strand @type arg1_reverse: string + @kwarg start_fuzzy: Indicates if start position of variant is fuzzy. + @type start_fuzzy: bool + @kwarg stop_fuzzy: Indicates if stop position of variant is fuzzy. + @type stop_fuzzy: bool """ forwardStart = start_g forwardStop = stop_g @@ -634,23 +655,64 @@ class GenRecord() : if varType != "subst" : if forwardStart != forwardStop : - self.record.addToDescription("%s_%s%s%s" % (forwardStart, - forwardStop, varType, arg1)) - self.record.addToChromDescription("%s_%s%s%s" % ( - self.record.toChromPos(forwardStart), - self.record.toChromPos(forwardStop), varType, arg1)) + # Todo: Fuzzy offsets to genomic positions (see bug #38). + # + # The genomic positioning is problematic. We would like to + # have it in brackets (as fuzzy positions), like the above + # g.(34299_23232)del example. + # + # Now consider a variant c.a-?_b+18del where only the offset + # before the exon is unknown but the offset after the exon is + # exact. Now a genomic description like g.(34299)_23232del + # comes to mind, however, this notation is not allowed by the + # HGVS grammar. + # + # I think all we can do is to treat both positions as fuzzy in + # the genomic description, even if only one of them really is. + # + # Peter thinks the HGVS grammar should at some point be + # updated to allow the brackets around individual locations. + if start_fuzzy or stop_fuzzy: + self.record.addToDescription("(%s_%s)%s%s" % ( + forwardStart, forwardStop, varType, arg1)) + self.record.addToChromDescription("(%s_%s)%s%s" % ( + self.record.toChromPos(forwardStart), + self.record.toChromPos(forwardStop), varType, arg1)) + else: + self.record.addToDescription("%s_%s%s%s" % ( + forwardStart, forwardStop, varType, arg1)) + self.record.addToChromDescription("%s_%s%s%s" % ( + self.record.toChromPos(forwardStart), + self.record.toChromPos(forwardStop), varType, arg1)) #if else : - self.record.addToDescription("%s%s%s" % (forwardStart, varType, - arg1)) - self.record.addToChromDescription("%s%s%s" % ( - self.record.toChromPos(forwardStart), varType, arg1)) + if start_fuzzy or stop_fuzzy: + # Todo: Current HGVS does not allow for () around single + # positions, only around ranges (see above and #38). + self.record.addToDescription("(%s)%s%s" % ( + forwardStart, varType, arg1)) + self.record.addToChromDescription("(%s)%s%s" % ( + self.record.toChromPos(forwardStart), varType, arg1)) + else: + self.record.addToDescription("%s%s%s" % ( + forwardStart, varType, arg1)) + self.record.addToChromDescription("%s%s%s" % ( + self.record.toChromPos(forwardStart), varType, arg1)) #else #if else : - self.record.addToDescription("%s%c>%c" % (forwardStart, arg1, arg2)) - self.record.addToChromDescription("%s%c>%c" % ( - self.record.toChromPos(forwardStart), arg1, arg2)) + if start_fuzzy or stop_fuzzy: + # Todo: Current HGVS does not allow for () around single + # positions, only around ranges (see above and #38). + self.record.addToDescription("(%s)%c>%c" % ( + forwardStart, arg1, arg2)) + self.record.addToChromDescription("(%s)%c>%c" % ( + self.record.toChromPos(forwardStart), arg1, arg2)) + else: + self.record.addToDescription("%s%c>%c" % ( + forwardStart, arg1, arg2)) + self.record.addToChromDescription("%s%c>%c" % ( + self.record.toChromPos(forwardStart), arg1, arg2)) for i in self.record.geneList : for j in i.transcriptList : @@ -683,24 +745,45 @@ class GenRecord() : if varType != "subst" : if orientedStart != orientedStop : - j.addToDescription("%s_%s%s%s" % ( - j.CM.g2c(orientedStart), j.CM.g2c(orientedStop), - varType, self.__maybeInvert(i, arg1, arg1_reverse))) - self.checkIntron(i, j, orientedStart) - self.checkIntron(i, j, orientedStop) + if (start_fuzzy or stop_fuzzy) and not j.current: + # Don't generate descriptions on transcripts + # other than the current in the case of fuzzy + # positions. + j.cancelDescription() + else: + j.addToDescription("%s_%s%s%s" % ( + j.CM.g2c(orientedStart, start_fuzzy), + j.CM.g2c(orientedStop, stop_fuzzy), + varType, self.__maybeInvert(i, arg1, arg1_reverse))) + self.checkIntron(i, j, orientedStart) + self.checkIntron(i, j, orientedStop) #if else : - j.addToDescription("%s%s%s" % ( - j.CM.g2c(orientedStart), varType, - self.__maybeInvert(i, arg1, arg1_reverse))) - self.checkIntron(i, j, orientedStart) + if start_fuzzy and not j.current: + # Don't generate descriptions on transcripts + # other than the current in the case of fuzzy + # positions. + j.cancelDescription() + else: + j.addToDescription("%s%s%s" % ( + j.CM.g2c(orientedStart, start_fuzzy), + varType, + self.__maybeInvert(i, arg1, arg1_reverse))) + self.checkIntron(i, j, orientedStart) #else #if else : - j.addToDescription("%s%c>%c" % (j.CM.g2c(orientedStart), - self.__maybeInvert(i, arg1, arg1_reverse), - self.__maybeInvert(i, arg2))) - self.checkIntron(i, j, orientedStart) + if start_fuzzy and not j.current: + # Don't generate descriptions on transcripts + # other than the current in the case of fuzzy + # positions. + j.cancelDescription() + else: + j.addToDescription("%s%c>%c" % ( + j.CM.g2c(orientedStart, start_fuzzy), + self.__maybeInvert(i, arg1, arg1_reverse), + self.__maybeInvert(i, arg2))) + self.checkIntron(i, j, orientedStart) #else #if #for @@ -710,14 +793,14 @@ class GenRecord() : def checkIntron(self, gene, transcript, position) : """ Checks if a position is on or near a splice site - + @arg gene: Gene @type gene: object @arg transcript: transcript @type transcript: object @arg position: g. position @type position: integer - + @return: @todo: Also check a range properly. """ diff --git a/mutalyzer/templates/check.html b/mutalyzer/templates/check.html index 271293e2bff8feb9fa951c69f396e97ee5e51958..ca1fd558341c2202182036351688ad0a207221c9 100644 --- a/mutalyzer/templates/check.html +++ b/mutalyzer/templates/check.html @@ -95,9 +95,10 @@ <b>Affected transcripts:</b><br> <br> <tt tal:repeat = "i descriptions"> - <a tal:content = "i/0" + <a tal:condition = "i/1" tal:content = "i/0" tal:attributes = - "href string:checkForward?mutationName=${i/1}"></a><br> + "href string:checkForward?mutationName=${i/1}"></a><tal + tal:condition = "not:i/1" tal:replace = "i/0"></tal><br> </tt> <br> <br> diff --git a/mutalyzer/variantchecker.py b/mutalyzer/variantchecker.py index 4068cba0424ad8aa16e241d76a88c941d72e71dc..126219694ceac857f7c2b6e21994fbac27b45e30 100644 --- a/mutalyzer/variantchecker.py +++ b/mutalyzer/variantchecker.py @@ -302,7 +302,8 @@ def apply_substitution(position, original, substitute, mutator, record, O): #apply_substitution -def apply_deletion_duplication(first, last, type, mutator, record, O): +def apply_deletion_duplication(first, last, type, mutator, record, O, + first_fuzzy=False, last_fuzzy=False): """ Do a semantic check for a deletion or duplication, do the actual deletion/duplication and give it a name. @@ -319,6 +320,13 @@ def apply_deletion_duplication(first, last, type, mutator, record, O): @type record: Modules.GenRecord.GenRecord @arg O: The Output object. @type O: Modules.Output.Output + + @kwarg first_fuzzy: Denotes that the start position is fuzzy (e.g. in the + case of an unknown offset in c. notation). + @type first_fuzzy: bool + @kwarg last_fuzzy: Denotes that the end position is fuzzy (e.g. in the + case of an unknown offset in c. notation). + @type last_fuzzy: bool """ reverse_roll, forward_roll = util.roll(mutator.orig, first, last) @@ -391,7 +399,9 @@ def apply_deletion_duplication(first, last, type, mutator, record, O): else: mutator.dupM(first, last) - record.name(first, last, type, '', '', (reverse_roll, forward_roll)) + record.name(first, last, type, '', '', (reverse_roll, forward_roll), + start_fuzzy=first_fuzzy, + stop_fuzzy=last_fuzzy) #apply_deletion_duplication @@ -644,21 +654,71 @@ def apply_delins(first, last, delete, insert, mutator, record, output): #apply_delins -def _get_offset(location): +def _get_offset(location, main_genomic, sites, output): """ Convert the offset coordinate in a location (from the Parser) to an integer. @arg location: A location. @type location: pyparsing.ParseResults + @arg main_genomic: Genomic main position to which the offset belongs. + @type main_genomic: int + @arg sites: List of splice sites. + @type sites: list + @arg output: The Output object. + @type output: Modules.Output.Output @return: Integer representation of the offset coordinate. @rtype: int """ if location.Offset : - if location.Offset == '?' : # This is highly debatable. - return 0 - offset = int(location.Offset) + if location.Offset == '?' : + try: + # Todo: If it removes CDS start, don't do protein translation. + # Todo: Wrt orientation, perhaps always go to splice site + # locations via the crossmapper... + # Todo: Also check if +? and -? are correctly used. + # Todo: Exactly centering might not be so nice, since the center + # might be closer to a neighbouring exon, making a+xxx from b-? + # and vice versa. This might not be fixed directly by doing a + # center +/- 1 because there might be rolling. Ideally we + # disable rolling entirely for these positions... + # + # Note that the code below might be a bit confusing, especially + # considering reverse strand transcripts. Magically, it works + # for both orientations. + i = sites.index(main_genomic) + if i == 0: + # Before first exon (or last on the reverse strand). + offset = main_genomic / 2 + elif i == len(sites) - 1: + # After last exon (or first on the reverse strand). + # Todo: Get length of reference, and calculate a sensible + # offset. + # + # We now use that 2000 is the default downstream length, + # but of course this is bogus on the reverse strand and + # just a hack anyway. + offset = 1000 + elif i % 2 == 0: + # Acceptor site (or donor on the reverse strand). + offset = abs(main_genomic - sites[i - 1]) / 2 - 1 + else: + # Donor site (or acceptor on the reverse strand). + offset = abs(sites[i + 1] - main_genomic) / 2 - 1 + # Todo: We would like to use the c. position in this message. + output.addMessage(__file__, 1, "IUNKNOWNOFFSET", "Unknown offset " \ + "relative to %s interpreted as middle of " \ + "flanking intron." % main_genomic) + except ValueError: + # Todo: This means we don't get an error if the main position + # was not on an exon boundary. We should return something else + # than 0 I guess. + #return 0 # This is highly debatable. + # Any non-zero value will do. + return 1 + else: + offset = int(location.Offset) if location.OffSgn == '-' : return -offset return offset @@ -761,7 +821,7 @@ def _genomic_to_genomic(first_location, last_location): return first, last -def _coding_to_genomic(first_location, last_location, transcript): +def _coding_to_genomic(first_location, last_location, transcript, output): """ Get genomic range from parsed c. location. @@ -771,6 +831,8 @@ def _coding_to_genomic(first_location, last_location, transcript): @type last_location: pyparsing.ParseResults @arg transcript: todo @type transcript: todo + @arg output: The Output object. + @type output: Modules.Output.Output @return: A tuple of: - first: Genomic start location represented by given location. @@ -792,11 +854,15 @@ def _coding_to_genomic(first_location, last_location, transcript): first_main = transcript.CM.main2int(first_location.MainSgn + \ first_location.Main) - first_offset = _get_offset(first_location) + first_main_genomic = transcript.CM.x2g(first_main, 0) + first_offset = _get_offset(first_location, first_main_genomic, + transcript.CM.RNA, output) last_main = transcript.CM.main2int(last_location.MainSgn + \ last_location.Main) - last_offset = _get_offset(last_location) + last_main_genomic = transcript.CM.x2g(last_main, 0) + last_offset = _get_offset(last_location, last_main_genomic, + transcript.CM.RNA, output) # These raise _RawVariantError exceptions on invalid positions. _check_intronic_position(first_main, first_offset, transcript) @@ -912,7 +978,8 @@ def process_raw_variant(mutator, variant, record, transcript, output): try: if transcript: # Coding positioning. - first, last = _coding_to_genomic(first_location, last_location, transcript) + first, last = _coding_to_genomic(first_location, last_location, + transcript, output) else: # Genomic positioning. first, last = _genomic_to_genomic(first_location, last_location) @@ -1062,8 +1129,12 @@ def process_raw_variant(mutator, variant, record, transcript, output): # Deletion or duplication. if variant.MutationType in ['del', 'dup']: + # The fuzzy flags are to support deletions of the form c.a-?_b+?del. + first_fuzzy = variant.StartLoc.PtLoc.Offset == '?' + last_fuzzy = variant.EndLoc and variant.EndLoc.PtLoc.Offset == '?' apply_deletion_duplication(first, last, variant.MutationType, mutator, - record, output) + record, output, first_fuzzy=first_fuzzy, + last_fuzzy=last_fuzzy) # Inversion. if variant.MutationType == 'inv': @@ -1259,6 +1330,9 @@ def process_variant(mutator, description, record, output): if transcript_id: transcript = gene.findLocus(transcript_id) if not transcript: + # Todo: Incorrect error message, it might also be that + # there are no transcripts at all (e.g. N4BP2L1 on + # NG_012772.1). output.addMessage(__file__, 4, "ENOTRANSCRIPT", "Multiple transcripts found for gene %s. Please " \ "choose from: %s" %(gene.name, @@ -1302,6 +1376,9 @@ def process_variant(mutator, description, record, output): # this gene. transcript = gene.transcriptList[0] else: + # Todo: Incorrect error message, it might also be that + # there are no transcripts at all (e.g. N4BP2L1 on + # NG_012772.1). output.addMessage(__file__, 4, "ENOTRANSCRIPT", "Multiple transcripts found for gene %s. Please " \ "choose from: %s" %(gene.name, @@ -1484,6 +1561,7 @@ def check_variant(description, config, output): mutator.newSplice(transcript.CDS.positionList), transcript.CM.orientation)), IUPAC.unambiguous_dna) + if transcript.CM.orientation == -1: cds_original = Bio.Seq.reverse_complement(cds_original) cds_variant = Bio.Seq.reverse_complement(cds_variant) @@ -1509,9 +1587,15 @@ def check_variant(description, config, output): return protein_variant = cds_variant.translate(table=transcript.txTable, to_stop=True) - cds_length = util.cds_length(mutator.newSplice(transcript.CDS.positionList)) - transcript.proteinDescription = util.protein_description( - cds_length, protein_original, protein_variant)[0] + try: + cds_length = util.cds_length( + mutator.newSplice(transcript.CDS.positionList)) + transcript.proteinDescription = util.protein_description( + cds_length, protein_original, protein_variant)[0] + except IndexError: + # Todo: Probably CDS start was hit by removal of exon... + transcript.proteinDescription = 'p.?' + else: output.addMessage(__file__, 2, "ECDS", "CDS length is " \ "not a multiple of three in gene %s, transcript " \ diff --git a/mutalyzer/website.py b/mutalyzer/website.py index 817bb0e35724299eb0b0d75add0bfee89323ef5b..be9c833b4362d8716ee0a53344e2cd02b5473e90 100644 --- a/mutalyzer/website.py +++ b/mutalyzer/website.py @@ -685,6 +685,13 @@ class Check: genomic_description = output.getIndexedOutput('genomicDescription', 0, '') + # Create a tuple (description, link) from a description + def description_to_link(description): + link = None + if description[-1] != '?': + link = urllib.quote(description) + return description, link + # Todo: Generate the fancy HTML views for the proteins here instead # of in mutalyzer/variantchecker.py. args = { @@ -697,7 +704,7 @@ class Check: 'chromDescription' : output.getIndexedOutput('genomicChromDescription', 0), 'genomicDNA' : genomic_dna, 'visualisation' : output.getOutput('visualisation'), - 'descriptions' : map(lambda d: (d, urllib.quote(d)), output.getOutput('descriptions')), + 'descriptions' : map(description_to_link, output.getOutput('descriptions')), 'protDescriptions' : output.getOutput('protDescriptions'), 'oldProtein' : output.getOutput('oldProteinFancy'), 'altStart' : output.getIndexedOutput('altStart', 0), diff --git a/tests/test_variantchecker.py b/tests/test_variantchecker.py index be4c39bf5e585aa445850091e5f7e2cd5ba84dba..debc39bfdd49999a817e8668cf79e3e7634912de 100644 --- a/tests/test_variantchecker.py +++ b/tests/test_variantchecker.py @@ -262,7 +262,6 @@ class TestVariantchecker(): """ Deletion of an entire exon with unknown offsets should be possible. """ - return # Todo check_variant('NG_012772.1(BRCA2_v001):c.632-?_681+?del', self.config, self.output) assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0 @@ -275,6 +274,8 @@ class TestVariantchecker(): 'NG_012772.1:g.(17550_19725)del') assert 'NG_012772.1(BRCA2_v001):c.632-?_681+?del' \ in self.output.getOutput('descriptions') + assert 'NG_012772.1(BRCA2_i001):p.(Val211Glufs*10)' \ + in self.output.getOutput('protDescriptions') # Todo: .c notation should still be c.632-?_681+?del, but what about # other transcripts? @@ -287,7 +288,6 @@ class TestVariantchecker(): NG_012772.1(BRCA2_v001):c.68-?_316+?del is such a variant, since positions 68 through 316 are exactly one exon and (316-68+1)/3 = 83. """ - return # Todo check_variant('NG_012772.1(BRCA2_v001):c.68-?_316+?del', self.config, self.output) assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0 @@ -308,8 +308,7 @@ class TestVariantchecker(): Deletion of an entire exon with unknown offsets and another composed variant with exact positioning should be possible. """ - return # Todo - check_variant('UD_129433404385(DMD_v010):c.[281-?_492+?del;492+4del]', + check_variant('NG_012772.1(BRCA2_v001):c.[632-?_681+?del;681+4del]', self.config, self.output) assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0 assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0 @@ -318,8 +317,28 @@ class TestVariantchecker(): assert self.output.getOutput('newprotein') # Genomic positions should be centered in flanking introns and unsure. assert_equal(self.output.getIndexedOutput('genomicDescription', 0), - 'UD_129433404385:g.[(1640003_1675849)del;1665239del]') - assert 'UD_129433404385(DMD_v010):c.[281-?_492+?del;492+4del]' \ + 'NG_012772.1:g.[(17550_19725)del;19017del]') + assert 'NG_012772.1(BRCA2_v001):c.[632-?_681+?del;681+4del]' \ + in self.output.getOutput('descriptions') + # Todo: .c notation should still be c.632-?_681+?del, but what about + # other transcripts? + + def test_del_exon_unknown_offsets_reverse(self): + """ + Deletion of an entire exon with unknown offsets should be possible, + also on the reverse strand. + """ + check_variant('AL449423.14(CDKN2A_v001):c.151-?_457+?del', + self.config, self.output) + assert len(self.output.getMessagesWithErrorCode('WOVERSPLICE')) > 0 + assert len(self.output.getMessagesWithErrorCode('IDELSPLICE')) > 0 + # Todo: For now, the following is how to check if protein + # prediction is done. + assert self.output.getOutput('newprotein') + # Genomic positions should be centered in flanking introns and unsure. + assert_equal(self.output.getIndexedOutput('genomicDescription', 0), + 'AL449423.14:g.(60314_63683)del') + assert 'AL449423.14(CDKN2A_v001):c.151-?_457+?del' \ in self.output.getOutput('descriptions') # Todo: .c notation should still be c.632-?_681+?del, but what about # other transcripts? diff --git a/tests/test_website.py b/tests/test_website.py index de31f2c74cd84992b8046aafc15f0734263683f3..089e09a97cbdf1a27dd663921458c1b0d7e9ef15 100644 --- a/tests/test_website.py +++ b/tests/test_website.py @@ -577,7 +577,6 @@ facilisi.""" and thus the cached file from request i cannot be re-used in request i+1. """ - return r = self.app.get('/check') form = r.forms[0] form['mutationName'] = 'AB026906.1:c.274G>T'