B
    H/\1                 @   s   d Z ddlmZmZmZ ddlmZ ddlmZ ddl	m
Z
 ddlmZ ddgZG d	d
 d
eZe ZG dd deZdd ZdS )a  
Timeouts.

Many functions in :mod:`gevent` have a *timeout* argument that allows
limiting the time the function will block. When that is not available,
the :class:`Timeout` class and :func:`with_timeout` function in this
module add timeouts to arbitrary code.

.. warning::

    Timeouts can only work when the greenlet switches to the hub.
    If a blocking function is called or an intense calculation is ongoing during
    which no switches occur, :class:`Timeout` is powerless.
    )absolute_importprint_functiondivision)string_types)_NONE)
getcurrent)get_hub_noargsTimeoutwith_timeoutc               @   s`   e Zd ZdZedd ZeZedd Ze ZZ	dd Z
dd	 ZeZe ZZd
d Zdd ZdS )
_FakeTimer c             C   s   dS )NFr   )selfr   r   -lib/python3.7/site-packages/gevent/timeout.pypending(   s    z_FakeTimer.pendingc             C   s   dS )zAlways returns NoneNr   )r   r   r   r   seconds.   s    z_FakeTimer.secondsc             O   s   t dd S )Nz$non-expiring timer cannot be started)AssertionError)r   argskwargsr   r   r   start4   s    z_FakeTimer.startc             C   s   d S )Nr   )r   r   r   r   stop8   s    z_FakeTimer.stopc             C   s   | S )Nr   )r   r   r   r   	__enter__?   s    z_FakeTimer.__enter__c             C   s   d S )Nr   )r   Z_tZ_vZ_tbr   r   r   __exit__B   s    z_FakeTimer.__exit__N)__name__
__module____qualname__	__slots__propertyr   activer   timer	exceptionr   r   cancelcloser   r   r   r   r   r   r      s   r   c               @   sz   e Zd ZdZdddZdd	 Zedd
dZedddZ	e
dd Zdd Zdd Zdd Zdd Zdd Zdd ZdS )r	   aS  
    Timeout(seconds=None, exception=None, ref=True, priority=-1)

    Raise *exception* in the current greenlet after *seconds*
    have elapsed::

        timeout = Timeout(seconds, exception)
        timeout.start()
        try:
            ...  # exception will be raised here, after *seconds* passed since start() call
        finally:
            timeout.close()

    .. note::

        If the code that the timeout was protecting finishes
        executing before the timeout elapses, be sure to ``close`` the
        timeout so it is not unexpectedly raised in the future. Even if it
        is raised, it is a best practice to close it. This ``try/finally``
        construct or a ``with`` statement is a recommended pattern. (If
        the timeout object will be started again, use ``cancel`` instead
        of ``close``; this is rare.)

    When *exception* is omitted or ``None``, the ``Timeout`` instance
    itself is raised::

        >>> import gevent
        >>> gevent.Timeout(0.1).start()
        >>> gevent.sleep(0.2)  #doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
         ...
        Timeout: 0.1 seconds

    If the *seconds* argument is not given or is ``None`` (e.g.,
    ``Timeout()``), then the timeout will never expire and never raise
    *exception*. This is convenient for creating functions which take
    an optional timeout parameter of their own. (Note that this is **not**
    the same thing as a *seconds* value of ``0``.)

    ::

       def function(args, timeout=None):
          "A function with an optional timeout."
          timer = Timeout(timeout)
          with timer:
             ...

    .. caution::

        A *seconds* value less than ``0.0`` (e.g., ``-1``) is poorly defined. In the future,
        support for negative values is likely to do the same thing as a value
        of ``None`` or ``0``

    A *seconds* value of ``0`` requests that the event loop spin and poll for I/O;
    it will immediately expire as soon as control returns to the event loop.

    .. rubric:: Use As A Context Manager

    To simplify starting and canceling timeouts, the ``with``
    statement can be used::

        with gevent.Timeout(seconds, exception) as timeout:
            pass  # ... code block ...

    This is equivalent to the try/finally block above with one
    additional feature: if *exception* is the literal ``False``, the
    timeout is still raised, but the context manager suppresses it, so
    the code outside the with-block won't see it.

    This is handy for adding a timeout to the functions that don't
    support a *timeout* parameter themselves::

        data = None
        with gevent.Timeout(5, False):
            data = mysock.makefile().readline()
        if data is None:
            ...  # 5 seconds passed without reading a line
        else:
            ...  # a line was read within 5 seconds

    .. caution::

        If ``readline()`` above catches and doesn't re-raise
        :exc:`BaseException` (for example, with a bare ``except:``), then
        your timeout will fail to function and control won't be returned
        to you when you expect.

    .. rubric:: Catching Timeouts

    When catching timeouts, keep in mind that the one you catch may
    not be the one you have set (a calling function may have set its
    own timeout); if you going to silence a timeout, always check that
    it's the instance you need::

        timeout = Timeout(1)
        timeout.start()
        try:
            ...
        except Timeout as t:
            if t is not timeout:
                raise # not my timeout
        finally:
            timeout.close()


    .. versionchanged:: 1.1b2

        If *seconds* is not given or is ``None``, no longer allocate a
        native timer object that will never be started.

    .. versionchanged:: 1.1

        Add warning about negative *seconds* values.

    .. versionchanged:: 1.3a1

        Timeout objects now have a :meth:`close`
        method that must be called when the timeout will no longer be
        used to properly clean up native resources.
        The ``with`` statement does this automatically.

    NTFc             C   sJ   t |  || _|| _|| _|d kr,t| _nt jj|p:d||d| _d S )Ng        )refpriority)	BaseException__init__r   r   	_one_shotr   r   get_hubZloop)r   r   r   r#   r$   r'   r   r   r   r&      s    
zTimeout.__init__c             C   sf   | j rtd|  | jdkr dS | jdks@| jdks@t| jtrF| }n| j}| jjt j	|dd dS )zSchedule the timeout.z5%r is already started; to restart it, cancel it firstNFT)update)
r   r   r   r   
isinstancer   r   r   r   throw)r   Zthrowsr   r   r   r      s    
 zTimeout.startc             C   s8   t |tr|js|  |S | ||||d}|  |S )a  Create a started :class:`Timeout`.

        This is a shortcut, the exact action depends on *timeout*'s type:

        * If *timeout* is a :class:`Timeout`, then call its :meth:`start` method
          if it's not already begun.
        * Otherwise, create a new :class:`Timeout` instance, passing (*timeout*, *exception*) as
          arguments, then call its :meth:`start` method.

        Returns the :class:`Timeout` instance.
        )r#   r'   )r*   r	   r   r   )clstimeoutr   r#   r'   r   r   r   	start_new   s    
zTimeout.start_newc             C   s   | d krt S tj| ||ddS )NT)r'   )r   r	   r.   )r-   r   r#   r   r   r   _start_new_or_dummy  s    zTimeout._start_new_or_dummyc             C   s   | j jp| j jS )z.True if the timeout is scheduled to be raised.)r   r   r   )r   r   r   r   r     s    zTimeout.pendingc             C   s   | j   | jr|   dS )z
        If the timeout is pending, cancel it. Otherwise, do nothing.

        The timeout object can be :meth:`started <start>` again. If
        you will not start the timeout again, you should use
        :meth:`close` instead.
        N)r   r   r'   r!   )r   r   r   r   r      s    
zTimeout.cancelc             C   s   | j   | j   t| _ dS )z
        Close the timeout and free resources. The timer cannot be started again
        after this method has been used.
        N)r   r   r!   r   )r   r   r   r   r!   &  s    

zTimeout.closec             C   sP   t | j}| jrd}nd}| jd kr*d}n
d| j }d|tt| | j||f S )Nz pending z exception=%rz<%s at %s seconds=%s%s%s>)typer   r   r   hexidr   )r   Z	classnamer   r   r   r   r   __repr__/  s    


zTimeout.__repr__c             C   sb   | j dkrdS | j dkrdnd}| jdkr8d| j |f S | jdkrPd| j |f S d| j || jf S )	z
        >>> raise Timeout #doctest: +IGNORE_EXCEPTION_DETAIL
        Traceback (most recent call last):
            ...
        Timeout
        Nr0      sz%s second%sFz%s second%s (silent)z%s second%s: %s)r   r   )r   suffixr   r   r   __str__;  s    


zTimeout.__str__c             C   s   | j s|   | S )z^
        Start and return the timer. If the timer is already started, just return it.
        )r   r   )r   r   r   r   r   M  s    zTimeout.__enter__c             C   s"   |    || kr| jdkrdS dS )z
        Stop the timer.

        .. versionchanged:: 1.3a1
           The underlying native timer is also stopped. This object cannot be
           used again.
        FTN)r!   r   )r   typvaluetbr   r   r   r   U  s    zTimeout.__exit__)NNTr"   F)NNTF)NT)r   r   r   __doc__r&   r   classmethodr.   staticmethodr/   r   r   r    r!   r4   r8   r   r   r   r   r   r   r	   H   s   z 
	c          
   O   sr   | dt}tj| dd}zHy
|||S  tk
r^ } z||krL|tk	rL|S  W dd}~X Y nX W d|  X dS )aZ  Wrap a call to *function* with a timeout; if the called
    function fails to return before the timeout, cancel it and return a
    flag value, provided by *timeout_value* keyword argument.

    If timeout expires but *timeout_value* is not provided, raise :class:`Timeout`.

    Keyword argument *timeout_value* is not passed to *function*.
    timeout_valueT)r'   N)popr   r	   r.   r    )r   Zfunctionr   kwdsr?   r-   exr   r   r   r
   b  s    	
N)r<   Z
__future__r   r   r   Zgevent._compatr   Zgevent._utilr   Zgreenletr   Zgevent._hub_localr   r(   __all__objectr   r%   r	   r
   r   r   r   r   <module>   s   '  