B
    }dV                 @   sX  d Z ddlZddlZddlmZ ddlmZ ddlmZ ddl	Z	yddl
mZmZ W n ek
rp   dZdZY nX ddlmZmZ d	d
lmZ dZdZdZdZd9ddZe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"d#Z!d<d$d%Z"d=d&d'Z#d(d) Z$d>d+d,Z%d?d-d.Z&d/d0 Z'd1d2 Z(d3d4 Z)d5d6 Z*ed7d8 Z+dS )@zBasic utilities for reading/writing LIGO_LW-format XML files.

All specific unified input/output for class objects should be placed in
an 'io' subdirectory of the containing directory for that class.
    N)contextmanager)wraps)import_module)ElementErrorLIGOLWContentHandler   )	file_list	FILE_LIKE   )deprecated_functionz(Duncan Macleod <duncan.macleod@ligo.org>s   <?xmls   <!doctype ligo_lws	   <ligo_lw>c             C   s>   ddl m} y
|| |S  tk
r8   |t| t|S X dS )z3Catch TypeError and cast `s` and `ns` to `int`
    r   )LIGOTimeGPSN)Zlalr   	TypeErrorint)snsr    r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/io/ligolw.py_ligotimegps7   s
    
r   ligo.lw.lsctablesc             c   s,   t | } | j}t| _z
dV  W d|| _X dS )zLContext manager to on-the-fly patch LIGOTimeGPS to accept all int types
    N)r   r   r   )moduleorigr   r   r   patch_ligotimegpsA   s    
r   c             C   sF   y|   d\}}}W n$ tk
r<   td|  dY nX t|S )z0Convert an ``ilwd`` string into an integer.
    :zinvalid ilwd:char '')stripsplit
ValueErrorr   )Zilwd_ir   r   r   	_int_ilwdP   s
    r   c                sH   ddl m ddlm m ddlm G  fddd}|S )zWrap a LIGO_LW content handler to swap ilwdchar for int on-the-fly
    when reading a document

    This is adapted from :func:`ligo.skymap.utils.ilwd`, copyright
    Leo Singer (GPL-3.0-or-later).
    r   )TableByName)ColumnTableStream)
FromPyTypec                   sP   e Zd Z fddZej fddZej fddZ  ZS )z-strip_ilwdchar.<locals>.IlwdMapContentHandlerc                s   t  j|| i | _d S )N)super__init___idconverter)selfargskwargs)	__class__r   r   r%   g   s    z6strip_ilwdchar.<locals>.IlwdMapContentHandler.__init__c                s   t  ||}|jdkr6t| jt||jf< t |_y|j j}W n t	k
rZ   |S X |j|kr fdd|D }|j|kr|
d||j  |S )Nz	ilwd:charc                s   i | ]}|  |qS r   )Z
ColumnName).0name)r!   r   r   
<dictcomp>y   s   zMstrip_ilwdchar.<locals>.IlwdMapContentHandler.startColumn.<locals>.<dictcomp>Name)r$   startColumnTyper   r&   idr.   r   validcolumnsKeyErrorZsetAttribute)r'   parentattrsresultr2   Zstripped_column_to_valid_column)r!   r#   r    r*   r   r   r/   k   s     




z9strip_ilwdchar.<locals>.IlwdMapContentHandler.startColumnc                sn   t  ||}t|rjt|j |jd k	r: t|jM  t||j fddt	|j
|jD  |S )Nc                s.   g | ]&\}}| kr&j |f|nd qS )N)r&   pop)r+   Zpytypecolname)loadcolumnspidr'   r   r   
<listcomp>   s   zMstrip_ilwdchar.<locals>.IlwdMapContentHandler.startStream.<locals>.<listcomp>)r$   startStream
isinstancesetZcolumnnamesr9   r1   Z
_tokenizerZ	set_typeszipZcolumnpytypes)r'   r4   r5   r6   )r"   r*   )r9   r:   r'   r   r<      s    


z9strip_ilwdchar.<locals>.IlwdMapContentHandler.startStream)__name__
__module____qualname__r%   r   r/   r<   __classcell__r   )r!   r#   r    r"   _ContentHandler)r*   r   IlwdMapContentHandlere   s   rE   )ligo.lw.lsctablesr    ligo.lw.tabler!   r"   ligo.lw.typesr#   )rD   rE   r   )r!   r#   r    r"   rD   r   strip_ilwdcharZ   s
    2rI   c             C   s(   ddl m} t|G dd d| }|S )Nr   )use_inc               @   s   e Zd ZdS )z-_wrap_content_handler.<locals>.ContentHandlerN)r@   rA   rB   r   r   r   r   ContentHandler   s   rK   )rF   rJ   rI   )contenthandlerrJ   rK   r   r   r   _wrap_content_handler   s
    
rM   c              C   s   ddl m}  t| S )a  Return a standard content handler to read LIGO_LW documents

    This handler knows how to parse LSCTables, and automatically converts
    old-style ilwdchar ID types to `int`.

    Returns
    -------
    contenthandler : subclass of `ligo.lw.ligolw.LIGOLWContentHandler`
    r   )r   )ligo.lw.ligolwr   rM   )r   r   r   r   default_content_handler   s    
rO   c                sF   ddl m} ddlm} t |r0 fdd}n fdd}t||S )am  Build a `PartialLIGOLWContentHandler` to read only this element

    Parameters
    ----------
    element : `type`, subclass of :class:`~ligo.lw.ligolw.Element`
        the element class to be read

    Returns
    -------
    contenthandler : `type`
        a subclass of `~ligo.lw.ligolw.PartialLIGOLWContentHandler`
        to read only the given `element`
    r   )PartialLIGOLWContentHandler)Tablec                s     | |S )N)CheckProperties)r,   r5   )elementr   r   _element_filter   s    z3get_partial_contenthandler.<locals>._element_filterc                s
   |  j kS )N)tagName)r,   r   )rS   r   r   rT      s    )rN   rP   rG   rQ   
issubclassbuild_content_handler)rS   rP   rQ   rT   r   )rS   r   get_partial_contenthandler   s    
rX   c                sF   ddl m} ddlm} t |r0 fdd}n fdd}t||S )a  Build a `FilteringLIGOLWContentHandler` to exclude this element

    Parameters
    ----------
    element : `type`, subclass of :class:`~ligo.lw.ligolw.Element`
        the element to exclude (and its children)

    Returns
    -------
    contenthandler : `type`
        a subclass of `~ligo.lw.ligolw.FilteringLIGOLWContentHandler`
        to exclude an element and its children
    r   )FilteringLIGOLWContentHandler)rQ   c                s     | | S )N)rR   )r,   r5   )rS   r   r   rT      s    z5get_filtering_contenthandler.<locals>._element_filterc                s
   |  j kS )N)rU   )r,   r   )rS   r   r   rT      s    )rN   rY   rG   rQ   rV   rW   )rS   rY   rQ   rT   r   )rS   r   get_filtering_contenthandler   s    
rZ   c                s   G  fddd| }t |S )a  Build a `~xml.sax.handler.ContentHandler` with a given filter

    Parameters
    ----------
    parent : `type`, subclass of `xml.sax.handler.ContentHandler`
        a class of contenthandler to use

    filter_func : `callable`
        the filter function to pass to the content handler creation

    Returns
    -------
    contenthandler : subclass of ``parent``
        a new content handler that applies the filter function and the
        default parsing extras from :func:`_wrap_content_handler`.
    c                   s   e Zd Z fddZ  ZS )z-build_content_handler.<locals>.ContentHandlerc                s   t  | d S )N)r$   r%   )r'   Zdocument)r*   filter_funcr   r   r%      s    z6build_content_handler.<locals>.ContentHandler.__init__)r@   rA   rB   r%   rC   r   )r[   )r*   r   rK      s   rK   )rM   )r4   r[   rK   r   )r[   r   rW      s    rW   c       	      K   s   ddl m} ddlm} ddlm}m} |j }x0|jD ]&}||j	kr:t
|j	| j|j|< q:W |dkrrt }t| } z>t| dkr|| d fd|i|S |j| | fd|i|S ||_X dS )a  Read one or more LIGO_LW format files

    Parameters
    ----------
    source : `str`, `file`
        the open file or file path to read

    contenthandler : `~xml.sax.handler.ContentHandler`, optional
        content handler used to parse document

    verbose : `bool`, optional
        be verbose when reading files, default: `False`

    Returns
    -------
    xmldoc : :class:`~ligo.lw.ligolw.Document`
        the document object as parsed from the file(s)
    r   )Document)types)load_url
ligolw_addNr   rL   )rN   r\   ligo.lwr]   ligo.lw.utilsr^   r_   ToPyTypecopyToNumPyTypenumpyZdtypetyperO   r   len)	sourcerL   r)   r\   r]   r^   r_   Ztopytypekeyr   r   r   read_ligolw  s,    


rj   c             K   s   ddl m} ddlm}m} |dk	rZ|j|j| }|dkrFt|}|j	}	|dk	rZ||_	t
| |rj| }
n8|dkrxt }zt| fd|i|}
W d|dk	r|	|_	X |dkrt|
}|stdt|dkrtdd	||j|j|d  }||
S )
a  Read a :class:`~ligo.lw.table.Table` from one or more LIGO_LW files

    Parameters
    ----------
    source : `Document`, `file`, `str`, `CacheEntry`, `list`
        object representing one or more files. One of

        - a LIGO_LW :class:`~ligo.lw.ligolw.Document`
        - an open `file`
        - a `str` pointing to a file path on disk
        - a formatted :class:`~lal.utils.CacheEntry` representing one file
        - a `list` of `str` file paths or :class:`~lal.utils.CacheEntry`

    tablename : `str`
        name of the table to read.

    columns : `list`, optional
        list of column name strings to read, default all.

    contenthandler : `~xml.sax.handler.ContentHandler`, optional
        SAX content handler for parsing LIGO_LW documents.

    **kwargs
        other keyword arguments are passed to `~gwpy.io.ligolw.read_ligolw`

    Returns
    -------
    table : :class:`~ligo.lw.table.Table`
        `Table` of data
    r   )r\   )table	lsctablesNrL   z&No tables found in LIGO_LW document(s)r   zMultiple tables found in LIGO_LW document(s), please specify the table to read via the ``tablename=`` keyword argument. The following tables were found: '{}'z', ')rN   r\   r`   rk   rl   r    rQ   	TableNamerX   r9   r=   rO   rj   list_tablesr   rg   formatjoin	get_table)rh   Z	tablenamecolumnsrL   r)   r\   rk   rl   Z
tableclassZ_oldcolsxmldoctablesr   r   r   
read_table>  s>    %
ru   c          	   K   s   ddl m} ddlm} |dkr&t }t| tsvy*t| d}t|fd|i|S Q R X W n t	t
fk
rt   | S X || fd|i|S )a  Try and open an existing LIGO_LW-format file, or create a new Document

    Parameters
    ----------
    fobj : `str`, `file`
        file path or open file object to read

    contenthandler : `~xml.sax.handler.ContentHandler`, optional
        the content handler with which to parse the document, if not given
        a default handler will be created using
        :func:`default_content_handler`.

    **kwargs
        other keyword arguments to pass to
        :func:`~ligo.lw.utils.load_fileobj` as appropriate

    Returns
    --------
    xmldoc : :class:`~ligo.lw.ligolw.Document`
        either the `Document` as parsed from an existing file, or a new, empty
        `Document`
    r   )r\   )load_fileobjNrbrL   )rN   r\   ra   rv   rO   r=   r	   openopen_xmldocOSErrorIOError)ZfobjrL   r)   r\   rv   Zfobj2r   r   r   ry     s"    
ry   c             C   sJ   ddl m}m} t| |r| S x|| D ]}t||r(|S q(W tddS )z<Find an existing <LIGO_LW> element in this XML Document
    r   )LIGO_LWWalkChildrenz+Cannot find LIGO_LW element in XML DocumentN)rN   r|   r}   r=   r   )rs   r|   r}   elemr   r   r   get_ligolw_element  s    

r   Fc          	   C   s   ddl m} ddlm} yt| }W n$ tk
rH   | }| | Y nX xt|D ]l}y|j||j	 
| }W n tk
r   || Y qPX |r|| |  || qP|| qPW | S )a  Write the given LIGO_LW table into a :class:`Document`

    Parameters
    ----------
    xmldoc : :class:`~ligo.lw.ligolw.Document`
        the document to write into

    tables : `list` of :class:`~ligo.lw.table.Table`
        the set of tables to write

    overwrite : `bool`, optional, default: `False`
        if `True`, delete an existing instance of the table type, otherwise
        append new rows
    r   )r|   )rl   )rN   r|   r`   rl   r   r   ZappendChildr    rm   r.   rq   ZremoveChildunlinkextend)rs   rt   	overwriter|   rl   llwrk   oldr   r   r   write_tables_to_document  s&    

r   c             K   s   ddl m}m} ddlm} t| ||fr0| }	nV|rP|dkrBt }t| |d}	n6|st| tt	j
frt	j| rtd|  n| }	t|	||d t| tr|j}
| j}n|j}
t|  }} |dr|d	d
 |
|	| f| dS )at  Write an LIGO_LW table to file

    Parameters
    ----------
    target : `str`, `file`, :class:`~ligo.lw.ligolw.Document`
        the file or document to write into

    tables : `list`, `tuple` of :class:`~ligo.lw.table.Table`
        the tables to write

    append : `bool`, optional, default: `False`
        if `True`, append to an existing file/table, otherwise `overwrite`

    overwrite : `bool`, optional, default: `False`
        if `True`, delete an existing instance of the table type, otherwise
        append new rows

    contenthandler : `~xml.sax.handler.ContentHandler`, optional
        the content handler with which to parse the document, if not given
        a default handler will be created using
        :func:`default_content_handler`.

    **kwargs
        other keyword arguments to pass to
        :func:`~ligo.lw.utils.load_fileobj` as appropriate
    r   )r\   r|   )utilsN)rL   zFile exists: )r   z.gzcompressgz)rN   r\   r|   r`   r   r=   rO   ry   strosPathLikepathexistsr{   r   r	   Zwrite_fileobjr,   Zwrite_filenameendswith
setdefault)targetrt   appendr   rL   r)   r\   r|   Zligolw_utilsrs   writerr,   r   r   r   write_tables  s0    "


r   c             c   s`   ddl m}m}m} t| |s2t|}t| |d} t| }x ||D ]}|jdkrD|V  qDW dS )a;  Iterate over all tables in the given document(s)

    Parameters
    ----------
    source : `file`, `str`, :class:`~ligo.lw.ligolw.Document`, `list`
        one or more open files, file paths, or LIGO_LW `Document`s

    Yields
    ------
    ligo.lw.table.Table
        a table structure from the document(s)
    r   )ElementStreamr}   )rL   rQ   N)	rN   r   r   r}   r=   rZ   rj   r   rU   )rh   r   r   r}   Zfiltr   r~   r   r   r   iter_tablesM  s    

r   c             C   s   dd t | D S )a  List the names of all tables in this file(s)

    Parameters
    ----------
    source : `file`, `str`, :class:`~ligo.lw.ligolw.Document`, `list`
        one or more open files, file paths, or LIGO_LW `Document`s

    Examples
    --------
    >>> from gwpy.io.ligolw import list_tables
    >>> print(list_tables('H1-LDAS_STRAIN-968654552-10.xml.gz'))
    ['process', 'process_params', 'sngl_burst', 'search_summary', 'segment_definer', 'segment_summary', 'segment']
    c             S   s   g | ]}| |jqS r   )rm   r.   )r+   tblr   r   r   r;   v  s    zlist_tables.<locals>.<listcomp>)r   )rh   r   r   r   rn   h  s    rn   c             C   sd   ddl m}m} | dks"||jkr&| S |j| }ytj||  | S  tk
r^   || | S X dS )a  Cast a value to the correct type for inclusion in a LIGO_LW table

    This method returns the input unmodified if a type mapping for ``colname``
    isn't found.

    Parameters
    ----------
    val : `object`
        The input object to convert, of any type

    cls : `type`, subclass of :class:`~ligo.lw.table.Table`
        the table class to map against

    colname : `str`
        The name of the mapping column

    Returns
    -------
    obj : `object`
        The input ``val`` cast to the correct type

    Examples
    --------
    >>> from gwpy.io.ligolw import to_table_type as to_ligolw_type
    >>> from ligo.lw.lsctables import SnglBurstTable
    >>> x = to_ligolw_type(1.0, SnglBurstTable, 'central_freq'))
    >>> print(type(x), x)
    <class 'numpy.float32'> 1.0
    r   )rd   rb   N)rH   rd   rb   r2   re   Z
sctypeDictr3   )valclsr8   Z
numpytypesZpytypesZllwtyper   r   r   to_table_typey  s    
r   c       	   	   O   s   |dk	r|  }|d zp|  }|  }y|toL|ttfS  tk
r   |t	do|t	dt	dfS X W d|| X yddl
m} W n tk
r   dS X t|dkot|d |S )z1Identify a file object as LIGO_LW-format XML
    Nr   zutf-8)r   )tellseekreadlinelower
startswithXML_SIGNATURELIGOLW_SIGNATURELIGOLW_ELEMENTr   decoderN   r   ImportErrorrg   r=   )	originfilepathfileobjr(   r)   locline1line2r   r   r   r   	is_ligolw  s(    

r   c          	   O   sV   |dk	r@|  }|d z|d }|tkS || X n|dk	rR|dS dS )z/Identify a file object as XML (any format)
    Nr      )z.xmlz.xml.gz)r   r   readr   r   r   )r   r   r   r(   r)   r   sigr   r   r   is_xml  s    
r   )r   )r   )N)NNN)N)F)FFN),__doc__r   os.path
contextlibr   	functoolsr   	importlibr   re   rN   r   ZLigolwElementErrorr   r   r   r   r	   Zutils.decoratorsr   
__author__r   r   r   r   r   r   rI   rM   rO   rX   rZ   rW   rj   ru   ry   r   r   r   r   rn   r   r   r   r   r   r   r   <module>   sT   



@
8  
T
1
-  
J2!