o
    pf=                     @  s  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rd dlm-Z-m.Z. nd dl/m-Z-m.Z. edZ0edddZ1e-dZ2d2ddZ3d3dd Z4G d!d" d"ee1 eZ5G d#d$ d$e+Z6G d%d& d&Z7e	d4d5d-d.Z8d6d0d1Z9dS )7    )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                 G  :   zt j}t j}W n ty   tddw |j| ||d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_backendr0    r8   J/home/ertert/spirit/venv/lib/python3.10/site-packages/anyio/from_thread.pyrun&      
r:   &Callable[[Unpack[PosArgsT]], T_Retval]c                 G  r-   )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.   Nr/   )r   r1   r2   r3   r4   run_sync_from_threadr6   r8   r8   r9   run_sync<   r;   r>   c                   @  sZ   e Zd ZU ded< ded< ded< dZded	< d ddZd!ddZd"ddZd#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                 C  s   || _ || _d S N)	_async_cm_portal)selfrD   rF   r8   r8   r9   __init__Z   s   
z%_BlockingAsyncContextManager.__init__r,   bool | Nonec              
     s   zt  | _| j I d H }W n ty" } z| j|  d }~ww | j| z| j I d H  W | jj	| j
 I d H }|S | jj	| j
 I d H }|     Y S rH   )r   rB   rI   
__aenter__BaseExceptionr@   set_exception
set_resultr	   	__aexit__rC   )rK   valueexcresultr8   r8   r9   run_async_cm^   s    z)_BlockingAsyncContextManager.run_async_cmr%   c                 C  s"   t  | _| j| j| _| j S rH   )r   r@   rJ   start_task_soonrV   rA   rU   rK   r8   r8   r9   	__enter__u   s   
z&_BlockingAsyncContextManager.__enter__&_BlockingAsyncContextManager__exc_typetype[BaseException] | None'_BlockingAsyncContextManager__exc_valueBaseException | None'_BlockingAsyncContextManager__tracebackTracebackType | Nonec                 C  s&   |||f| _ | j| jj | j S rH   )rC   rJ   callrB   setrA   rU   )rK   rZ   r\   r^   r8   r8   r9   __exit__z   s   
z%_BlockingAsyncContextManager.__exit__N)rD   rE   rF   rG   )r,   rM   )r,   r%   )rZ   r[   r\   r]   r^   r_   r,   rM   )	__name__
__module____qualname____annotations__rC   rL   rV   rY   rb   r8   r8   r8   r9   r?   R   s   
 



r?   c                   @  s"   e Zd ZdddZddd
dZdS )_BlockingPortalTaskStatusfuturer   c                 C  s
   || _ d S rH   )_future)rK   rh   r8   r8   r9   rL         
z"_BlockingPortalTaskStatus.__init__NrS   objectr,   Nonec                 C  s   | j | d S rH   )ri   rQ   )rK   rS   r8   r8   r9   started   s   z!_BlockingPortalTaskStatus.started)rh   r   rH   )rS   rk   r,   rl   )rc   rd   re   rL   rm   r8   r8   r8   r9   rg      s    
rg   c                   @  s   e Zd ZdZdAddZdBddZdAdd	ZdCddZdBddZdBddZ	dDdEddZ
dFd$d%ZdGd(d)ZedHd-d.ZedId0d.ZdJd1d.Zed2d3dKd4d5Zed2d3dLd6d5Zd2d3dMd7d5Zd2d3dNd:d;ZdOd?d@Zd2S )PrG   zLAn object that lets external threads run code in an asynchronous event loop.r,   c                 C  s
   t   S rH   )r   create_blocking_portal)clsr8   r8   r9   __new__   rj   zBlockingPortal.__new__rl   c                 C  s&   t  | _t | _t | _t | _d S rH   )		threading	get_ident_event_loop_thread_idr   _stop_eventr   _task_groupr   _cancelled_exc_classrX   r8   r8   r9   rL      s   
zBlockingPortal.__init__c                   s   | j  I d H  | S rH   )ru   rN   rX   r8   r8   r9   rN      s   zBlockingPortal.__aenter__exc_typer[   exc_valr]   exc_tbr_   rM   c                   s&   |   I d H  | j|||I d H S rH   )stopru   rR   )rK   rw   rx   ry   r8   r8   r9   rR      s   zBlockingPortal.__aexit__c                 C  s,   | j d u r	td| j t krtdd S )NzThis portal is not runningz7This method cannot be called from the event loop thread)rs   r4   rq   rr   rX   r8   r8   r9   _check_running   s   
zBlockingPortal._check_runningc                   s   | j  I dH  dS )z#Sleep until :meth:`stop` is called.N)rt   r	   rX   r8   r8   r9   sleep_until_stopped   s   z"BlockingPortal.sleep_until_stoppedFcancel_remainingboolc                   s*   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)rs   rt   ra   ru   cancel_scopecancel)rK   r}   r8   r8   r9   rz      s   
zBlockingPortal.stopr(   <Callable[[Unpack[PosArgsT]], Awaitable[T_Retval] | T_Retval]r*   tuple[Unpack[PosArgsT]]kwargsdict[str, Any]rh   Future[T_Retval]c           	   
     s&  d fdd}zz6||i |}t |r=t  | r#   n|| |I d H }W d    n1 s7w   Y  n|}W n2 jyR   |  |  Y n4 tyr } z| sb|| t	|t
sh W Y d }~nd }~ww | s|| W d  d S W d  d S W d  d S W d  d S d  w )Nfr   r,   rl   c                   s2   |   rjd t fvr j d S d S d S rH   )	cancelledrs   rq   rr   r`   r   )r   scoperK   r8   r9   callback   s   z+BlockingPortal._call_func.<locals>.callback)r   r   r,   rl   )r   r   r   r   add_done_callbackrv   set_running_or_notify_cancelrO   rP   
isinstance	ExceptionrQ   )	rK   r(   r*   r   rh   r   retval_or_awaitableretvalrT   r8   r   r9   
_call_func   sD   



zBlockingPortal._call_funcnamerk   c                 C  s   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)rK   r(   r*   r   r   rh   r8   r8   r9   _spawn_task_from_thread   s   z&BlockingPortal._spawn_task_from_threadr)   r+   r$   c                 G     d S rH   r8   rK   r(   r*   r8   r8   r9   r`     s   zBlockingPortal.callr<   c                 G  r   rH   r8   r   r8   r8   r9   r`     s   c                 G  s   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$   rW   rU   r   r8   r8   r9   r`     s   N)r   c                G  r   rH   r8   rK   r(   r   r*   r8   r8   r9   rW   "     zBlockingPortal.start_task_soonc                G  r   rH   r8   r   r8   r8   r9   rW   +  r   c                G  s$   |    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   )rK   r(   r   r*   r   r8   r8   r9   rW   4  s   "Callable[..., Awaitable[T_Retval]]tuple[Future[T_Retval], Any]c                  sV   d	 fd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

        rh   r   r,   rl   c                   sP      s&|  r   d S |  r |   d S td} | d S d S )Nz1Task exited without calling task_status.started())doner   r   	exceptionrP   r4   )rh   rT   task_status_futurer8   r9   	task_doneh  s   z,BlockingPortal.start_task.<locals>.task_donetask_statusN)rh   r   r,   rl   )r{   r   rg   r   r   rU   )rK   r(   r   r*   r   r   r   r8   r   r9   
start_taskQ  s   
zBlockingPortal.start_taskcmrE   ContextManager[T_co]c                 C  s
   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

        )r?   )rK   r   r8   r8   r9   wrap_async_context_manager|  s   
z)BlockingPortal.wrap_async_context_manager)r,   rG   r,   rl   )rw   r[   rx   r]   ry   r_   r,   rM   )F)r}   r~   r,   rl   )
r(   r   r*   r   r   r   rh   r   r,   rl   )r(   r   r*   r   r   r   r   rk   rh   r   r,   rl   r(   r)   r*   r+   r,   r$   r(   r<   r*   r+   r,   r$   )r(   r   r*   r+   r,   r$   )r(   r)   r*   r+   r   rk   r,   r   )r(   r<   r*   r+   r   rk   r,   r   )r(   r   r*   r+   r   rk   r,   r   )r(   r   r*   rk   r   rk   r,   r   )r   rE   r,   r   )rc   rd   re   __doc__rp   rL   rN   rR   r{   r|   rz   r   r   r   r`   rW   r   r   r8   r8   r8   r9   rG      s6    




	


*
!+rG   asynciobackendstrbackend_optionsdict[str, Any] | None$Generator[BlockingPortal, Any, None]c                 #  s$   d fdd}t   tdy}|jtj|| |d}ztttt  | gtd W n t	y9    
  |
   w   r|  }d}z$z|V  W n
 t	yT   d	} w W z	||j| W n tyh   Y nw z	||j| W w  ty{   Y w w |  W d
   d
S 1 sw   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,   rl   c               	     sx   t  4 I d H '}   r$ |  |  I d H  W d   I d H  d S W d   I d H  d S 1 I d H s5w   Y  d S rH   )rG   r   rQ   r|   )portal_rh   r8   r9   
run_portal  s   
.z)start_blocking_portal.<locals>.run_portalr   )r   r   )return_whenFTNr   )r   r   submitr   r:   r	   r   r   r   rO   r   r   rU   r`   rz   r4   )r   r   r   executor
run_futurerF   cancel_remaining_tasksr8   r   r9   start_blocking_portal  sT   



"r   rl   c                  C  s0   zt j} W n ty   tdd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   r1   r3   r4   check_cancelled)r7   r8   r8   r9   r     s   
r   r   r   )r   N)r   r   r   r   r,   r   r   ):
__future__r   sysrq   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>   r?   rg   rG   r   r   r8   r8   r8   r9   <module>   s@    (


3  :