
    gC                     *   d dl 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 g dZ G d de      Z G d	 d
e      Z G d de      Z G d de      Z G d de      Z G d de      Z G d de      Zy)    N)genioloop)Future"future_set_result_unless_cancelled)UnionOptionalTypeAny	Awaitable)DequeSet)	ConditionEvent	SemaphoreBoundedSemaphoreLockc                        e Zd ZdZddZddZy)_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....')
    Nc                 D    t        j                         | _        d| _        y )Nr   )collectionsdeque_waiters	_timeoutsselfs    B/var/www/openai/venv/lib/python3.12/site-packages/tornado/locks.py__init__z!_TimeoutGarbageCollector.__init__)   s    #))+    c                     | xj                   dz  c_         | j                   dkD  r3d| _         t        j                  d | j                  D              | _        y y )N   d   r   c              3   B   K   | ]  }|j                         r|  y wN)done).0ws     r   	<genexpr>z<_TimeoutGarbageCollector._garbage_collect.<locals>.<genexpr>2   s     -WAaffhas   )r   r   r   r   r   s    r   _garbage_collectz)_TimeoutGarbageCollector._garbage_collect-   sD    !>>CDN'---W-WWDM  r   returnN)__name__
__module____qualname____doc__r   r(    r   r   r   r      s    Xr   r   c                   t    e Zd ZdZdefdZ	 d
deeee	j                  f      dee   fdZddeddfdZdd	Zy)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::

        import asyncio
        from tornado import gen
        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()])

        asyncio.run(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`.
    r*   c                     d| j                   j                  }| j                  r|dt        | j                        z  z  }|dz   S )N<z waiters[%s]>)	__class__r+   r   len)r   results     r   __repr__zCondition.__repr__q   s=    ..113==ns4=='999F|r   Ntimeoutc                      t                j                  j                         |rLd fd}t        j                  j                         j                  ||      j                  fd       S )zWait for `.notify`.

        Returns a `.Future` that resolves ``True`` if the condition is notified,
        or ``False`` after a timeout.
        c                  ^    j                         st        d        j                          y NF)r$   r   r(   r   waiters   r   
on_timeoutz"Condition.wait.<locals>.on_timeout   s"    {{}6vuE%%'r   c                 &    j                        S r#   remove_timeout_io_looptimeout_handles    r   <lambda>z Condition.wait.<locals>.<lambda>   s    w/E/En/Ur   r)   )r   r   appendr   IOLoopcurrentadd_timeoutadd_done_callbackr   r8   r>   rD   rE   r=   s   `  @@@r   waitzCondition.waitw   s`     V$(
 mm++-G$00*EN$$%UVr   nc                     g }|r[| j                   rO| j                   j                         }|j                         s|dz  }|j                  |       |r| j                   rO|D ]  }t	        |d        y)zWake ``n`` waiters.r    TN)r   popleftr$   rG   r   )r   rN   waitersr=   s       r   notifyzCondition.notify   sa    DMM]]**,F;;=Qv&	 DMM F.vt< r   c                 L    | j                  t        | j                               y)zWake all waiters.N)rR   r5   r   r   s    r   
notify_allzCondition.notify_all   s    C&'r   r#   r    r)   )r+   r,   r-   r.   strr7   r   r   floatdatetime	timedeltar   boolrM   intrR   rT   r/   r   r   r   r   5   sa    9v#  EIeX-?-?&? @A	4,
= 
=D 
=(r   r   c                   ~    e Zd ZdZddZdefdZdefdZddZ	ddZ
	 dd	eeeej                  f      ded   fd
Zy)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::

        import asyncio
        from tornado import gen
        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()])

        asyncio.run(runner())

    .. testoutput::

        Waiting for event
        About to set the event
        Not waiting this time
        Done
    r*   Nc                 0    d| _         t               | _        y r;   )_valuesetr   r   s    r   r   zEvent.__init__   s    r   c                 f    d| j                   j                  d| j                         rddS ddS )Nr2    r_   clearr3   )r4   r+   is_setr   s    r   r7   zEvent.__repr__   s7    NN##[[]E/
 	
(//
 	
r   c                     | j                   S )z-Return ``True`` if the internal flag is true.r^   r   s    r   rc   zEvent.is_set   s    {{r   c                     | j                   s;d| _         | j                  D ]$  }|j                         r|j                  d       & yy)zSet the internal flag to ``True``. All waiters are awakened.

        Calling `.wait` once the flag is set will not block.
        TN)r^   r   r$   
set_result)r   futs     r   r_   z	Event.set   s:    
 {{DK}}xxzNN4( % r   c                     d| _         y)zkReset the internal flag to ``False``.

        Calls to `.wait` will block until `.set` is called.
        FNre   r   s    r   rb   zEvent.clear   s    
 r   r8   c                     t                j                  rj                  d       S  j                  j	                         j                   fd       |S t        j                  |      }|j                  fd       |S )zBlock until the internal flag is true.

        Returns an awaitable, which raises `tornado.util.TimeoutError` after a
        timeout.
        Nc                 :    j                   j                  |       S r#   )r   remove)rh   r   s    r   rF   zEvent.wait.<locals>.<lambda>   s    $--*>*>s*Cr   c                 H    j                         sj                         S d S r#   )r$   cancel)tfrh   s    r   rF   zEvent.wait.<locals>.<lambda>   s    sxxz3::<CtCr   )r   r^   rg   r   addrK   r   with_timeout)r   r8   timeout_futrh   s   `  @r   rM   z
Event.wait   s|     h;;NN4 J#CD?J**7C8K ))C r   r)   r#   )r+   r,   r-   r.   r   rV   r7   rZ   rc   r_   rb   r   r   rW   rX   rY   r   rM   r/   r   r   r   r      sd    %N
# 
 
) EIeX-?-?&? @A	4r   r   c                   `    e Zd ZdZdeddfdZddZddd	ee   d
ee	j                     ddfdZy)_ReleasingContextManagerzReleases a Lock or Semaphore at the end of a "with" statement.

    with (yield semaphore.acquire()):
        pass

    # Now semaphore.release() has been called.
    objr*   Nc                     || _         y r#   )_obj)r   ru   s     r   r   z!_ReleasingContextManager.__init__  s	    	r   c                      y r#   r/   r   s    r   	__enter__z"_ReleasingContextManager.__enter__  s    r   exc_typeOptional[Type[BaseException]]exc_valexc_tbc                 8    | j                   j                          y r#   )rw   release)r   rz   r|   r}   s       r   __exit__z!_ReleasingContextManager.__exit__  s     			r   r)   )r+   r,   r-   r.   r
   r   ry   r   BaseExceptiontypesTracebackTyper   r/   r   r   rt   rt     sZ    C D 1 -( ,,-	
 
r   rt   c                       e Zd ZdZddeddf fdZdef fdZddZ	 dde	e
eej                  f      dee   fd	Zdd
Zddde	e   de	ej(                     ddfdZddZddde	e   de	ej(                     ddfdZ xZS )r   a  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

       inited = False

       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)

       def use_some_resource():
           global inited
           global futures_q
           if not inited:
               inited = True
               # Ensure reliable doctest output: resolve Futures one at a time.
               futures_q = deque([Future() for _ in range(3)])
               IOLoop.current().add_callback(simulator, list(futures_q))

           return futures_q.popleft()

    .. testcode:: semaphore

        import asyncio
        from tornado import gen
        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)])

        asyncio.run(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.

    valuer*   Nc                 P    t         |           |dk  rt        d      || _        y )Nr   z$semaphore initial value must be >= 0)superr   
ValueErrorr^   r   r   r4   s     r   r   zSemaphore.__init__  s(    19CDDr   c                    t         |          }| j                  dk(  rdndj                  | j                        }| j                  r%dj                  |t        | j                              }dj                  |dd |      S )Nr   lockedzunlocked,value:{0}z{0},waiters:{1}z<{0} [{1}]>r    )r   r7   r^   formatr   r5   )r   resextrar4   s      r   r7   zSemaphore.__repr__  sr    g q(H.B.I.I$++.V 	 ==%,,UC4FGE##C"Iu55r   c                    | xj                   dz  c_         | j                  rh| j                  j                         }|j                         s0| xj                   dz  c_         |j	                  t        |              y| j                  rgyy)*Increment the counter and wake one waiter.r    N)r^   r   rP   r$   rg   rt   r<   s     r   r   zSemaphore.release  sb    qmm]]**,F;;=q  !!":4"@A mmr   r8   c                 t    t                j                  dkD  r1 xj                  dz  c_        j                  t                      S  j                  j                         |rLd fd}t        j                  j                         j                  ||      j                  f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    c                      j                         s#j                  t        j                                 j	                          y r#   )r$   set_exceptionr   TimeoutErrorr(   r<   s   r   r>   z%Semaphore.acquire.<locals>.on_timeout  s/    !;;=,,S-=-=-?@))+r   c                 &    j                        S r#   r@   rB   s    r   rF   z#Semaphore.acquire.<locals>.<lambda>  s    g44^Dr   r)   )r   r^   rg   rt   r   rG   r   rH   rI   rJ   rK   rL   s   `  @@@r   acquirezSemaphore.acquire  s     ;;?KK1K6t<=  MM  (,
 !--//1!(!4!4Wj!I((D r   c                     t        d      )Nz0Use 'async with' instead of 'with' for SemaphoreRuntimeErrorr   s    r   ry   zSemaphore.__enter__  s    MNNr   typr{   	tracebackc                 $    | j                          y r#   ry   )r   r   r   r   s       r   r   zSemaphore.__exit__       	r   c                 @   K   | j                          d {    y 7 wr#   r   r   s    r   
__aenter__zSemaphore.__aenter__       lln   tbc                 ,   K   | j                          y wr#   r   r   r   r   r   s       r   	__aexit__zSemaphore.__aexit__        	   rU   r)   r#   )r+   r,   r-   r.   r[   r   rV   r7   r   r   r   rW   rX   rY   r   rt   r   ry   r   r   r   r   r   r   __classcell__r4   s   @r   r   r     s    bHc $ 6# 6$ EIeX-?-?&? @A	+	,8O, & E//0	
 
, & U(()	
 
r   r   c                   :     e Zd ZdZddeddf fdZd fdZ x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   r*   Nc                 4    t         |   |       || _        y )Nr   )r   r   _initial_valuer   s     r   r   zBoundedSemaphore.__init__  s    u%#r   c                 j    | j                   | j                  k\  rt        d      t        |           y)r   z!Semaphore released too many timesN)r^   r   r   r   r   )r   r4   s    r   r   zBoundedSemaphore.release  s+    ;;$---@AAr   rU   r)   )r+   r,   r-   r.   r[   r   r   r   r   s   @r   r   r     s%    $c $$ $ r   r   c                       e Zd ZdZddZdefdZ	 ddeee	e
j                  f      dee   fdZddZdd	Zd
ddee   deej&                     ddfdZddZd
ddee   deej&                     ddfdZy)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.

    r*   Nc                 &    t        d      | _        y )Nr    r   )r   _blockr   s    r   r   zLock.__init__  s    &Q/r   c                 P    d| j                   j                  d| j                  dS )Nr2   z _block=r3   )r4   r+   r   r   s    r   r7   zLock.__repr__  s    #'>>#:#:DKKHHr   r8   c                 8    | j                   j                  |      S )zAttempt to lock. Returns an awaitable.

        Returns an awaitable, which raises `tornado.util.TimeoutError` after a
        timeout.
        )r   r   )r   r8   s     r   r   zLock.acquire  s     {{""7++r   c                 j    	 | j                   j                          y# t        $ r t        d      w xY w)zUnlock.

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

        If not locked, raise a `RuntimeError`.
        zrelease unlocked lockN)r   r   r   r   r   s    r   r   zLock.release  s2    	8KK! 	8677	8s    2c                     t        d      )Nz+Use `async with` instead of `with` for Lockr   r   s    r   ry   zLock.__enter__(  s    HIIr   r   r{   r   r   c                 $    | j                          y r#   r   r   s       r   r   zLock.__exit__+  r   r   c                 @   K   | j                          d {    y 7 wr#   r   r   s    r   r   zLock.__aenter__3  r   r   c                 ,   K   | j                          y wr#   r   r   s       r   r   zLock.__aexit__6  r   r   r)   r#   )r+   r,   r-   r.   r   rV   r7   r   r   rW   rX   rY   r   rt   r   r   ry   r   r   r   r   r   r   r/   r   r   r   r     s    "H0I# I EI,eX-?-?&? @A,	+	,,
8J, & U(()	
 
, & U(()	
 
r   r   )r   rX   r   tornador   r   tornado.concurrentr   r   typingr   r   r	   r
   r   TYPE_CHECKINGr   r   __all__objectr   r   r   rt   r   r   r   r/   r   r   <module>r      s        I 8 8 	!
IXv X,f(( f(RaF aHv 0v( vry (U6 Ur   