B
    hD                 @   s   d dl Z d dlmZ d dlZd dlZd dlmZmZ d dlm	Z	m
Z
 d dlmZmZmZmZmZ d dlZejr~d dlmZmZ ddd	d
dgZG dd deZG dd deZG dd deZG dd deZG dd	 d	eZG dd
 d
eZG dd deZdS )    N)CancelledError)genioloop)Future"future_set_result_unless_cancelled)UnionOptionalTypeAny	Awaitable)DequeSet	ConditionEvent	SemaphoreBoundedSemaphoreLockc               @   s,   e Zd ZdZddddZddddZdS )_TimeoutGarbageCollectorzBase class for objects that periodically clean up timed-out waiters.

    Avoids memory leak in a common pattern like:

        while True:
            yield condition.wait(short_timeout)
            print('looping....')
    N)returnc             C   s   t  | _d| _d S )Nr   )collectionsdeque_waiters	_timeouts)self r   JC:\Users\sanjo\AppData\Local\Qlobot\Launcher\ext_packages\tornado\locks.py__init__*   s    
z!_TimeoutGarbageCollector.__init__c             C   s:   |  j d7  _ | j dkr6d| _ tdd | jD | _d S )N   d   r   c             s   s   | ]}|  s|V  qd S )N)done).0wr   r   r   	<genexpr>3   s    z<_TimeoutGarbageCollector._garbage_collect.<locals>.<genexpr>)r   r   r   r   )r   r   r   r   _garbage_collect.   s    
z)_TimeoutGarbageCollector._garbage_collect)__name__
__module____qualname____doc__r   r#   r   r   r   r   r       s   r   c                   st   e Zd ZdZdd fddZedddZdeee	j
f ee dd	d
ZdeddddZddddZ  ZS )r   a  A condition allows one or more coroutines to wait until notified.

    Like a standard `threading.Condition`, but does not need an underlying lock
    that is acquired and released.

    With a `Condition`, coroutines can wait to be notified by other coroutines:

    .. testcode::

        from tornado import gen
        from tornado.ioloop import IOLoop
        from tornado.locks import Condition

        condition = Condition()

        async def waiter():
            print("I'll wait right here")
            await condition.wait()
            print("I'm done waiting")

        async def notifier():
            print("About to notify")
            condition.notify()
            print("Done notifying")

        async def runner():
            # Wait for waiter() and notifier() in parallel
            await gen.multi([waiter(), notifier()])

        IOLoop.current().run_sync(runner)

    .. testoutput::

        I'll wait right here
        About to notify
        Done notifying
        I'm done waiting

    `wait` takes an optional ``timeout`` argument, which is either an absolute
    timestamp::

        io_loop = IOLoop.current()

        # Wait up to 1 second for a notification.
        await condition.wait(timeout=io_loop.time() + 1)

    ...or a `datetime.timedelta` for a timeout relative to the current time::

        # Wait up to 1 second.
        await condition.wait(timeout=datetime.timedelta(seconds=1))

    The method returns False if there's no notification before the deadline.

    .. versionchanged:: 5.0
       Previously, waiters could be notified synchronously from within
       `notify`. Now, the notification will always be received on the
       next iteration of the `.IOLoop`.
    N)r   c                s   t t|   tj | _d S )N)superr   r   r   IOLoopcurrentio_loop)r   )	__class__r   r   r   r   s    zCondition.__init__c             C   s.   d| j jf }| jr&|dt| j 7 }|d S )Nz<%sz waiters[%s]>)r,   r$   r   len)r   resultr   r   r   __repr__v   s    zCondition.__repr__)timeoutr   c                sX   t  j |rTddfdd}tj   || fdd S )zWait for `.notify`.

        Returns a `.Future` that resolves ``True`` if the condition is notified,
        or ``False`` after a timeout.
        N)r   c                  s     std    d S )NF)r   r   r#   r   )r   waiterr   r   
on_timeout   s    
z"Condition.wait.<locals>.on_timeoutc                s
     S )N)remove_timeout)_)r+   timeout_handler   r   <lambda>       z Condition.wait.<locals>.<lambda>)r   r   appendr   r)   r*   add_timeoutadd_done_callback)r   r1   r3   r   )r+   r   r6   r2   r   wait|   s    
zCondition.waitr   )nr   c             C   sT   g }x2|r6| j r6| j  }| s|d8 }|| qW x|D ]}t|d q>W dS )zWake ``n`` waiters.r   TN)r   popleftr   r9   r   )r   r=   waitersr2   r   r   r   notify   s    

zCondition.notifyc             C   s   |  t| j dS )zWake all waiters.N)r@   r.   r   )r   r   r   r   
notify_all   s    zCondition.notify_all)N)r   )r$   r%   r&   r'   r   strr0   r   floatdatetime	timedeltar   boolr<   intr@   rA   __classcell__r   r   )r,   r   r   6   s   : c               @   sv   e Zd ZdZddddZedddZeddd	Zddd
dZ	ddddZ
deeejf ed dddZdS )r   a  An event blocks coroutines until its internal flag is set to True.

    Similar to `threading.Event`.

    A coroutine can wait for an event to be set. Once it is set, calls to
    ``yield event.wait()`` will not block unless the event has been cleared:

    .. testcode::

        from tornado import gen
        from tornado.ioloop import IOLoop
        from tornado.locks import Event

        event = Event()

        async def waiter():
            print("Waiting for event")
            await event.wait()
            print("Not waiting this time")
            await event.wait()
            print("Done")

        async def setter():
            print("About to set the event")
            event.set()

        async def runner():
            await gen.multi([waiter(), setter()])

        IOLoop.current().run_sync(runner)

    .. testoutput::

        Waiting for event
        About to set the event
        Not waiting this time
        Done
    N)r   c             C   s   d| _ t | _d S )NF)_valuesetr   )r   r   r   r   r      s    zEvent.__init__c             C   s   d| j j|  rdndf S )Nz<%s %s>rJ   clear)r,   r$   is_set)r   r   r   r   r0      s    zEvent.__repr__c             C   s   | j S )z-Return ``True`` if the internal flag is true.)rI   )r   r   r   r   rL      s    zEvent.is_setc             C   s2   | j s.d| _ x | jD ]}| s|d qW dS )zSet the internal flag to ``True``. All waiters are awakened.

        Calling `.wait` once the flag is set will not block.
        TN)rI   r   r   
set_result)r   futr   r   r   rJ      s
    z	Event.setc             C   s
   d| _ dS )zkReset the internal flag to ``False``.

        Calls to `.wait` will block until `.set` is called.
        FN)rI   )r   r   r   r   rK      s    zEvent.clear)r1   r   c                sp   t   jr d  S j   fdd |dkrD S tj| tfd}| fdd |S dS )zBlock until the internal flag is true.

        Returns an awaitable, which raises `tornado.util.TimeoutError` after a
        timeout.
        Nc                s    j | S )N)r   remove)rN   )r   r   r   r7      r8   zEvent.wait.<locals>.<lambda>)quiet_exceptionsc                s      s  S d S )N)r   cancel)tf)rN   r   r   r7      r8   )	r   rI   rM   r   addr;   r   with_timeoutr   )r   r1   Ztimeout_futr   )rN   r   r   r<      s    
z
Event.wait)N)r$   r%   r&   r'   r   rB   r0   rF   rL   rJ   rK   r   rC   rD   rE   r   r<   r   r   r   r   r      s   &c               @   sL   e Zd ZdZeddddZddddZd	ee ee	j
 dd
ddZdS )_ReleasingContextManagerzReleases a Lock or Semaphore at the end of a "with" statement.

        with (yield semaphore.acquire()):
            pass

        # Now semaphore.release() has been called.
    N)objr   c             C   s
   || _ d S )N)_obj)r   rV   r   r   r   r     s    z!_ReleasingContextManager.__init__)r   c             C   s   d S )Nr   )r   r   r   r   	__enter__  s    z"_ReleasingContextManager.__enter__zOptional[Type[BaseException]])exc_typeexc_valexc_tbr   c             C   s   | j   d S )N)rW   release)r   rY   rZ   r[   r   r   r   __exit__  s    z!_ReleasingContextManager.__exit__)r$   r%   r&   r'   r
   r   rX   r   BaseExceptiontypesTracebackTyper]   r   r   r   r   rU     s   rU   c                   s   e Zd ZdZdedd fddZed fdd	Zddd
dZde	e
ejf ee dddZddddZdee eej ddddZddddZdee eej ddddZ  ZS )r   aS  A lock that can be acquired a fixed number of times before blocking.

    A Semaphore manages a counter representing the number of `.release` calls
    minus the number of `.acquire` calls, plus an initial value. The `.acquire`
    method blocks if necessary until it can return without making the counter
    negative.

    Semaphores limit access to a shared resource. To allow access for two
    workers at a time:

    .. testsetup:: semaphore

       from collections import deque

       from tornado import gen
       from tornado.ioloop import IOLoop
       from tornado.concurrent import Future

       # Ensure reliable doctest output: resolve Futures one at a time.
       futures_q = deque([Future() for _ in range(3)])

       async def simulator(futures):
           for f in futures:
               # simulate the asynchronous passage of time
               await gen.sleep(0)
               await gen.sleep(0)
               f.set_result(None)

       IOLoop.current().add_callback(simulator, list(futures_q))

       def use_some_resource():
           return futures_q.popleft()

    .. testcode:: semaphore

        from tornado import gen
        from tornado.ioloop import IOLoop
        from tornado.locks import Semaphore

        sem = Semaphore(2)

        async def worker(worker_id):
            await sem.acquire()
            try:
                print("Worker %d is working" % worker_id)
                await use_some_resource()
            finally:
                print("Worker %d is done" % worker_id)
                sem.release()

        async def runner():
            # Join all workers.
            await gen.multi([worker(i) for i in range(3)])

        IOLoop.current().run_sync(runner)

    .. testoutput:: semaphore

        Worker 0 is working
        Worker 1 is working
        Worker 0 is done
        Worker 2 is working
        Worker 1 is done
        Worker 2 is done

    Workers 0 and 1 are allowed to run concurrently, but worker 2 waits until
    the semaphore has been released once, by worker 0.

    The semaphore can be used as an async context manager::

        async def worker(worker_id):
            async with sem:
                print("Worker %d is working" % worker_id)
                await use_some_resource()

            # Now the semaphore has been released.
            print("Worker %d is done" % worker_id)

    For compatibility with older versions of Python, `.acquire` is a
    context manager, so ``worker`` could also be written as::

        @gen.coroutine
        def worker(worker_id):
            with (yield sem.acquire()):
                print("Worker %d is working" % worker_id)
                yield use_some_resource()

            # Now the semaphore has been released.
            print("Worker %d is done" % worker_id)

    .. versionchanged:: 4.3
       Added ``async with`` support in Python 3.5.

    r   N)valuer   c                s(   t t|   |dk rtd|| _d S )Nr   z$semaphore initial value must be >= 0)r(   r   r   
ValueErrorrI   )r   ra   )r,   r   r   r   }  s    zSemaphore.__init__)r   c                sT   t t|  }| jdkrdn
d| j}| jr@d|t| j}d|dd |S )Nr   lockedzunlocked,value:{0}z{0},waiters:{1}z<{0} [{1}]>r   )r(   r   r0   rI   formatr   r.   )r   resextra)r,   r   r   r0     s
    zSemaphore.__repr__c             C   sN   |  j d7  _ x:| jrH| j }| s|  j d8  _ |t|  P qW dS )z*Increment the counter and wake one waiter.r   N)rI   r   r>   r   rM   rU   )r   r2   r   r   r   r\     s    
zSemaphore.release)r1   r   c                s   t  jdkr. jd8  _t nNj |r|ddfdd}tj   	||
 fdd S )	zDecrement the counter. Returns an awaitable.

        Block if the counter is zero and wait for a `.release`. The awaitable
        raises `.TimeoutError` after the deadline.
        r   r   N)r   c                  s"     st     d S )N)r   set_exceptionr   TimeoutErrorr#   r   )r   r2   r   r   r3     s    z%Semaphore.acquire.<locals>.on_timeoutc                s
     S )N)r4   )r5   )r+   r6   r   r   r7     r8   z#Semaphore.acquire.<locals>.<lambda>)r   rI   rM   rU   r   r9   r   r)   r*   r:   r;   )r   r1   r3   r   )r+   r   r6   r2   r   acquire  s    

zSemaphore.acquirec             C   s   t dd S )Nz0Use 'async with' instead of 'with' for Semaphore)RuntimeError)r   r   r   r   rX     s    zSemaphore.__enter__zOptional[Type[BaseException]])typra   	tracebackr   c             C   s   |    d S )N)rX   )r   rl   ra   rm   r   r   r   r]     s    zSemaphore.__exit__c                s   |   I d H  d S )N)rj   )r   r   r   r   
__aenter__  s    zSemaphore.__aenter__)rl   ra   tbr   c                s   |    d S )N)r\   )r   rl   ra   ro   r   r   r   	__aexit__  s    zSemaphore.__aexit__)r   )N)r$   r%   r&   r'   rG   r   rB   r0   r\   r   rC   rD   rE   r   rU   rj   rX   r   r^   r_   r`   r]   rn   rp   rH   r   r   )r,   r   r     s    ^	c                   s<   e Zd ZdZd
edd fddZdd fdd	Z  ZS )r   a:  A semaphore that prevents release() being called too many times.

    If `.release` would increment the semaphore's value past the initial
    value, it raises `ValueError`. Semaphores are mostly used to guard
    resources with limited capacity, so a semaphore released too many times
    is a sign of a bug.
    r   N)ra   r   c                s   t t| j|d || _d S )N)ra   )r(   r   r   _initial_value)r   ra   )r,   r   r   r     s    zBoundedSemaphore.__init__)r   c                s&   | j | jkrtdtt|   dS )z*Increment the counter and wake one waiter.z!Semaphore released too many timesN)rI   rq   rb   r(   r   r\   )r   )r,   r   r   r\     s    zBoundedSemaphore.release)r   )r$   r%   r&   r'   rG   r   r\   rH   r   r   )r,   r   r     s   c               @   s   e Zd ZdZddddZedddZdeee	j
f ee dd	d
ZddddZddddZdee eej ddddZddddZdee eej ddddZdS )r   a  A lock for coroutines.

    A Lock begins unlocked, and `acquire` locks it immediately. While it is
    locked, a coroutine that yields `acquire` waits until another coroutine
    calls `release`.

    Releasing an unlocked lock raises `RuntimeError`.

    A Lock can be used as an async context manager with the ``async
    with`` statement:

    >>> from tornado import locks
    >>> lock = locks.Lock()
    >>>
    >>> async def f():
    ...    async with lock:
    ...        # Do something holding the lock.
    ...        pass
    ...
    ...    # Now the lock is released.

    For compatibility with older versions of Python, the `.acquire`
    method asynchronously returns a regular context manager:

    >>> async def f2():
    ...    with (yield lock.acquire()):
    ...        # Do something holding the lock.
    ...        pass
    ...
    ...    # Now the lock is released.

    .. versionchanged:: 4.3
       Added ``async with`` support in Python 3.5.

    N)r   c             C   s   t dd| _d S )Nr   )ra   )r   _block)r   r   r   r   r   
  s    zLock.__init__c             C   s   d| j j| jf S )Nz<%s _block=%s>)r,   r$   rr   )r   r   r   r   r0     s    zLock.__repr__)r1   r   c             C   s   | j |S )zAttempt to lock. Returns an awaitable.

        Returns an awaitable, which raises `tornado.util.TimeoutError` after a
        timeout.
        )rr   rj   )r   r1   r   r   r   rj     s    zLock.acquirec             C   s0   y| j   W n tk
r*   tdY nX dS )zUnlock.

        The first coroutine in line waiting for `acquire` gets the lock.

        If not locked, raise a `RuntimeError`.
        zrelease unlocked lockN)rr   r\   rb   rk   )r   r   r   r   r\     s    zLock.releasec             C   s   t dd S )Nz+Use `async with` instead of `with` for Lock)rk   )r   r   r   r   rX   &  s    zLock.__enter__zOptional[Type[BaseException]])rl   ra   ro   r   c             C   s   |    d S )N)rX   )r   rl   ra   ro   r   r   r   r]   )  s    zLock.__exit__c                s   |   I d H  d S )N)rj   )r   r   r   r   rn   1  s    zLock.__aenter__c                s   |    d S )N)r\   )r   rl   ra   ro   r   r   r   rp   4  s    zLock.__aexit__)N)r$   r%   r&   r'   r   rB   r0   r   rC   rD   rE   r   rU   rj   r\   rX   r   r^   r_   r`   r]   rn   rp   r   r   r   r   r     s    #)r   concurrent.futuresr   rD   r_   tornador   r   tornado.concurrentr   r   typingr   r   r	   r
   r   TYPE_CHECKINGr   r   __all__objectr   r   r   rU   r   r   r   r   r   r   r   <module>   s$   kd 5