
:>"^7"              
   @   sO  d  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 m Z d d
 l m Z Gd d   d  Z d d   Z d d   Z d d   Z d d   Z d d   Z d e d e d e d e d e i Z d d   Z d d d d  Z d d d  d!  Z d" d#   Z d S)$zBio.SeqIO support for the SnapGene file format.

The SnapGene binary format is the native format used by the SnapGene program
from GSL Biotech LLC.
    )datetime)sub)unpack)parseString)Alphabet)	as_handle)Seq)
SeqFeatureFeatureLocation)	SeqRecordc               @   sF   e  Z d  Z d Z d d   Z d d   Z d d   Z d d	   Z d
 S)_PacketIteratora?  Iterate over the packets of a SnapGene file.

    A SnapGene file is made of packets, each packet being a TLV-like
    structure comprising:

      - 1 single byte indicating the packet's type;
      - 1 big-endian long integer (4 bytes) indicating the length of the
        packet's data;
      - the actual data.
    c             C   s   | |  _  d  S)N)handle)selfr    r   9/tmp/pip-build-ww9dw3qa/biopython/Bio/SeqIO/SnapGeneIO.py__init__&   s    z_PacketIterator.__init__c             C   s   |  S)Nr   )r   r   r   r   __iter__)   s    z_PacketIterator.__iter__c             C   s   |  j  j d  } t |  d k  r* t  t d |  d } |  j  j d  } t |  d k  rm t d   t d |  d } |  j  j |  } t |  | k  r t d   | | | f S)N   z>Br      zUnexpected end of packetz>I)r   readlenStopIterationr   
ValueError)r   typelengthdatar   r   r   __next__,   s    z_PacketIterator.__next__c             C   s
   |  j    S)N)r   )r   r   r   r   next>   s    z_PacketIterator.nextN)__name__
__module____qualname____doc__r   r   r   r   r   r   r   r   r      s
   
r   c             C   s~   | j  r t d   t d |  d |  \ } } t | j d  d t j | _  | d @rm d | j d <n d | j d <d	 S)
z}Parse a DNA sequence packet.

    A DNA sequence packet contains a single byte flag followed by the
    sequence itself.
    z*The file contains more than one DNA packetz>B%dsr   ASCIIZalphabetZcircularZtopologyZlinearN)seqr   r   r   decoder   Zgeneric_dnaannotations)r   r   recordflagssequencer   r   r   _parse_dna_packetB   s    	!
r)   c             C   s   t  | j d   } t | d  } | d k r@ d | j d <n d | j d <t | d  } | r{ t j | d  | j d	 <t | d
  } | r | | _ t | d  } | r | j d d  d | _ | | _	 | s | j | _ d S)zParse a 'Notes' packet.

    This type of packet contains some metadata about the sequence. They
    are stored as a XML string with a 'Notes' root node.
    r"   ZTypeZ	SyntheticZSYNZdata_file_divisionZUNCZLastModifiedz%Y.%m.%ddateZAccessionNumberZComments r   r   N)
r   r$   _get_child_valuer%   r   strptimeidsplitnamedescription)r   r   r&   xmlr   r*   acccommentr   r   r   _parse_notes_packetS   s"    		r5   c             C   s@   t  d |  \ } } } } | j d  d k r< t d   d S)zParse a SnapGene cookie packet.

    Every SnapGene file starts with a packet of this type. It acts as
    a magic cookie identifying the file as a SnapGene file.
    z>8sHHHr"   ZSnapGenez%The file is not a valid SnapGene fileN)r   r$   r   )r   r   r&   cookieZseq_typeZexp_versionZimp_versionr   r   r   _parse_cookie_packetp   s    r7   c             C   sR  t  | j d   } x6| j d  D]%} i  } t | d d d } t | d  } | rh | g | d <d } t t | d	 d d
  }	 |	 d k r d } d }
 x | j d  D]x } t | d  } d d   | j d  D \ } } | d } |
 st | | d | }
 q |
 t | | d | }
 q W|
 s?t d   x | j d  D] } t | d d d } g  } x | j d  D] } | j d  r| j	 t
 | j d j   q| j d  r| j	 t
 | j d j   q| j d  r| j	 t | j d j   qW| | | <qOWt |
 d | d | } | j j	 |  q% Wd S)zParse a sequence features packet.

    This packet stores sequence features (except primer binding sites,
    which are in a dedicated Primers packet). The data is a XML string
    starting with a 'Features' root node.
    r"   Featurer   defaultZmisc_featurer0   labelr   directionality1   NZSegmentrangec             S   s   g  |  ] } t  |   q Sr   )int).0xr   r   r   
<listcomp>   s   	 z*_parse_features_packet.<locals>.<listcomp>-strandzMissing feature locationQerrorzMissing qualifier nameVtextZpredefr?   
qualifiersr   )r   r$   getElementsByTagName_get_attribute_valuer?   r/   r
   r   hasAttributeappend_decode
attributesvaluer	   features)r   r   r&   r2   featurequalsr   r:   rD   r;   locationZsegmentrngstartendZ	qualifierqnameZqvaluesrQ   r   r   r   _parse_features_packet{   sH    "
  !rZ   c             C   s  t  | j d   } x | j d  D] } i  } t | d  } | rS | g | d <x | j d  D] } t | d d d } d	 d
   | j d  D \ }	 }
 t t | d d d  } | d k r d } n d } t t |	 |
 d | d d d | } | j j	 |  qc Wq% Wd S)zParse a Primers packet.

    A Primers packet is similar to a Features packet but specifically
    stores primer binding features. The data is a XML string starting
    with a 'Primers' root node.
    r"   ZPrimerr0   r:   ZBindingSiterU   rF   zMissing binding site locationc             S   s   g  |  ] } t  |   q Sr   )r?   )r@   rA   r   r   r   rB      s   	 z)_parse_primers_packet.<locals>.<listcomp>rC   ZboundStrandr9   0r   rD   r   Zprimer_bindrI   NrJ   r   )
r   r$   rK   rL   r/   r?   r	   r
   rR   rN   )r   r   r&   r2   ZprimerrT   r0   siterV   rW   rX   rD   rS   r   r   r   _parse_primers_packet   s&    "		r]         	   
   c             C   s   t  d d |   S)Nz<[^>]+> )r   )rH   r   r   r   rO      s    rO   Nc             C   s@   |  j  |  r# t |  j | j  S| r8 t |   n | Sd  S)N)rM   rO   rP   rQ   r   )noder0   r9   rF   r   r   r   rL      s
    rL   c             C   sl   |  j  |  } | rO | d j rO | d j j |  j k rO t | d j j  S| rd t |   n | Sd  S)Nr   )rK   
childNodesZ
firstChildZnodeTypeZ	TEXT_NODErO   r   r   )rc   r0   r9   rF   childrenr   r   r   r,      s    r,   c             c   s   t  d  } d } d } t |  d   }  xs t t |    D]_ \ } \ } } } d } | d k r| | d k r| t d   | t k r= t | | | |  q= W| r t d   | j s t d	   | VWd QRXd S)
zParse a SnapGene file and return a SeqRecord object.

    Note that a SnapGene file can only contain one sequence, so this
    iterator will always return a single record.
    Nr   TrbFr`   z5The file does not start with a SnapGene cookie packetzEmpty file.zNo DNA packet in file)r   r   	enumerater   r   _packet_handlersr#   )r   r&   nemptyr   r   r   r   r   r   SnapGeneIterator   s     (		rk   )r!   r   rer   structr   Zxml.dom.minidomr   ZBior   ZBio.Filer   ZBio.Seqr   ZBio.SeqFeaturer	   r
   ZBio.SeqRecordr   r   r)   r5   r7   rZ   r]   rh   rO   rL   r,   rk   r   r   r   r   <module>   s0   (6$	