B
    dL                 @   s  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
Z
ddlmZ ddlmZ d	d
lmZ d	dlmZmZ dZddddddddgZd)ddZeedd Zdd Zdd Zd*ddZd+ddZd,ddZd-ddZd.d!d"Zd/d%dZd0d&dZ d1d(dZ!dS )2zUser interface functions for GWDataFind.

These are all imported to the top-level namespace, so should be
referred to in usage as ``gwdatafind.<function>`` and not
``gwdatafind.ui.<function>``
    )wraps)compile)urlparse)warnN)get)segments   )api)file_segmentget_default_hostz(Duncan Macleod <duncan.macleod@ligo.org>connectpingfind_observatories
find_types
find_timesfind_latestfind_url	find_urlsc       	      C   s   ddl }ddlm}m} ddlm} tdt | dkr<t } |dkrvy| 	dd\} }W n t
k
rl   Y n
X t|}|dkr| \}}| }||| || ||d	S || |d
S )a(  Open a new connection to a Datafind server.

    This method will auto-select between HTTP and HTTPS based on port,
    and (for HTTPS) will automatically load the necessary X509 credentials
    using :func:`gwdatafind.utils.find_credential`.

    .. warning::

       This method is deprecated and will be removed in a future release

    Parameters
    ----------
    host : `str`, optional
        the name of the datafind server to connect to; if not given will be
        taken from the ``GWDATAFIND_SERVER`` environment variable.

    port : `int`, optional
        the port on the server to use, if not given it will be stripped from
        the ``host`` name.

    Returns
    -------
    connection : `gwdatafind.HTTPConnection` or `gwdatafind.HTTPSConnection`
        a newly opened connection
    r   Nr   )HTTPConnectionHTTPSConnection)find_credentialzAthis method is deprecated and will be removed in a future release:)NP   )hostportcontext)r   r   )sslhttpr   r   utilsr   r   DeprecationWarningr   rsplit
ValueErrorintcreate_default_contextload_cert_chain)	r   r   r   r   r   r   certkeyr    r'   Z/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwdatafind/ui.pyr   ;   s(    
c             O   s   |  dr tjdk r |dd t| d d \}}|ddd }|d	t| d
| | d
| dh |dd t| f||S )Nzhttp://z2.15.0r%   F   r   r   r   Ztoken_audiencez://ANYZtoken_scopezgwdatafind.read)
startswithrequests__version__
setdefaultr   splitlist_get)urlargskwargsschemenetlocr   r'   r'   r(   r   p   s    
r   c              O   s   t | |}|  | S )a  Perform a GET request and return JSON.

    Parameters
    ----------
    *args, **kwargs
        all keyword arguments are passed directly to
        :meth:`igwn_auth_utils.requests.get`

    Returns
    -------
    data : `object`
        the URL reponse parsed with :func:`json.loads`

    See also
    --------
    igwn_auth_utils.requests.get
        for information on how the request is performed
    )r   raise_for_statusjson)r3   r4   responser'   r'   r(   get_json   s    
r:   c             O   sj   |||}| dkrt  } d| krV| d} | ddd drLd|  } n
d|  } d	j| d|d
S )a_  Construct the full URL for a query to ``host`` using an API function.

    Parameters
    ----------
    host : `str`, `None`
        the host to query, if `None` `~gwdatafind.utils.get_default_host()`
        will be used to discover the default host.

    api_func : `callable`
        the function from the :mod:`gwdatafind.api` module to use in
        constructing the URL path.

    *args, **kwargs
        any positional or keyword arguments are passed directly as
        ``api_func(*args, **kwargs)``

    Returns
    -------
    url : `str`
        a full URL including scheme, host, and path
    Nz:///r   r   z:80zhttp://zhttps://z{host}/{path})r   path)r   lstripr/   endswithformatrstrip)r   Zapi_funcr3   r4   r<   r'   r'   r(   _url   s    


rA   c             K   s,   t | tj}t|fd|i|}|  dS )a  Ping the GWDataFind host to test for life.

    Parameters
    ----------
    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Raises
    ------
    requests.RequestException
        if the request fails for any reason
    sessionN)rA   r	   Z	ping_pathr   r7   )r   rB   
request_kwqurlr9   r'   r'   r(   r      s    c             K   sH   t |tj}tt|fd|i|}| r@t| j} tt| |S t|S )aT  Query a GWDataFind host for observatories with available data.

    Parameters
    ----------
    match : `str`, `re.Pattern`, optional
        restrict returned observatories to those matching a
        regular expression.

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Returns
    -------
    obs : `list` of `str`
        the list of known observatories prefices (and combinations)

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason

    Examples
    --------
    >>> find_observatories(host="datafind.gw-openscience.org")
    ['L', 'V', 'H']
    >>> find_observatories(match="H", host="datafind.gw-openscience.org")
    ['H']
    rB   )	rA   r	   Zfind_observatories_pathsetr:   compile_regexsearchr0   filter)matchr   rB   rC   rD   sitesr'   r'   r(   r      s    /
c             K   sL   t |tj| d}tt|fd|i|}|rDt|j}tt||S t|S )aJ  Query a GWDataFind host for dataset types.

    Parameters
    ----------
    site : `str`, optional
        single-character name of site to match; if not given
        types for all sites will be returned.

    match : `str`, `re.Pattern`, optional
        regular expression to match against known types

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`~igwn_auth_utils.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Returns
    -------
    types : `list` of `str`
        list of dataset types

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason

    Examples
    --------
    >>> find_types(host="datafind.gw-openscience.org")
    ['H2_LOSC_4_V1', 'V1_GWOSC_O3a_16KHZ_R1', 'H1_LOSC_16_V1', 'L1_LOSC_4_V1', 'V1_GWOSC_O2_16KHZ_R1', 'V1_GWOSC_O3a_4KHZ_R1', 'L1_GWOSC_O3a_4KHZ_R1', 'L1_GWOSC_O2_16KHZ_R1', 'L1_GWOSC_O2_4KHZ_R1', 'V1_GWOSC_O2_4KHZ_R1', 'H1_LOSC_4_V1', 'H1_GWOSC_O3a_16KHZ_R1', 'H1_GWOSC_O2_16KHZ_R1', 'H1_GWOSC_O3a_4KHZ_R1', 'L1_GWOSC_O3a_16KHZ_R1', 'H1_GWOSC_O2_4KHZ_R1', 'L1_LOSC_16_V1']
    >>> find_types(site='V', host="datafind.gw-openscience.org")
    ['V1_GWOSC_O3a_4KHZ_R1', 'V1_GWOSC_O3a_16KHZ_R1', 'V1_GWOSC_O2_4KHZ_R1', 'V1_GWOSC_O2_16KHZ_R1']

    (accurate as of Nov 18 2021)
    )siterB   )	rA   r	   Zfind_types_pathrE   r:   rF   rG   r0   rH   )rK   rI   r   rB   rC   rD   typesr'   r'   r(   r     s    4
c       	      K   s:   t |tj| |||}t|fd|i|}tttj|S )a  Query a GWDataFind host for times in which data are available.

    Parameters
    ----------
    site : `str`
        single-character name of site to match

    frametype : `str`
        name of dataset to match

    gpsstart : `int`, optional
        GPS start time of query

    gpsend : `int`, optional
        GPS end time of query

    match : `str`, `re.Pattern`, optional
        regular expression to match against known types

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Returns
    -------
    segments : `segments.segmentlist`
        the list of ``[start, end)`` intervals during which data are
        available for the relevant dataset.

    Examples
    --------
    >>> find_times(
    ...     "V",
    ...     "V1_GWOSC_O3a_4KHZ_R1",
    ...     gpsstart=1238249472,
    ...     gpsend=1239429120,
    ...     host="datafind.gw-openscience.org",
    ... )
    [segment(1238249472, 1238417408), segment(1238421504, 1238605824), segment(1238609920, 1238827008), segment(1238839296, 1239429120)]

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason
    rB   )rA   r	   Zfind_times_pathr:   r   segmentlistmapsegment)	rK   	frametypegpsstartgpsendr   rB   rC   rD   timesr'   r'   r(   r   T  s    Gignorec                sZ   t | f|} r&tt fdd|}|s2|dkr6|S d}|dkrNt| |S t|d S )Nc                s   t | j kS )N)r   r5   )e)r5   r'   r(   <lambda>      z_get_urls.<locals>.<lambda>rT   zno files foundr   )r:   r0   rH   r   RuntimeError)rD   r5   
on_missingr4   urlserrr'   )r5   r(   	_get_urls  s    r\   fileerrorc             K   s&   t |tj| }t|f|||d|S )a*  Query a GWDataFind host for the URL of a single filename.

    Parameters
    ----------
    framefile : `str`
        the name of the file to match; note that only the basename of
        the file is relevant.

    urltype : `str`, optional
        URL scheme to search for

    on_missing : `str`, optional
        what to do when the requested file isn't found, one of:

        - ``'error'``: raise a `RuntimeError`
        - ``'warn'``: print a warning but return an empty `list`
        - ``'ignore'``: return an empty `list` with no warnings

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Returns
    -------
    urls : `list` of `str`
        a list of URLs for all instances of ``filename``

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason

    RuntimeError
        if no matching URLs are found and ``on_missing="error"`` was given
    )r5   rY   rB   )rA   r	   Zfind_url_pathr\   )Z	framefileurltyperY   r   rB   rC   rD   r'   r'   r(   r     s    <c             K   s(   t |tj| ||d}t|fd|i|S )a,  Query a GWDataFind host for the latest file in a given dataset.

    Parameters
    ----------
    site : `str`
        single-character name of site to match

    frametype : `str`
        name of dataset to match

    urltype : `str`, optional
        URL scheme to search for

    on_missing : `str`, optional
        what to do when the requested file isn't found, one of:

        - ``'error'``: raise a `RuntimeError`
        - ``'warn'``: print a warning but return an empty `list`
        - ``'ignore'``: return an empty `list` with no warnings

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Returns
    -------
    urls : `list` of `str`
        a list of URLs for the latest file found

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason

    RuntimeError
        if no latest file is found and ``on_missing="error"`` was given

    Examples
    --------
    >>> find_latest('H', 'H1_GWOSC_O2_4KHZ_R1', urltype='file', host='datafind.gw-openscience.org'))
    ['file://localhost/cvmfs/gwosc.osgstorage.org/gwdata/O2/strain.4k/frame.v1/H1/1186988032/H-H1_GWOSC_O2_4KHZ_R1-1187733504-4096.gwf']
    )r_   rY   )rA   r	   Zfind_latest_pathr\   )rK   rP   r_   rY   r   rB   rC   rD   r'   r'   r(   r     s    Dr   c	          
   K   s   t |tj| |||||d}
t|
fd|i|	}|dkr:|S t||}ttt|	 }t|g| 	 }|sv|S dd
tt| }|dkrt| |S t|dS )a  Query a GWDataFind host for all URLs for a dataset in an interval.

    Parameters
    ----------
    site : `str`
        single-character name of site to match

    frametype : `str`
        name of dataset to match

    gpsstart : `int`, optional
        GPS start time of interval

    gpsend : `int`, optional
        GPS end time of interval

    match : `str`, `re.Pattern`, optional
        regular expression pattern to match URLs against

    urltype : `str`, optional
        URL scheme to search for

    on_gaps : `str`, optional
        what to do when the requested all or some of the GPS interval
        is not covereed by the dataset, one of:

        - ``'error'``: raise a `RuntimeError`
        - ``'warn'``: print a warning but return all available URLs
        - ``'ignore'``: return the list of URLs with no warnings

    host : `str`, optional
        the URL/name of the GWDataFind host to query; if not given
        :func:`~gwdatafind.utils.get_default_host` will be used to
        discover the default host.

    session : `requests.Session`, optional
        the connection session to use; if not given, a
        :class:`igwn_auth_utils.requests.Session` will be
        created on-the-fly

    token, token_audience, token_scope
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`scitokens` for more details.

    cert
        passed directly to :class:`~igwn_auth_utils.Session`, see
        :ref:`x509` for more details.

    request_kw
        other keywords are passed to :func:`igwn_auth_utils.get`

    Raises
    ------
    requests.RequestsException
        if the request fails for any reason

    RuntimeError
        if gaps in the dataset are found and ``on_gaps="error"`` was given
    )r_   rI   rB   rT   zMissing segments: 
%s
r   N)rA   r	   Zfind_urls_pathr\   r   rO   rM   rN   r
   Zcoalescejoinstrr   rX   )rK   rP   rQ   rR   rI   r_   Zon_gapsr   rB   rC   rD   rZ   spanZseglistmissingmsgr'   r'   r(   r   ?  s,    G)NN)NN)NNN)NNNN)NNNN)NrT   )r]   r^   NN)r]   r^   NN)Nr]   r   NN)"__doc__	functoolsr   rer   rF   urllib.parser   warningsr   r,   Zigwn_auth_utils.requestsr   r1   Zligor    r	   r   r
   r   
__author____all__r   r:   rA   r   r   r   r   r\   r   r   r   r'   r'   r'   r(   <module>   sV   
5%
$
7
?   
F
   
D   
G    