
    ܲe=                       d dl mZ d dlZd dlZd dlmZmZmZ d dlm	Z	m
Z
mZmZ d dlmZmZ d dlmZ d dlmZ d dlmZmZmZmZmZmZmZmZ d	d
lmZ d	dlm Z m!Z!m"Z" d	dl#m$Z$ d	dl%m&Z&m'Z' d	dl(m)Z) d	dl*m+Z+ ej,        dk    r	d dlm-Z-m.Z. nd dl/m-Z-m.Z.  ed          Z0 edd          Z1 e-d          Z2d.dZ3d/dZ4 G d d ee1         e          Z5 G d! d"e+          Z6 G d# d$          Z7e	 d0d1d+            Z8d2d-Z9dS )3    )annotationsN)	AwaitableCallable	Generator)FIRST_COMPLETEDFutureThreadPoolExecutorwait)AbstractContextManagercontextmanager)isawaitable)TracebackType)AnyAsyncContextManagerContextManagerGenericIterableTypeVarcastoverload   )
_eventloop)get_async_backendget_cancelled_exc_classthreadlocals)Event)CancelScopecreate_task_group)AsyncBackend)
TaskStatus)      )TypeVarTupleUnpackT_RetvalT_coT)	covariantPosArgsTfunc1Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]]argsUnpack[PosArgsT]returnc                    	 t           j        }t           j        }n# t          $ r t	          d          dw xY w|                    | ||          S )z
    Call a coroutine function from a worker thread.

    :param func: a coroutine function
    :param args: positional arguments for the callable
    :return: the return value of the coroutine function

    9This function can only be run from an AnyIO worker threadNtoken)r   current_async_backendcurrent_tokenAttributeErrorRuntimeErrorrun_async_from_threadr)   r+   async_backendr1   s       1lib/python3.11/site-packages/anyio/from_thread.pyrunr:   &   si    $:*   G
 
	
 ..tT.GGG    6&Callable[[Unpack[PosArgsT]], T_Retval]c                    	 t           j        }t           j        }n# t          $ r t	          d          dw xY w|                    | ||          S )z
    Call a function in the event loop thread from a worker thread.

    :param func: a callable
    :param args: positional arguments for the callable
    :return: the return value of the callable

    r/   Nr0   )r   r2   r3   r4   r5   run_sync_from_threadr7   s       r9   run_syncr?   <   si    $:*   G
 
	
 --dD-FFFr;   c                  \    e Zd ZU ded<   ded<   ded<   dZded	<   ddZddZddZddZdS ) _BlockingAsyncContextManagerzFuture[T_co]_enter_futurezFuture[bool | None]_exit_futurer   _exit_event)NNNzMtuple[type[BaseException] | None, BaseException | None, TracebackType | None]_exit_exc_infoasync_cmAsyncContextManager[T_co]portalBlockingPortalc                "    || _         || _        d S N)	_async_cm_portal)selfrF   rH   s      r9   __init__z%_BlockingAsyncContextManager.__init__Z   s    !    r-   bool | Nonec                  K   	 t                      | _        | j                                         d {V }| j                            |           n-# t          $ r }| j                            |            d }~ww xY w	 | j                                         d {V   | j        j	        | j
          d {V }|S #  | j        j	        | j
          d {V }|c cY S xY wrK   )r   rD   rL   
__aenter__rB   
set_resultBaseExceptionset_exceptionr
   	__aexit__rE   )rN   valueexcresults       r9   run_async_cmz)_BlockingAsyncContextManager.run_async_cm^   s*     	1$wwD.3355555555E
 ))%0000	  	 	 	,,S111		
 "'')))))))))
 44>3T5HIIIIIIIFM 44>3T5HIIIIIIIFMMMMMMMMs#   2A 
A;A66A;?B: :Cr&   c                    t                      | _        | j                            | j                  | _        | j                                        S rK   )r   rB   rM   start_task_soonr[   rC   rZ   rN   s    r9   	__enter__z&_BlockingAsyncContextManager.__enter__u   s>    #XX L889JKK!((***rP   &_BlockingAsyncContextManager__exc_typetype[BaseException] | None'_BlockingAsyncContextManager__exc_valueBaseException | None'_BlockingAsyncContextManager__tracebackTracebackType | Nonec                    |||f| _         | j                            | j        j                   | j                                        S rK   )rE   rM   callrD   setrC   rZ   )rN   r`   rb   rd   s       r9   __exit__z%_BlockingAsyncContextManager.__exit__z   sD     )+{B$*./// '')))rP   N)rF   rG   rH   rI   )r-   rQ   )r-   r&   )r`   ra   rb   rc   rd   re   r-   rQ   )	__name__
__module____qualname____annotations__rE   rO   r[   r_   ri    rP   r9   rA   rA   R   s         %%%% 	           .+ + + +
* * * * * *rP   rA   c                       e Zd Zd
dZddd	ZdS )_BlockingPortalTaskStatusfuturer   c                    || _         d S rK   )_future)rN   rq   s     r9   rO   z"_BlockingPortalTaskStatus.__init__   s    rP   NrX   objectr-   Nonec                :    | j                             |           d S rK   )rs   rT   )rN   rX   s     r9   startedz!_BlockingPortalTaskStatus.started   s    &&&&&rP   )rq   r   rK   )rX   rt   r-   ru   )rj   rk   rl   rO   rw   rn   rP   r9   rp   rp      sA           ' ' ' ' ' ' 'rP   rp   c                      e Zd ZdZd4dZd5dZd4dZd6dZd5dZd5dZ	d7d8dZ
d9dZd:d Zed;d$            Zed<d&            Zd=d'Zed(d)d>d*            Zed(d)d?d+            Zd(d)d@d,Zd(d)dAd/ZdBd3Zd(S )CrI   zLAn object that lets external threads run code in an asynchronous event loop.r-   c                B    t                                                      S rK   )r   create_blocking_portal)clss    r9   __new__zBlockingPortal.__new__   s     ""99;;;rP   ru   c                    t          j                    | _        t                      | _        t                      | _        t                      | _        d S rK   )		threading	get_ident_event_loop_thread_idr   _stop_eventr   _task_groupr   _cancelled_exc_classr^   s    r9   rO   zBlockingPortal.__init__   sA    1:1D1F1F" 77,..$;$=$=!!!rP   c                H   K   | j                                          d {V  | S rK   )r   rS   r^   s    r9   rS   zBlockingPortal.__aenter__   s2      ))+++++++++rP   exc_typera   exc_valrc   exc_tbre   rQ   c                ~   K   |                                   d {V  | j                            |||           d {V S rK   )stopr   rW   )rN   r   r   r   s       r9   rW   zBlockingPortal.__aexit__   sU       iikk%//'6JJJJJJJJJrP   c                    | j         t          d          | j         t          j                    k    rt          d          d S )NzThis portal is not runningz7This method cannot be called from the event loop thread)r   r5   r~   r   r^   s    r9   _check_runningzBlockingPortal._check_running   sN    %-;<<<%)<)>)>>>I   ?>rP   c                H   K   | j                                          d{V  dS )z#Sleep until :meth:`stop` is called.N)r   r
   r^   s    r9   sleep_until_stoppedz"BlockingPortal.sleep_until_stopped   s3      ##%%%%%%%%%%%rP   Fcancel_remainingboolc                   K   d| _         | j                                         |r | j        j                                         dS dS )a.  
        Signal the portal to shut down.

        This marks the portal as no longer accepting new calls and exits from
        :meth:`sleep_until_stopped`.

        :param cancel_remaining: ``True`` to cancel all the remaining tasks, ``False``
            to let them finish before returning

        N)r   r   rh   r   cancel_scopecancel)rN   r   s     r9   r   zBlockingPortal.stop   sU       &*" 	3)0022222	3 	3rP   r)   <Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval]r+   tuple[Unpack[PosArgsT]]kwargsdict[str, Any]rq   Future[T_Retval]c                   	K   d	 fd}	  ||i |}t          |          rmt                      5 	|                                r	                                 n|                    |           | d {V }d d d            n# 1 swxY w Y   n|}|                                s|                    |           n#  j        $ r+ |                                 |                                 Y nUt          $ rI}|                                s|	                    |           t          |t                    s Y d }~nd }~ww xY wd 	d S # d 	w xY w)Nfr   r-   ru   c                    |                                  r8j        d t          j                    fvr                    j                   d S d S d S rK   )	cancelledr   r~   r   rg   r   )r   scoperN   s    r9   callbackz+BlockingPortal._call_func.<locals>.callback   sg    {{}} (!;#%%D " " 		%,'''''	( ( " "rP   )r   r   r-   ru   )r   r   r   r   add_done_callbackrT   r   set_running_or_notify_cancelrU   rV   
isinstance	Exception)
rN   r)   r+   r   rq   r   retval_or_awaitableretvalrY   r   s
   `        @r9   
_call_funczBlockingPortal._call_func   s     	( 	( 	( 	( 	( 	( 	(	"&$"7"7"7.// 	- ]] 7e'')) ;00:::#6666666F7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 - ##%% *!!&))) ( 	2 	2 	2MMOOO//11111 	 	 	##%% *$$S))) c9--     	 EEEDELLLLs_   %B= AB9B= B		B= B	B= *E
 =2E/E
 1	E:?D>9E
 >EE
 
Enamert   c                    t           )a%  
        Spawn a new task using the given callable.

        Implementors must ensure that the future is resolved when the task finishes.

        :param func: a callable
        :param args: positional arguments to be passed to the callable
        :param kwargs: keyword arguments to be passed to the callable
        :param name: name of the task (will be coerced to a string if not ``None``)
        :param future: a future that will resolve to the return value of the callable,
            or the exception raised during its execution

        )NotImplementedError)rN   r)   r+   r   r   rq   s         r9   _spawn_task_from_threadz&BlockingPortal._spawn_task_from_thread   s
    * "!rP   r*   r,   r%   c                    d S rK   rn   rN   r)   r+   s      r9   rg   zBlockingPortal.call  s	     	rP   r<   c                    d S rK   rn   r   s      r9   rg   zBlockingPortal.call  s	     	rP   c                h    t          t           | j        |g|R                                            S )a3  
        Call the given function in the event loop thread.

        If the callable returns a coroutine object, it is awaited on.

        :param func: any callable
        :raises RuntimeError: if the portal is not running or if this method is called
            from within the event loop thread

        )r   r%   r]   rZ   r   s      r9   rg   zBlockingPortal.call  s6     H2d24?$???FFHHIIIrP   N)r   c                   d S rK   rn   rN   r)   r   r+   s       r9   r]   zBlockingPortal.start_task_soon"  	     	rP   c                   d S rK   rn   r   s       r9   r]   zBlockingPortal.start_task_soon+  r   rP   c               |    |                                   t                      }|                     ||i ||           |S )a  
        Start a task in the portal's task group.

        The task will be run inside a cancel scope which can be cancelled by cancelling
        the returned future.

        :param func: the target function
        :param args: positional arguments passed to ``func``
        :param name: name of the task (will be coerced to a string if not ``None``)
        :return: a future that resolves with the return value of the callable if the
            task completes successfully, or with the exception raised in the task
        :raises RuntimeError: if the portal is not running or if this method is called
            from within the event loop thread
        :rtype: concurrent.futures.Future[T_Retval]

        .. versionadded:: 3.0

        )r   r   r   )rN   r)   r   r+   r   s        r9   r]   zBlockingPortal.start_task_soon4  s@    0 	$hh$$T4T1===rP   "Callable[..., Awaitable[T_Retval]]tuple[Future[T_Retval], Any]c                  dfd}|                                   t                      t                    }t                      }|                    |           |                     ||d|i||           |                                fS )a  
        Start a task in the portal's task group and wait until it signals for readiness.

        This method works the same way as :meth:`.abc.TaskGroup.start`.

        :param func: the target function
        :param args: positional arguments passed to ``func``
        :param name: name of the task (will be coerced to a string if not ``None``)
        :return: a tuple of (future, task_status_value) where the ``task_status_value``
            is the value passed to ``task_status.started()`` from within the target
            function
        :rtype: tuple[concurrent.futures.Future[T_Retval], Any]

        .. versionadded:: 3.0

        rq   r   r-   ru   c                J                                    s|                                 r                                 d S |                                 r)                    |                                            d S t          d          }                    |           d S d S )Nz1Task exited without calling task_status.started())doner   r   	exceptionrV   r5   )rq   rY   task_status_futures     r9   	task_donez,BlockingPortal.start_task.<locals>.task_doneh  s    %**,, 	:##%% :&--/////%%'' :&44V5E5E5G5GHHHHH&K C '44S99999	: 	:rP   task_status)rq   r   r-   ru   )r   r   rp   r   r   rZ   )rN   r)   r   r+   r   r   r   r   s          @r9   
start_taskzBlockingPortal.start_taskQ  s    .
	: 
	: 
	: 
	: 
	: 
	: 	%+XX/0BCCHH	I&&&$$T4-1MtUVWWW$++----rP   cmrG   ContextManager[T_co]c                "    t          ||           S )a  
        Wrap an async context manager as a synchronous context manager via this portal.

        Spawns a task that will call both ``__aenter__()`` and ``__aexit__()``, stopping
        in the middle until the synchronous context manager exits.

        :param cm: an asynchronous context manager
        :return: a synchronous context manager

        .. versionadded:: 2.1

        )rA   )rN   r   s     r9   wrap_async_context_managerz)BlockingPortal.wrap_async_context_manager|  s     ,B555rP   )r-   rI   r-   ru   )r   ra   r   rc   r   re   r-   rQ   )F)r   r   r-   ru   )
r)   r   r+   r   r   r   rq   r   r-   ru   )r)   r   r+   r   r   r   r   rt   rq   r   r-   ru   r)   r*   r+   r,   r-   r%   r)   r<   r+   r,   r-   r%   )r)   r   r+   r,   r-   r%   )r)   r*   r+   r,   r   rt   r-   r   )r)   r<   r+   r,   r   rt   r-   r   )r)   r   r+   r,   r   rt   r-   r   )r)   r   r+   rt   r   rt   r-   r   )r   rG   r-   r   )rj   rk   rl   __doc__r|   rO   rS   rW   r   r   r   r   r   r   rg   r]   r   r   rn   rP   r9   rI   rI      s       VV< < < <> > > >   K K K K   & & & &3 3 3 3 3 ( ( ( (T" " " ".    X    X
J J J J" 
 	     X 
 	     X 	     B 	). ). ). ). ). ).V6 6 6 6 6 6rP   rI   asynciobackendstrbackend_optionsdict[str, Any] | None$Generator[BlockingPortal, Any, None]c              #    K   d
fd}t                      t          d          5 }|                    t          j        || |          }	 t          t          t          t                    |g          t                     n7# t          $ r* 
                                 |
                                  w xY w                                r                                }d}	 |V  n# t          $ r d} w xY w	 	 |                    |j        |           nA# t          $ r Y n5w xY w# 	 |                    |j        |           w # t          $ r Y w w xY wxY w|                                 d	d	d	           d	S # 1 swxY w Y   d	S )a|  
    Start a new event loop in a new thread and run a blocking portal in its main task.

    The parameters are the same as for :func:`~anyio.run`.

    :param backend: name of the backend
    :param backend_options: backend options
    :return: a context manager that yields a blocking portal

    .. versionchanged:: 3.0
        Usage as a context manager is now required.

    r-   ru   c                   K   t                      4 d {V }                                 r/                    |            |                                  d {V  d d d           d {V  d S # 1 d {V swxY w Y   d S rK   )rI   r   rT   r   )portal_rq   s    r9   
run_portalz)start_blocking_portal.<locals>.run_portal  s     !## 	4 	4 	4 	4 	4 	4 	4w2244 4!!'***11333333333	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4 	4s   AA//
A9<A9r   )r   r   )return_whenFTNr   )r   r	   submitr   r:   r
   r   r   r   rU   r   r   rZ   rg   r   r5   )r   r   r   executor
run_futurerH   cancel_remaining_tasksrq   s          @r9   start_blocking_portalr     s3     $4 4 4 4 4 4 &,XXF	A		 (__N+	 % 
 

	Xf%
F';<<+      	 	 	MMOOO	
 ;;== 	]]__F%*"	    )-& 
KK-CDDDD#   DKK-CDDDD#   D 	?                 s   $E;6BE;4B77-E;%C*)D)*C88D)=DE;
D&#E;%D&&E;)E+EE
E	EE	EE;;E?E?ru   c                     	 t           j        } n# t          $ r t          d          dw xY w|                                  dS )aa  
    Check if the cancel scope of the host task's running the current worker thread has
    been cancelled.

    If the host task's current cancel scope has indeed been cancelled, the
    backend-specific cancellation exception will be raised.

    :raises RuntimeError: if the current thread was not spawned by
        :func:`.to_thread.run_sync`

    r/   N)r   r2   r4   r5   check_cancelled)r8   s    r9   r   r     s^    &2&H   G
 
	
 !!#####s    *r   r   )r   N)r   r   r   r   r-   r   r   ):
__future__r   sysr~   collections.abcr   r   r   concurrent.futuresr   r   r	   r
   
contextlibr   r   inspectr   typesr   typingr   r   r   r   r   r   r   r   _corer   _core._eventloopr   r   r   _core._synchronizationr   _core._tasksr   r   abcr   
abc._tasksr    version_infor#   r$   typing_extensionsr%   r&   r(   r:   r?   rA   rp   rI   r   r   rn   rP   r9   <module>r      s   " " " " " " 



     : : : : : : : : : : P P P P P P P P P P P P = = = = = = = =            	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	       V V V V V V V V V V ) ) ) ) ) ) 8 8 8 8 8 8 8 8       " " " " " "w+++++++++666666667:wv&&&<
##H H H H,G G G G,0* 0* 0* 0* 0*74=2H 0* 0* 0*f' ' ' ' '
 ' ' '~6 ~6 ~6 ~6 ~6 ~6 ~6 ~6B GK7 7 7 7 7t$ $ $ $ $ $rP   