o
    0׾g"d                     @   s   d Z ddlmZmZmZ ddl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 ddlmZmZ dd	lmZ dd
lmZ ddlmZ g d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 )a2  
Managing greenlets in a group.

The :class:`Group` class in this module abstracts a group of running
greenlets. When a greenlet dies, it's automatically removed from the
group. All running greenlets in a group can be waited on with
:meth:`Group.join`, or all running greenlets can be killed with
:meth:`Group.kill`.

The :class:`Pool` class, which is a subclass of :class:`Group`,
provides a way to limit concurrency: its :meth:`spawn <Pool.spawn>`
method blocks if the number of greenlets in the pool has already
reached the limit, until there is a free slot.
    )print_functionabsolute_importdivision)GreenletExit
getcurrentkill)joinallGreenlet)Full)Timeout)Event)	SemaphoreDummySemaphore)izip)IMap)IMapUnordered)GroupPoolPoolFullc                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 ZdddZdddZ	d ddZ
dd Zdd Zd!ddZd!ddZdd Zdd Zdd Zd
S )"GroupMappingMixin c                 O      t  )a  
        A function that runs *func* with *args* and *kwargs*, potentially
        asynchronously. Return a value with a ``get`` method that blocks
        until the results of func are available, and a ``rawlink`` method
        that calls a callback when the results are available.

        If this object has an upper bound on how many asyncronously executing
        tasks can exist, this method may block until a slot becomes available.
        NotImplementedError)selffuncargskwargsr   r   U/var/www/html/backend_erp/backend_erp_env/lib/python3.10/site-packages/gevent/pool.pyspawn-   s   
zGroupMappingMixin.spawnc                 C   r   )zc
        should the function passed to apply be called immediately,
        synchronously?
        r   r   r   r   r   _apply_immediately9      z$GroupMappingMixin._apply_immediatelyc                 C   r   )z
        Should apply_async directly call Greenlet.spawn(), bypassing
        `spawn`?

        Return true when self.spawn would block.
        r   r    r   r   r   _apply_async_use_greenlet@   s   z+GroupMappingMixin._apply_async_use_greenletc                 C   r   )zk
        Run the given callback function, possibly
        asynchronously, possibly synchronously.
        r   r   callbackresultr   r   r   _apply_async_cb_spawnI   r"   z'GroupMappingMixin._apply_async_cb_spawnNc                 C   s&   |  |||}|dur| || |S )a  
        :meth:`apply` the given *func(\*args, \*\*kwds)*, and, if a *callback* is given, run it with the
        results of *func* (unless an exception was raised.)

        The *callback* may be called synchronously or asynchronously. If called
        asynchronously, it will not be tracked by this group. (:class:`Group` and :class:`Pool`
        call it asynchronously in a new greenlet; :class:`~gevent.threadpool.ThreadPool` calls
        it synchronously in the current greenlet.)
        N)applyr'   )r   r   r   kwdsr%   r&   r   r   r   apply_cbP   s   
zGroupMappingMixin.apply_cbc                 C   sf   |du rd}|du ri }|   rt| j||||S | j|g|R i |}|dur1|t| |S )a  
        A variant of the :meth:`apply` method which returns a :class:`~.Greenlet` object.

        When the returned greenlet gets to run, it *will* call :meth:`apply`,
        passing in *func*, *args* and *kwds*.

        If *callback* is specified, then it should be a callable which
        accepts a single argument. When the result becomes ready
        callback is applied to it (unless the call failed).

        This method will never block, even if this group is full (that is,
        even if :meth:`spawn` would block, this method will not).

        .. caution:: The returned greenlet may or may not be tracked
           as part of this group, so :meth:`joining <join>` this group is
           not a reliable way to wait for the results to be available or
           for the returned greenlet to run; instead, join the returned
           greenlet.

        .. tip:: Because :class:`~.ThreadPool` objects do not track greenlets, the returned
           greenlet will never be a part of it. To reduce overhead and improve performance,
           :class:`Group` and :class:`Pool` may choose to track the returned
           greenlet. These are implementation details that may change.
        Nr   )r#   r	   r   r*   link
pass_value)r   r   r   r)   r%   greenletr   r   r   apply_async_   s   	zGroupMappingMixin.apply_asyncc                 C   sJ   |du rd}|du ri }|   r||i |S | j|g|R i | S )a  
        Rough quivalent of the :func:`apply()` builtin function blocking until
        the result is ready and returning it.

        The ``func`` will *usually*, but not *always*, be run in a way
        that allows the current greenlet to switch out (for example,
        in a new greenlet or thread, depending on implementation). But
        if the current greenlet or thread is already one that was
        spawned by this pool, the pool may choose to immediately run
        the `func` synchronously.

        Any exception ``func`` raises will be propagated to the caller of ``apply`` (that is,
        this method will raise the exception that ``func`` raised).
        Nr   )r!   r   get)r   r   r   r)   r   r   r   r(      s   zGroupMappingMixin.applyc                    s   dd  fdd|D D S )Nc                 S   s   g | ]}|  qS r   )r/   ).0gr   r   r   
<listcomp>   s    z+GroupMappingMixin.__map.<locals>.<listcomp>c                    s   g | ]}  |qS r   )r   )r0   ir   r   r   r   r2      s    r   )r   r   iterabler   r4   r   __map   s   zGroupMappingMixin.__mapc                 C   s   t | j||}| S )z~Return a list made by applying the *func* to each element of
        the iterable.

        .. seealso:: :meth:`imap`
        )r	   r   _GroupMappingMixin__mapr/   )r   r   r5   r1   r   r   r   map   s   "zGroupMappingMixin.mapc                 C   s    |  ||}|d ur|| |S N)r8   )r   r   r5   r%   r&   r   r   r   map_cb   s   zGroupMappingMixin.map_cbc                 C   s   t | j|||S )z
        A variant of the map() method which returns a Greenlet object that is executing
        the map function.

        If callback is specified then it should be a callable which accepts a
        single argument.
        )r	   r   r:   )r   r   r5   r%   r   r   r   	map_async   s   zGroupMappingMixin.map_asyncc                 O   s2   | dd }|rtd|j|t| | jd|dS )NmaxsizezUnsupported keyword argumentsT)r   _zippedr<   )pop	TypeErrorr   r   )r   clsr   	iterablesr   r<   r   r   r   __imap   s   zGroupMappingMixin.__imapc                 O      | j t|g|R i |S )a  
        imap(func, *iterables, maxsize=None) -> iterable

        An equivalent of :func:`itertools.imap`, operating in parallel.
        The *func* is applied to each element yielded from each
        iterable in *iterables* in turn, collecting the result.

        If this object has a bound on the number of active greenlets it can
        contain (such as :class:`Pool`), then at most that number of tasks will operate
        in parallel.

        :keyword int maxsize: If given and not-None, specifies the maximum number of
            finished results that will be allowed to accumulate awaiting the reader;
            more than that number of results will cause map function greenlets to begin
            to block. This is most useful if there is a great disparity in the speed of
            the mapping code and the consumer and the results consume a great deal of resources.

            .. note:: This is separate from any bound on the number of active parallel
               tasks, though they may have some interaction (for example, limiting the
               number of parallel tasks to the smallest bound).

            .. note:: Using a bound is slightly more computationally expensive than not using a bound.

            .. tip:: The :meth:`imap_unordered` method makes much better
                use of this parameter. Some additional, unspecified,
                number of objects may be required to be kept in memory
                to maintain order by this function.

        :return: An iterable object.

        .. versionchanged:: 1.1b3
            Added the *maxsize* keyword parameter.
        .. versionchanged:: 1.1a1
            Accept multiple *iterables* to iterate in parallel.
        )_GroupMappingMixin__imapr   r   r   rA   r   r   r   r   imap   s   $zGroupMappingMixin.imapc                 O   rC   )a  
        imap_unordered(func, *iterables, maxsize=None) -> iterable

        The same as :meth:`imap` except that the ordering of the results
        from the returned iterator should be considered in arbitrary
        order.

        This is lighter weight than :meth:`imap` and should be preferred if order
        doesn't matter.

        .. seealso:: :meth:`imap` for more details.
        )rD   r   rE   r   r   r   imap_unordered  s   z GroupMappingMixin.imap_unordered)NNNNNr9   )__name__
__module____qualname__	__slots__r   r!   r#   r'   r*   r.   r(   r7   r8   r:   r;   rD   rF   rG   r   r   r   r   r   '   s     	


-
%

	&r   c                   @   s   e Zd ZdZeZdd Zdd Zdd Zdd	 Z	d
d Z
dd Zdd Zdd Zdd Zdd Zd)ddZeddfddZeddfddZdd  Zd*d!d"Zd#d$ Zd%d& Zd'd( ZdS )+r   a  
    Maintain a group of greenlets that are still running, without
    limiting their number.

    Links to each item and removes it upon notification.

    Groups can be iterated to discover what greenlets they are tracking,
    they can be tested to see if they contain a greenlet, and they know the
    number (len) of greenlets they are tracking. If they are not tracking any
    greenlets, they are False in a boolean context.

    .. attribute:: greenlet_class

        Either :class:`gevent.Greenlet` (the default) or a subclass.
        These are the type of
        object we will :meth:`spawn`. This can be
        changed on an instance or in a subclass.
    c                 G   sZ   t |dks
J |t| | _|r|d D ]}|| j qt | _t | _| j  d S )N   r   )lenset	greenletsrawlink_discarddyingr   _empty_event)r   r   r-   r   r   r   __init__1  s   
zGroup.__init__c                 C   s   d| j jt| | jf S )Nz<%s at 0x%x %s>)	__class__rI   idrP   r    r   r   r   __repr__<  s   zGroup.__repr__c                 C   
   t | jS )z
        Answer how many greenlets we are tracking. Note that if we are empty,
        we are False in a boolean context.
        )rN   rP   r    r   r   r   __len__?  s   
zGroup.__len__c                 C   s
   || j v S )z?
        Answer if we are tracking the given greenlet.
        )rP   r   itemr   r   r   __contains__F     
zGroup.__contains__c                 C   rY   )z[
        Iterate across all the greenlets we are tracking, in no particular order.
        )iterrP   r    r   r   r   __iter__L  r^   zGroup.__iter__c                 C   sB   z|j }W n	 ty   Y nw || j | j| | j  dS )ar  
        Begin tracking the *greenlet*.

        If this group is :meth:`full`, then this method may block
        until it is possible to track the greenlet.

        Typically the *greenlet* should **not** be started when
        it is added because if this object blocks in this method,
        then the *greenlet* may run to completion before it is tracked.
        N)rQ   AttributeErrorrR   rP   addrT   clear)r   r-   rQ   r   r   r   rb   R  s   

z	Group.addc                 C   s0   | j | | j| | j s| j  d S d S r9   )rP   discardrS   rT   rO   r   r-   r   r   r   rR   f  s
   zGroup._discardc                 C   s8   |  | z|j}W n
 ty   Y dS w || j  dS )z-
        Stop tracking the greenlet.
        N)rR   unlinkra   )r   r-   rf   r   r   r   rd   l  s   

zGroup.discardc                 C   s   |  | |  dS )z
        Add the **unstarted** *greenlet* to the collection of greenlets
        this group is monitoring, and then start it.
        Nrb   startre   r   r   r   rh   x  s   
zGroup.startc                 O   s   | j |i |}| | |S )z
        Begin a new greenlet with the given arguments (which are passed
        to the greenlet constructor) and add it to the collection of greenlets
        this group is monitoring.

        :return: The newly started greenlet.
        )greenlet_classrh   )r   r   r   r-   r   r   r   r     s   
zGroup.spawnNFc                 C   sP   |rt | jnd}| jj|d}|D ]}|jdur%t|dr"|  |jq|S )a;  
        Wait for this group to become empty *at least once*.

        If there are no greenlets in the group, returns immediately.

        .. note:: By the time the waiting code (the caller of this
           method) regains control, a greenlet may have been added to
           this group, and so this object may no longer be empty. (That
           is, ``group.join(); assert len(group) == 0`` is not
           guaranteed to hold.) This method only guarantees that the group
           reached a ``len`` of 0 at some point.

        :keyword bool raise_error: If True (*not* the default), if any
            greenlet that finished while the join was in progress raised
            an exception, that exception will be raised to the caller of
            this method. If multiple greenlets raised exceptions, which
            one gets re-raised is not determined. Only greenlets currently
            in the group when this method is called are guaranteed to
            be checked for exceptions.

        :return bool: A value indicating whether this group became empty.
           If the timeout is specified and the group did not become empty
           during that timeout, then this will be a false value. Otherwise
           it will be a true value.

        .. versionchanged:: 1.2a1
           Add the return value.
        r   timeoutN_raise_exception)listrP   rT   wait	exceptionhasattrrl   )r   rk   raise_errorrP   r&   r-   r   r   r   join  s   

z
Group.joinTc              
   C   s   t |}zdz>| jrCt| jD ](}|| jv rqz|j}W n ty*   t|| Y nw ||dd | j| q|s;nt	| j | js
W n t y[ } z||urQ W Y d}~nd}~ww W |
  dS W |
  dS |
  w )zA
        Kill all greenlets being tracked by this group.
        FblockN)r   _start_new_or_dummyrP   rm   rS   r   ra   _killrb   r   cancel)r   ro   rt   rk   timerr-   r   exr   r   r   r     s8   



z
Group.killc                 C   sL   || j vr || jv r"|j|dd | j | |r$|| dS dS dS dS )zf
        If the given *greenlet* is running and being tracked by this group,
        kill it.
        Frs   N)rS   rP   r   rb   rr   )r   r-   ro   rt   rk   r   r   r   killone  s   zGroup.killonec                 C      dS )z
        Return a value indicating whether this group can track more greenlets.

        In this implementation, because there are no limits on the number of
        tracked greenlets, this will always return a ``False`` value.
        Fr   r    r   r   r   full  s   z
Group.fullc                 C   r{   )z
        Block until it is possible to :meth:`spawn` a new greenlet.

        In this implementation, because there are no limits on the number
        of tracked greenlets, this will always return immediately.
        Nr   r   rk   r   r   r   wait_available  s    zGroup.wait_availablec                 C   s
   t  | v S r9   )r   r    r   r   r   r!     r^   zGroup._apply_immediatelyc                 C   s   t || d S r9   )r	   r   r$   r   r   r   r'     s   zGroup._apply_async_cb_spawnc                 C   s   |   S r9   )r|   r    r   r   r   r#     s   zGroup._apply_async_use_greenlet)NFr9   )rI   rJ   rK   __doc__r	   ri   rU   rX   rZ   r]   r`   rb   rR   rd   rh   r   rr   r   r   rz   r|   r~   r!   r'   r#   r   r   r   r   r     s*    
(
	
r   c                   @   s   e Zd ZdZdS )r   zr
    Raised when a Pool is full and an attempt was made to
    add a new greenlet to it in non-blocking mode.
    N)rI   rJ   rK   r   r   r   r   r   r     s    r   c                   @   sJ   e Zd ZdddZdddZdd Zdd	 Zd
d ZdddZdd Z	dS )r   Nc                 C   s\   |dur|dk rt d|f t|  || _|dur|| _|du r%t}nt}||| _dS )a  
        Create a new pool.

        A pool is like a group, but the maximum number of members
        is governed by the *size* parameter.

        :keyword int size: If given, this non-negative integer is the
            maximum count of active greenlets that will be allowed in
            this pool. A few values have special significance:

            * `None` (the default) places no limit on the number of
              greenlets. This is useful when you want to track, but not limit,
              greenlets. In general, a :class:`Group`
              may be a more efficient way to achieve the same effect, but some things
              need the additional abilities of this class (one example being the *spawn*
              parameter of :class:`gevent.baseserver.BaseServer` and
              its subclass :class:`gevent.pywsgi.WSGIServer`).

            * ``0`` creates a pool that can never have any active greenlets. Attempting
              to spawn in this pool will block forever. This is only useful
              if an application uses :meth:`wait_available` with a timeout and checks
              :meth:`free_count` before attempting to spawn.
        Nr   zsize must not be negative: %r)
ValueErrorr   rU   sizeri   r   r   
_semaphore)r   r   ri   factoryr   r   r   rU   
  s   
zPool.__init__c                 C   s   | j j|dS )a  
        Wait until it's possible to spawn a greenlet in this pool.

        :param float timeout: If given, only wait the specified number
            of seconds.

        .. warning:: If the pool was initialized with a size of 0, this
           method will block forever unless a timeout is given.

        :return: A number indicating how many new greenlets can be put into
           the pool without blocking.

        .. versionchanged:: 1.1a3
            Added the ``timeout`` parameter.
        rj   )r   rn   r}   r   r   r   r~   .  s   zPool.wait_availablec                 C   s   |   dkS )z
        Return a boolean indicating whether this pool is full, e.g. if
        :meth:`add` would block.

        :return: False if there is room for new members, True if there isn't.
        r   )
free_countr    r   r   r   r|   @  s   z	Pool.fullc                 C   s"   | j du rdS td| j t|  S )zu
        Return a number indicating *approximately* how many more members
        can be added to this pool.
        NrM   r   )r   maxrN   r    r   r   r   r   I  s   
zPool.free_countc                 O   s$   | j |g|R i | |  dS )z
        start(greenlet, blocking=True, timeout=None) -> None

        Add the **unstarted** *greenlet* to the collection of greenlets
        this group is monitoring and then start it.

        Parameters are as for :meth:`add`.
        Nrg   )r   r-   r   r   r   r   r   rh   R  s   	z
Pool.startTc                 C   s<   | j j||dst z	t| | W dS    | j    )a  
        Begin tracking the given **unstarted** greenlet, possibly blocking
        until space is available.

        Usually you should call :meth:`start` to track and start the greenlet
        instead of using this lower-level method, or :meth:`spawn` to
        also create the greenlet.

        :keyword bool blocking: If True (the default), this function
            will block until the pool has space or a timeout occurs.  If
            False, this function will immediately raise a Timeout if the
            pool is currently full.
        :keyword float timeout: The maximum number of seconds this
            method will block, if ``blocking`` is True.  (Ignored if
            ``blocking`` is False.)
        :raises PoolFull: if either ``blocking`` is False and the pool
            was full, or if ``blocking`` is True and ``timeout`` was
            exceeded.

        ..  caution:: If the *greenlet* has already been started and
            *blocking* is true, then the greenlet may run to completion
            while the current greenlet blocks waiting to track it. This would
            enable higher concurrency than desired.

        ..  seealso:: :meth:`Group.add`

        ..  versionchanged:: 1.3.0 Added the ``blocking`` and
            ``timeout`` parameters.
        )blockingrk   N)r   acquirer   r   rb   release)r   r-   r   rk   r   r   r   rb   ^  s   
zPool.addc                 C   s   t | | | j  d S r9   )r   rR   r   r   re   r   r   r   rR     s   zPool._discardrH   r9   )TN)
rI   rJ   rK   rU   r~   r|   r   rh   rb   rR   r   r   r   r   r     s    

$		
*r   c                   @   sJ   e Zd ZdgZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )r,   r%   c                 C   s
   || _ d S r9   )r%   )r   r%   r   r   r   rU        
zpass_value.__init__c                 C   s   |  r| |j d S d S r9   )
successfulr%   value)r   sourcer   r   r   __call__  s   zpass_value.__call__c                 C   rY   r9   )hashr%   r    r   r   r   __hash__  r   zpass_value.__hash__c                 C   s   | j t|d|kS Nr%   )r%   getattr)r   otherr   r   r   __eq__  s   zpass_value.__eq__c                 C   rY   r9   )strr%   r    r   r   r   __str__  r   zpass_value.__str__c                 C   rY   r9   )reprr%   r    r   r   r   rX     r   zpass_value.__repr__c                 C   s   |dksJ t | j|S r   )r   r%   r[   r   r   r   __getattr__  s   zpass_value.__getattr__N)rI   rJ   rK   rL   rU   r   r   r   r   rX   r   r   r   r   r   r,     s    r,   N)#r   
__future__r   r   r   
gevent.hubr   r   r   rv   gevent.greenletr   r	   gevent.queuer
   	QueueFullgevent.timeoutr   gevent.eventr   gevent.lockr   r   gevent._compatr   gevent._imapr   r   __all__objectr   r   r   r   r,   r   r   r   r   <module>   s(   	 u g 