U
    f/e,                     @  s"  d dl mZ d dlZd dlmZ d dlZd dlmZmZ d dl	Z	d dl
mZmZ d dlmZmZ d dlZd dlmZ d dlmZ d d	lmZ d
Ze ZdZdZdd Zdd Zeded
deefddZeZd'ddZ d(ddddddZ!d)ddddZ"d*ddd d!Z#d+d#d$Z$d,d%d&Z%dS )-    )annotationsNwraps)AnyCallable)FilePathOrBufferFrameOrSeries)get_lzma_fileimport_lzma)rands)ensure_clean)urlopenF)z	timed outzServer Hangupz#HTTP Error 503: Service Unavailablez502: Proxy ErrorzHTTP Error 502: internal errorzHTTP Error 502zHTTP Error 503zHTTP Error 403zHTTP Error 400z$Temporary failure in name resolutionzName or service not knownzConnection refusedzcertificate verify)e   o   n   h   6   <   c                  C  s   dd l } t| jjtfS )Nr   )http.clientIOErrorclientHTTPExceptionTimeoutError)http r   7/tmp/pip-unpacked-wheel-tiezk1ph/pandas/_testing/_io.py_get_default_network_errorsE   s    r   c                   s   t   fdd}|S )aB  
    allows a decorator to take optional positional and keyword arguments.
    Assumes that taking a single, callable, positional argument means that
    it is decorating a function, i.e. something like this::

        @my_decorator
        def function(): pass

    Calls decorator with decorator(f, *args, **kwargs)
    c                    sN    fdd} o,t  dko,t d }|rF d }d ||S |S d S )Nc                   s   | f S Nr   )f)args	decoratorkwargsr   r   decZ   s    z+optional_args.<locals>.wrapper.<locals>.dec   r   r   )lencallable)r   r!   r"   Zis_decoratingr   r    )r   r!   r   wrapperX   s    zoptional_args.<locals>.wrapperr   )r    r'   r   r&   r   optional_argsL   s    r(   zhttps://www.google.comc              	     sF   ddl m dkrt d_t fdd}|S )a\  
    Label a test as requiring network connection and, if an error is
    encountered, only raise if it does not find a network connection.

    In comparison to ``network``, this assumes an added contract to your test:
    you must assert that, under normal conditions, your test will ONLY fail if
    it does not have network connectivity.

    You can call this in 3 ways: as a standard decorator, with keyword
    arguments, or with a positional argument that is the url to check.

    Parameters
    ----------
    t : callable
        The test requiring network connectivity.
    url : path
        The url to test via ``pandas.io.common.urlopen`` to check
        for connectivity. Defaults to 'https://www.google.com'.
    raise_on_error : bool
        If True, never catches errors.
    check_before_test : bool
        If True, checks connectivity before running the test case.
    error_classes : tuple or Exception
        error classes to ignore. If not in ``error_classes``, raises the error.
        defaults to IOError. Be careful about changing the error classes here.
    skip_errnos : iterable of int
        Any exception that has .errno or .reason.erno set to one
        of these values will be skipped with an appropriate
        message.
    _skip_on_messages: iterable of string
        any exception e for which one of the strings is
        a substring of str(e) will be skipped with an appropriate
        message. Intended to suppress errors where an errno isn't available.

    Notes
    -----
    * ``raise_on_error`` supersedes ``check_before_test``

    Returns
    -------
    t : callable
        The decorated test ``t``, with checks for connectivity errors.

    Example
    -------

    Tests decorated with @network will fail if it's possible to make a network
    connection to another URL (defaults to google.com)::

      >>> from pandas._testing import network
      >>> from pandas.io.common import urlopen
      >>> @network
      ... def test_network():
      ...     with urlopen("rabbit://bonanza.com"):
      ...         pass
      Traceback
         ...
      URLError: <urlopen error unknown url type: rabit>

      You can specify alternative URLs::

        >>> @network("https://www.yahoo.com")
        ... def test_something_with_yahoo():
        ...    raise IOError("Failure Message")
        >>> test_something_with_yahoo()
        Traceback (most recent call last):
            ...
        IOError: Failure Message

    If you set check_before_test, it will check the url first and not run the
    test on failure::

        >>> @network("failing://url.blaher", check_before_test=True)
        ... def test_something():
        ...     print("I ran!")
        ...     raise ValueError("Failure")
        >>> test_something()
        Traceback (most recent call last):
            ...

    Errors not related to networking will always be raised.
    r   )skipNTc               
     s   rst s  z| |W S  tk
r } zt|dd }|s^t|dr^t|jdd }|krtd|  t| t fddD rd|  t|s st r nd|  W 5 d }~X Y nX d S )Nerrnoreasonz+Skipping test due to known errno and error c                 3  s   | ]}|     kV  qd S r   )lower).0mZe_strr   r   	<genexpr>   s     z+network.<locals>.wrapper.<locals>.<genexpr>z;Skipping test because exception message is known and error z4Skipping test due to lack of connectivity and error )can_connect	Exceptiongetattrhasattrr+   strany
isinstance)r   r!   errr*   _skip_on_messagescheck_before_testerror_classesraise_on_errorr)   skip_errnosturlr/   r   r'      s2    
znetwork.<locals>.wrapper)pytestr)   r   networkr   )r?   r@   r=   r;   r<   r>   r:   r'   r   r9   r   rB   h   s    \!rB   c              	   C  sF   |dkrt  }zt|  W 5 Q R X W n |k
r<   Y dS X dS dS )a@  
    Try to connect to the given url. True if succeeds, False if IOError
    raised

    Parameters
    ----------
    url : basestring
        The URL to try to connect to

    Returns
    -------
    connectable : bool
        Return True if no IOError (unable to connect) or URLError (bad url) was
        raised
    NFT)r   r   )r@   r<   r   r   r   r1      s    
r1   r   zFilePathOrBuffer | Noner   )objpathreturnc              
   C  sR   |}|dkrdt d d}t|$}t| | t|W  5 Q R  S Q R X dS )a  
    Pickle an object and then read it again.

    Parameters
    ----------
    obj : any object
        The object to pickle and then re-read.
    path : str, path object or file-like object, default None
        The path where the pickled object is written and then read.

    Returns
    -------
    pandas object
        The original object that was pickled and then re-read.
    N__
   z	__.pickle)r   r   pdZ	to_pickleZread_pickle)rC   rD   _pathZ	temp_pathr   r   r   round_trip_pickle  s    
rJ   z
str | None)rD   c              	   C  sP   ddl }|dj}|dkr d}t|}| || |||}W 5 Q R X |S )a  
    Write an object to file specified by a pathlib.Path and read it back

    Parameters
    ----------
    writer : callable bound to pandas object
        IO writing function (e.g. DataFrame.to_csv )
    reader : callable
        IO reading function (e.g. pd.read_csv )
    path : str, default None
        The path where the object is written and then read.

    Returns
    -------
    pandas object
        The original object that was serialized and then re-read.
    r   NpathlibZ___pathlib___)rA   importorskipPathr   )writerreaderrD   rA   rM   rC   r   r   r   round_trip_pathlib+  s    
rP   c              	   C  sP   ddl }|dj}|dkr d}t|}| || |||}W 5 Q R X |S )a  
    Write an object to file specified by a py.path LocalPath and read it back.

    Parameters
    ----------
    writer : callable bound to pandas object
        IO writing function (e.g. DataFrame.to_csv )
    reader : callable
        IO reading function (e.g. pd.read_csv )
    path : str, default None
        The path where the object is written and then read.

    Returns
    -------
    pandas object
        The original object that was serialized and then re-read.
    r   Nzpy.pathZ___localpath___)rA   rL   localr   )rN   rO   rD   rA   Z	LocalPathrC   r   r   r   round_trip_localpathH  s    
rR   testc           	   	   C  s   |f}d}d}| dkr.t j}d}||f}d}n@| dkr>tj}n0| dkrNtj}n | dkr`tt}ntd	|  |||d
}t	|||  W 5 Q R X dS )a  
    Write data to a compressed file.

    Parameters
    ----------
    compression : {'gzip', 'bz2', 'zip', 'xz'}
        The compression type to use.
    path : str
        The file path to write the data.
    data : str
        The data to write.
    dest : str, default "test"
        The destination file (for ZIP only)

    Raises
    ------
    ValueError : An invalid compression value was passed in.
    wbwritezipwwritestrgzipbz2xzzUnrecognized compression type: )modeN)
zipfileZipFilerY   GzipFilerZ   BZ2Filer	   lzma
ValueErrorr3   )	compressionrD   datadestr   r\   methodZcompress_methodr   r   r   r   write_to_compressede  s"    
rg   c                 C  s:   ddl m}m} | d kr.| D ]} ||  qn||  d S )Nr   )closeget_fignums)Zmatplotlib.pyplotrh   ri   )Zfignum_closeri   r   r   r   rh     s
    
rh   )N)N)N)N)rS   )N)&
__future__r   rZ   	functoolsr   rY   typingr   r   r]   Zpandas._typingr   r   Zpandas.compatr	   r
   ZpandasrH   Zpandas._testing._randomr   Zpandas._testing.contextsr   Zpandas.io.commonr   Z_RAISE_NETWORK_ERROR_DEFAULTra   Z_network_error_messagesZ_network_errno_valsr   r(   rB   Zwith_connectivity_checkr1   rJ   rP   rR   rg   rh   r   r   r   r   <module>   sB    
 
.