
:>"^g                 @   s   d  Z  d d l Z d d l m Z d d l m Z d d l m Z d d l m	 Z	 d d l
 m Z d d l m Z d d	 l m Z d d
 l m Z d d l m Z d d l m Z Gd d   d e j  Z Gd d   d e  Z Gd d   d e  Z d S)a  Bio.SeqIO support for the "seqxml" file format, SeqXML.

This module is for reading and writing SeqXML format files as
SeqRecord objects, and is expected to be used via the Bio.SeqIO API.

SeqXML is a lightweight XML format which is supposed be an alternative for
FASTA files. For more Information see http://www.seqXML.org and Schmitt et al
(2011), https://doi.org/10.1093/bib/bbr025
    N)XMLGenerator)AttributesImpl)handler)sax)
basestring)Alphabet)Seq)
UnknownSeq)	SeqRecord   )SequentialSequenceWriterc               @   s   e  Z d  Z d Z d d   Z d d   Z d d   Z d d	   Z d
 d   Z d d   Z	 d d   Z
 d d   Z d d   Z d d   Z d d   Z d d   Z d d   Z d d   Z d d   Z d  d!   Z d" d#   Z d$ d%   Z d& S)'ContentHandlerz5Handles XML events generated by the parser (PRIVATE).c             C   s\   t  j j |   d |  _ d |  _ d |  _ d |  _ d |  _ d |  _ d |  _	 g  |  _
 d S)z&Create a handler to handle XML events.N)r   r   __init__sourcesourceVersionseqXMLversion	ncbiTaxIDspeciesNamestartElementNSdatarecords)self r   7/tmp/pip-build-ww9dw3qa/biopython/Bio/SeqIO/SeqXmlIO.pyr   %   s    							zContentHandler.__init__c             C   s   |  j  |  _ d S)z2Set XML handlers when an XML declaration is found.N)startSeqXMLElementr   )r   r   r   r   startDocument1   s    zContentHandler.startDocumentc             C   s  | d k r t  d   | d k	 r0 t d   d } x| j   D] \ } } | \ } } | d k r | d k r | |  _ q:| d k r | |  _ q:| d k r | |  _ q:| d k r t |  }	 | |  _ q:| d	 k r | |  _ q:t  d
   qC | d k r*| d k r| } q:t  d   qC t  d |   qC W|  j d k rYt  d   d |  j }
 | |
 k rt  d | |  j f   |  j	 |  _
 |  j |  _ d S)z!Handle start of a seqXML element.NseqXMLz*Failed to find the start of seqXML elementz#Unexpected qname for seqXML elementr   r   r   r   r   z#Unexpected attribute for XML Schemaz)http://www.w3.org/2001/XMLSchema-instanceZnoNamespaceSchemaLocationz0Unexpected attribute for XML Schema in namespacez.Unexpected namespace '%s' for seqXML attributezFailed to find seqXMLversionz#http://www.seqxml.org/%s/seqxml.xsdzDXML Schema '%s' found not consistent with reported seqXML version %s)Nr   )
ValueErrorRuntimeErroritemsr   r   r   intr   r   endSeqXMLElementendElementNSstartEntryElementr   )r   nameqnameattrsZschemakeyvalue	namespace	localnamenumberurlr   r   r   r   5   s@    	z!ContentHandler.startSeqXMLElementc             C   sr   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r\ t  d   d |  _ d |  _ d S)z!Handle end of the seqXML element.Nz(Unexpected namespace '%s' for seqXML endz$Unexpected qname '%s' for seqXML endr   z$Failed to find end of seqXML element)r   r   r"   )r   r$   r%   r)   r*   r   r   r   r!   \   s    	zContentHandler.endSeqXMLElementc       	      C   sc  | d k r t  d   | d k	 r0 t d   t d d d } |  j d k	 ra |  j | j d <|  j d k	 r |  j | j d <|  j | j d	 <x | j   D]{ \ } } | \ } } | d k r| d k r | | _ q| d	 k r | | j d	 <qt  d
 |   q t  d |   q W| j d k r7t  d   |  j	 j
 |  |  j |  _ |  j |  _ d S)z>Set new entry with id and the optional entry source (PRIVATE).Nentryz.Expected to find the start of an entry elementz"Unexpected qname for entry element idorganism
ncbi_taxidr   z(Unexpected attribute %s in entry elementz-Unexpected namespace '%s' for entry attributezFailed to find entry ID)Nzentry)r   r   r
   r   annotationsr   r   r   r/   r   appendstartEntryFieldElementr   endEntryElementr"   )	r   r$   r%   r&   recordr'   r(   r)   r*   r   r   r   r#   h   s0    z ContentHandler.startEntryElementc             C   sL   | d k r t  d   | d k	 r0 t d   |  j |  _ |  j |  _ d S)zHandle end of an entry element.Nr-   z,Expected to find the end of an entry elementz"Unexpected qname for entry element)Nzentry)r   r   r#   r   r!   r"   )r   r$   r%   r   r   r   r5      s    zContentHandler.endEntryElementc             C   s   | \ } } | d k	 r. t  d | | f   | d k	 rP t d | | f   | d k ri |  j |  S| d k r |  j |  S| d k r |  j |  S| d	 k r |  j |  S| d
 k r |  j |  St  d |   d S)z3Receive a field of an entry element and forward it.Nz(Unexpected namespace '%s' for %s elementz$Unexpected qname '%s' for %s elementspeciesdescriptionDNAseqRNAseqAAseqDBRefpropertyzUnexpected field %s in entry)r9   r:   r;   )r   r   startSpeciesElementstartDescriptionElementstartSequenceElementstartDBRefElementstartPropertyElement)r   r$   r%   r&   r)   r*   r   r   r   r4      s     z%ContentHandler.startEntryFieldElementc       
      C   s   d } d } x | j    D]| \ } } | \ } } | d k r | d k rR | } q | d k rs t |  } | } q t d |   q t d |   q W| d k r t d   | d k r t d   |  j d }	 | |	 j d	 <| |	 j d
 <|  j |  _ d S)zParse the species information.Nr$   r   z.Unexpected attribute '%s' found in species tagz/Unexpected namespace '%s' for species attributezFailed to find species namezFailed to find ncbiTaxIdr   r0   r1   )r   r    r   r   r2   endSpeciesElementr"   )
r   r&   r$   r   r'   r(   r)   r*   r+   r6   r   r   r   r>      s(    		z"ContentHandler.startSpeciesElementc             C   sl   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r\ t  d   |  j |  _ d S)z Handle end of a species element.Nz)Unexpected namespace '%s' for species endz%Unexpected qname '%s' for species endr7   z%Failed to find end of species element)r   r5   r"   )r   r$   r%   r)   r*   r   r   r   rD      s    z ContentHandler.endSpeciesElementc             C   sM   | r t  d   |  j d k	 r4 t d |  j   d |  _ |  j |  _ d S)zParse the description.z2Unexpected attributes found in description elementNzUnexpected data found: '%s'r.   )r   r   r   endDescriptionElementr"   )r   r&   r   r   r   r?      s    	z&ContentHandler.startDescriptionElementc             C   s   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r\ t  d   |  j d } |  j } | r | | _ d |  _ |  j |  _ d S)z(Handle the end of a description element.Nz-Unexpected namespace '%s' for description endz)Unexpected qname '%s' for description endr8   z)Failed to find end of description elementr   rC   )r   r   r   r8   r5   r"   )r   r$   r%   r)   r*   r6   r8   r   r   r   rE      s    			z$ContentHandler.endDescriptionElementc             C   sM   | r t  d   |  j d k	 r4 t d |  j   d |  _ |  j |  _ d S)z$Parse DNA, RNA, or protein sequence.z/Unexpected attributes found in sequence elementNzUnexpected data found: '%s'r.   )r   r   r   endSequenceElementr"   )r   r&   r   r   r   r@      s    	z#ContentHandler.startSequenceElementc             C   s   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r\ t j } n@ | d k rt t j } n( | d k r t j } n t  d |   |  j d	 } t |  j |  | _ d |  _ |  j	 |  _
 d S)
z%Handle the end of a sequence element.Nz*Unexpected namespace '%s' for sequence endz&Unexpected qname '%s' for sequence endr9   r:   r;   z/Failed to find end of sequence (localname = %s)r   rC   )r   r   Zgeneric_dnaZgeneric_rnaZgeneric_proteinr   r   r   seqr5   r"   )r   r$   r%   r)   r*   alphabetr6   r   r   r   rF      s     	z!ContentHandler.endSequenceElementc       
      C   s4  d } d } x~ | j    D]p \ } } | \ } } | d k ry | d k rR | } q | d k rg | } q t d |   q t d |   q W| d k r t d   | d k r t d   |  j d k	 r t d |  j   d	 |  _ |  j d } d | | f }	 |	 | j k r$| j j |	  |  j |  _ d S)z!Parse a database cross reference.Nr   r/   z1Unexpected attribute '%s' found for DBRef elementz-Unexpected namespace '%s' for DBRef attributez'Failed to find source for DBRef elementz#Failed to find id for DBRef elementzUnexpected data found: '%s'r.   r   z%s:%srC   )	r   r   r   r   r   dbxrefsr3   endDBRefElementr"   )
r   r&   r   ZIDr'   r(   r)   r*   r6   dbxrefr   r   r   rA      s.    			z ContentHandler.startDBRefElementc             C   s   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r` t  d |   |  j r| t  d |  j   d |  _ |  j |  _ d S)z"Handle the end of a DBRef element.Nz+Unexpected namespace '%s' for DBRef elementz'Unexpected qname '%s' for DBRef elementr<   z+Unexpected localname '%s' for DBRef elementz0Unexpected data received for DBRef element: '%s')r   r   r5   r"   )r   r$   r%   r)   r*   r   r   r   rJ     s    		zContentHandler.endDBRefElementc       	      C   s   d } d } x~ | j    D]p \ } } | \ } } | d k ry | d k rR | } q | d k rg | } q t d |   q t d |   q W| d k r t d   |  j d } | | j k r g  | j | <| j | j |  |  j |  _ d S)	z'Handle the start of a property element.Nr$   r(   z4Unexpected attribute '%s' found for property elementz0Unexpected namespace '%s' for property attributez(Failed to find name for property elementr   rC   )r   r   r   r2   r3   endPropertyElementr"   )	r   r&   Zproperty_nameZproperty_valuer'   r(   r)   r*   r6   r   r   r   rB   *  s$    		z#ContentHandler.startPropertyElementc             C   sp   | \ } } | d k	 r( t  d |   | d k	 rD t  d |   | d k r` t  d |   |  j |  _ d S)z%Handle the end of a property element.Nz.Unexpected namespace '%s' for property elementz*Unexpected qname '%s' for property elementr=   z.Unexpected localname '%s' for property element)r   r5   r"   )r   r$   r%   r)   r*   r   r   r   rL   B  s    z!ContentHandler.endPropertyElementc             C   s"   |  j  d k	 r |  j  | 7_  d S)zHandle character data.N)r   )r   r   r   r   r   
charactersM  s    zContentHandler.charactersN)__name__
__module____qualname____doc__r   r   r   r!   r#   r5   r4   r>   rD   r?   rE   r@   rF   rA   rJ   rB   rL   rM   r   r   r   r   r   "   s&   '			r   c               @   sb   e  Z d  Z d Z d Z d d d  Z d d   Z d d	   Z e j	 d
 d k  r^ d d   Z
 d S)SeqXmlIteratora)  Breaks seqXML file into SeqRecords.

    Assumes valid seqXML please validate beforehand.
    It is assumed that all information for one record can be found within a
    record element or above. Two types of methods are called when the start
    tag of an element is reached. To receive only the attributes of an
    element before its end tag is reached implement _attr_TAGNAME.
    To get an element and its children as a DOM tree implement _elem_TAGNAME.
    Everything that is part of the DOM tree will not trigger any further
    method calls.
    i   Nc             C   sn  t  j   |  _ t   } |  j j |  |  j j t j d  y t |  } Wn$ t	 k
 rt | |  _
 d |  _ Yn X| |  _
 d |  _ |  j } ys xl |  j
 j |  } | s | j d k r t d   n t d   |  j j |  | j } | d k	 r Pq WWn+ t k
 r0|  j r)|  j
 j     Yn X| |  _ | j |  _ | j |  _ | j |  _ | j |  _ d S)z0Create the object and initialize the XML parser.TFNzEmpty file.zXML file contains no data.)r   make_parserparserr   setContentHandler
setFeaturer   feature_namespacesopen	TypeErrorhandleshould_close_handleBLOCKreadr   r   feedr   	Exceptioncloser   r   r   r   )r   Zstream_or_pathr)   content_handlerrZ   r\   textr   r   r   r   r   b  s@    									zSeqXmlIterator.__init__c             C   s   |  S)Nr   )r   r   r   r   __iter__  s    zSeqXmlIterator.__iter__c             C   s  |  j  j   } | j } |  j } yY xR |  j j |  } | s@ P|  j  j |  t |  d k r' | j d  } | Sq' WWn+ t	 k
 r |  j
 r |  j j     Yn Xy | j d  } Wn t k
 r Yn X| S|  j  j   |  j
 r |  j j   t  d S)z)Iterate over the records in the XML file.r   r   N)rT   getContentHandlerr   r\   rZ   r]   r^   lenpopr_   r[   r`   
IndexErrorStopIteration)r   ra   r   r\   rb   r6   r   r   r   __next__  s2    				zSeqXmlIterator.__next__r      c             C   s
   |  j    S)z8Python 2 style alias for Python 3 style __next__ method.)ri   )r   r   r   r   next  s    zSeqXmlIterator.next)rN   rO   rP   rQ   r\   r   rc   ri   sysversion_infork   r   r   r   r   rR   S  s   '!rR   c               @   s   e  Z d  Z d Z d d d d d d  Z d d   Z d d   Z d	 d
   Z d d   Z d d   Z	 d d   Z
 d d   Z d d   Z d S)SeqXmlWriterzWrites SeqRecords into seqXML file.

    SeqXML requires the sequence alphabet be explicitly RNA, DNA or protein,
    i.e. an instance or subclass of Bio.Alphapet.RNAAlphabet,
    Bio.Alphapet.DNAAlphabet or Bio.Alphapet.ProteinAlphabet.
    Nc             C   sW   t  j |  |  t | d  |  _ |  j j   | |  _ | |  _ | |  _ | |  _ d S)z*Create Object and start the xml generator.zutf-8N)	r   r   r   xml_generatorr   r   source_versionr7   	ncbiTaxId)r   rZ   r   rp   r7   rq   r   r   r   r     s    			zSeqXmlWriter.__init__c             C   s   t  j |   d d d d d d i } |  j d k	 rA |  j | d <|  j d k	 r] |  j | d	 <|  j d k	 r t |  j t  s t d
   |  j | d <|  j d k	 r t |  j t t	 f  s t d   |  j | d <|  j
 j d t |   d S)z'Write root node with document metadata.z	xmlns:xsiz)http://www.w3.org/2001/XMLSchema-instancezxsi:noNamespaceSchemaLocationz$http://www.seqxml.org/0.4/seqxml.xsdr   z0.4Nr   r   z species should be of type stringr   z)ncbiTaxID should be of type string or intr   r   )r   write_headerr   rp   r7   
isinstancer   rY   rq   r    ro   startElementr   )r   r&   r   r   r   rr     s"    zSeqXmlWriter.write_headerc             C   s  | j  s | j  d k r% t d   t | j  t  sC t d   d | j  i } d | j k r |  j | j d k r t | j d t  s t d   | j d | d <|  j j d t	 |   |  j
 |  |  j |  |  j |  |  j |  |  j |  |  j j d  d S)	zWrite one record.z<unknown id>zSeqXML requires identifierz#Identifier should be of type stringr/   r   zsource should be of type stringr-   N)r/   r   rs   r   rY   r2   r   ro   rt   r   _write_species_write_description
_write_seq_write_dbxrefs_write_properties
endElement)r   r6   Zattrbr   r   r   write_record  s"    zSeqXmlWriter.write_recordc             C   s.   t  j |   |  j j d  |  j j   d S)z0Close the root node and finish the XML document.r   N)r   write_footerro   rz   endDocument)r   r   r   r   r|     s    zSeqXmlWriter.write_footerc             C   s:  d } d | j  k ry | j  d } t | t  ry t |  d k rP | d } n) t |  d k rk d } n t d |  d | j  k r6| r6| j  d } t | t  s t d   t | t t f  s t d   | |  j k s | |  j	 k r6d	 | d
 t
 |  i } |  j j d t |   |  j j d  d S)z%Write the species if given (PRIVATE).Nr1   r   r   z9Multiple entries for record.annotations['ncbi_taxid'], %rr0   z!organism should be of type stringz)ncbiTaxID should be of type string or intr$   r   r7   )r2   rs   listre   r   r   rY   r    r7   rq   strro   rt   r   rz   )r   r6   Zlocal_ncbi_taxidZ	local_orgattrr   r   r   ru     s*    	zSeqXmlWriter._write_speciesc             C   s   | j  r t | j  t  s' t d   | j  } | d k rB d } t | j   d k r |  j j d t i    |  j j |  |  j j	 d  d S)z)Write the description if given (PRIVATE).z$Description should be of type stringz<unknown description>r.   r   r8   N)
r8   rs   r   rY   re   ro   rt   r   rM   rz   )r   r6   r8   r   r   r   rv   #  s    		zSeqXmlWriter._write_descriptionc             C   s   t  | j t  r t d   t | j  } t |  d k sK t d   t j | j j	  } t  | t j
  r{ d } nB t  | t j  r d } n' t  | t j  r d } n t d   |  j j | t i    |  j j |  |  j j |  d S)	ziWrite the sequence (PRIVATE).

        Note that SeqXML requires a DNA, RNA or protein alphabet.
        z8Sequence type is UnknownSeq but SeqXML requires sequencer   z,The sequence length should be greater than 0r:   r9   r;   z#Need a DNA, RNA or Protein alphabetN)rs   rG   r	   rY   r   re   r   r   Z_get_base_alphabetrH   ZRNAAlphabetZDNAAlphabetZProteinAlphabetro   rt   r   rM   rz   )r   r6   rG   alphaZseqElemr   r   r   rw   3  s     			zSeqXmlWriter._write_seqc             C   s   | j  d k	 r x | j  D] } t | t  s: t d   | j d  d k  r[ t d   | j d d  \ } } d | d | i } |  j j d t	 |   |  j j
 d  q Wd S)	z.Write all database cross references (PRIVATE).Nz(dbxrefs should be of type list of string:r   z9dbxrefs should be in the form ['source:id', 'source:id' ]r   r/   r<   )rI   rs   r   rY   findr   splitro   rt   r   rz   )r   r6   rK   ZdbsourceZdbidr   r   r   r   rx   O  s    	zSeqXmlWriter._write_dbxrefsc             C   sC  x<| j  j   D]+\ } } | d k r | d k rl d | i } |  j j d t |   |  j j d  q t | t  r x | D]Y } t | t t	 t
 f  r d | d | i } |  j j d t |   |  j j d  q Wq t | t t	 t
 f  r d | d t |  i } |  j j d t |   |  j j d  q Wd S)	ztWrite all annotations that are key value pairs with values of a primitive type or list of primitive types (PRIVATE).r0   r1   r   Nr$   r=   r(   )zorganismz
ncbi_taxidzsource)r2   r   ro   rt   r   rz   rs   r~   r    floatr   r   )r   r6   r'   r(   r   vr   r   r   ry   b  s"    	zSeqXmlWriter._write_properties)rN   rO   rP   rQ   r   rr   r{   r|   ru   rv   rw   rx   ry   r   r   r   r   rn     s    rn   )rQ   rl   xml.sax.saxutilsr   Zxml.sax.xmlreaderr   Zxml.saxr   xmlr   Z	Bio._py3kr   ZBior   ZBio.Seqr   r	   ZBio.SeqRecordr
   Z
Interfacesr   r   objectrR   rn   r   r   r   r   <module>   s    2a