Ë
    r™ãj:>  ã                  óÌ   — d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	 ddl
mZ  G d„ d	«      Z G d
„ d«      Zej                  dd„«       Z G d„ d«      Zd„ Z	 dd„Z	 dd„Zy)a›  Deterministic cancellation testing for the asyncio dialects.

An asyncio task may be cancelled at any ``await``, and reproducing a
specific one of those points by racing ``task.cancel()`` against real
network traffic is unreliable.  Here the choice is made exact.
:func:`.greenlet_spawn` drives every await performed by an asyncio-driven
SQLAlchemy operation, ``connect()`` included, so instrumenting the greenlet
it switches into gives a stable enumeration of a scenario's IO points, and
cancelling at point ``N`` is reproducible run to run.

The cancellation is delivered to the task the application is running,
which is not necessarily the task performing the await; SQLAlchemy runs
some operations, such as the ``close()`` performed by an async context
manager on exit, in a task of its own.

Four things are asserted afterwards:

* The cancellation reaches the application.  The task ends cancelled,
  rather than raising some other exception in place of the
  ``CancelledError`` or returning normally; an application that treats an
  ordinary exception as something to retry would otherwise carry on past
  its own shutdown.

* Every DBAPI connection the pool creates is eventually closed through
  ``Pool._close_connection()``.  A connection that is never closed is
  leaked; for an asyncio driver the garbage collector cannot close it
  either, since closing requires the event loop.

* Once the application's task has finished and garbage has been
  collected, no pool slot is still checked out.  A slot still checked out
  at that point is lost: either nothing remains that could return it, or
  it is being returned by a task SQLAlchemy left running in the
  background, which the application has no way to wait for.  In the
  latter case, an application that disposes of its engine at that point
  has the connection returned into the disposed pool afterwards, where
  nothing closes it.

* The pool still works.  The scenario is run once more against the same
  engine, un-cancelled, and has to succeed.  A connection that was closed
  and nonetheless returned to the pool as though it were usable is neither
  leaked nor a lost slot; it is found only by the next thing to check it
  out.

é    )ÚannotationsN)Úmocké   )Úexc)Úconcurrencyc                  ó    — e Zd ZdZdZd„ Zd„ Zy)Ú_InstrumentedAwaitablez6An awaitable that invokes ``hook`` when it is awaited.©Ú	awaitableÚhookc                ó    — || _         || _        y ©Nr
   )Úselfr   r   s      új/var/www/html/python-recuperauto-other/env/lib/python3.12/site-packages/sqlalchemy/testing/cancellation.pyÚ__init__z_InstrumentedAwaitable.__init__F   s   € Ø"ˆŒØˆ�	ó    c                ól   — | j                  | j                  «       | j                  j                  «       S r   )r   r   Ú	__await__©r   s    r   r   z _InstrumentedAwaitable.__await__J   s%   € Ø�	‰	�$—.‘.Ô!Ø�~‰~×'Ñ'Ó)Ð)r   N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r   r   © r   r   r	   r	   A   s   „ Ù@à%€Iòó*r   r	   c                  óD   — e Zd ZdZdd„Zed„ «       Zed„ «       Zd„ Zd„ Z	y)	ÚAwaitPointsaq  Counts await points, and cancels the running task at each of the
    ones given.

    ``cancel_at`` is a tuple of await point numbers; each one is a separate
    ``task.cancel()`` call.  asyncio delivers a given cancellation exactly
    once, so a second number models a second, independent canceller
    reaching a task that is still cleaning up after the first.

    c                ó<   — d| _         || _        g | _        d | _        y ©Nr   )Ú_countÚ
_cancel_atÚ_cancelled_atÚ_task)r   Ú	cancel_ats     r   r   zAwaitPoints.__init__Z   s   € ØˆŒØ#ˆŒØˆÔØˆ�
r   c                ó   — | j                   S )z*The number of await points counted so far.)r    r   s    r   ÚcountzAwaitPoints.count`   s   € ð �{‰{Ðr   c                ó,   — t        | j                  «      S )zMDescriptions of the awaitables at which a cancellation was
        delivered.)Útupler"   r   s    r   Úcancelled_atzAwaitPoints.cancelled_atf   s   € ô
 �T×'Ñ'Ó(Ð(r   c                óN   — t        j                  |«      | _        | j                  S )zZRun ``coro`` in a new task, which is the task that cancellations
        are delivered to.)ÚasyncioÚcreate_taskr#   )r   Úcoros     r   r,   zAwaitPoints.create_taskm   s    € ô ×(Ñ(¨Ó.ˆŒ
Ø�z‰zÐr   c           	     óH  — | xj                   dz  c_         | j                   | j                  vry | j                  j                  t	        |dt        |«      «      «       | j                  �| j                  nt        j                  «       }|€J d«       ‚|j                  «        y )Né   r   zQcancellation can only be delivered to an operation running within an asyncio task)
r    r!   r"   ÚappendÚgetattrÚreprr#   r+   Úcurrent_taskÚcancel)r   r   Útasks      r   Ú__call__zAwaitPoints.__call__t   s‰   € Ø�Š�qÑ�Ø�;‰;˜dŸo™oÑ-Øà×Ñ×!Ñ!Ü�I˜~¬t°I«Ó?ô	
ð "ŸZ™ZÐ3ˆt�zŠz¼×9MÑ9MÓ9OˆØÐð 	
ð%ó	
Ðð 	�‰�r   N©r   )
r   r   r   r   r   Úpropertyr&   r)   r,   r6   r   r   r   r   r   O   s>   „ ñóð ñó ðð
 ñ)ó ð)òór   r   c              #  ó�  ‡‡‡‡K  — t        | «      Št        j                  j                  }|j                  Š|j
                  Šˆfd„Šˆˆfd„}ˆˆfd„}t        j                  j                  |d|«      5  t        j                  j                  |d|«      5  ‰–— ddd«       ddd«       y# 1 sw Y   ŒxY w# 1 sw Y   yxY w­w)zlCount the await points performed within the block, cancelling the
    running task at each of ``cancel_at``.c                ó8   •— | j                   r|S t        |‰«      S r   )Údeadr	   )ÚgreenletÚresultÚpointss     €r   Ú
instrumentz await_points.<locals>.instrument—   s   ø€ ð �=Š=ØˆMÜ% f¨fÓ5Ð5r   c                ó*   •—  ‰|  ‰| g|¢­i |¤Ž«      S r   r   )r   ÚargÚkwr?   Úreal_switchs      €€r   Úswitchzawait_points.<locals>.switchž   s   ø€ Ù˜$¡¨DÐ =°3Ò =¸"Ñ =Ó>Ð>r   c                ó$   •—  ‰|  ‰| g|¢­Ž «      S r   r   )r   rA   r?   Ú
real_throws     €€r   Úthrowzawait_points.<locals>.throw¡   s   ø€ Ù˜$¡
¨4Ð 6°#Ò 6Ó7Ð7r   rD   rG   N)	r   r   Ú_concurrency_shimÚ_AsyncIoGreenletrD   rG   r   ÚpatchÚobject)r$   Úgreenlet_clsrD   rG   r?   r>   rC   rF   s       @@@@r   Úawait_pointsrM   �   s§   ûè ø€ ô
 ˜Ó#€FÜ×0Ñ0×AÑA€LØ×%Ñ%€KØ×#Ñ#€Jô6õ?õ8ô 	�
‰
×Ñ˜,¨°&Ó9ñä�
‰
×Ñ˜,¨°Ó7ñð Š÷	÷ ÷ ñ ú÷ ð üs6   †A0CÁ6"B:ÂB.ÂB:Â%	CÂ.B7	Â3B:Â:CÂ?Cc                  ót   — e Zd ZdZd„ Zej                  d„ «       Zd„ Zddœd„Z	e
d„ «       Zd	„ Zd
„ Zd„ Zd„ Zy)ÚConnectionAccountingaà  Records which DBAPI connections a pool created and which it managed
    to close, how many of the pool's slots were lost, and whether the pool
    could still be used afterwards.

    Creation is observed at ``Pool._invoke_creator`` rather than through the
    ``connect`` pool event, because the ``connect`` event is itself where
    ``dialect.initialize()`` runs; a listener added there does not fire for
    precisely the connections that a failure in that event strands.

    c                ó¼   — || _         |j                  | _        |j                  | _        d| _        d | _        d | _        t        «       | _	        t        «       | _
        y r   )Ú_poolÚ_invoke_creatorÚ_real_invoke_creatorÚ_close_connectionÚ_real_close_connectionÚ_lost_slotsÚ_next_use_errorÚ_uncancelled_outcomeÚsetÚ_createdÚ_closed)r   Úpools     r   r   zConnectionAccounting.__init__·   sO   € ØˆŒ
Ø$(×$8Ñ$8ˆÔ!Ø&*×&<Ñ&<ˆÔ#ØˆÔØ#ˆÔØ$(ˆÔ!Ü›ˆŒÜ“uˆ�r   c              #  ó<  K  — t         j                  j                  | j                  d| j                  «      5  t         j                  j                  | j                  d| j
                  «      5  | –— ddd«       ddd«       y# 1 sw Y   ŒxY w# 1 sw Y   yxY w­w)z4Account for the pool's connections within the block.rR   rT   N)r   rJ   rK   rQ   rR   rT   r   s    r   ÚstartzConnectionAccounting.startÁ   s‚   è ø€ ô
 �J‰J×ÑØ—
‘
Ð-¨t×/CÑ/Cóñ	ô �J‰J×ÑØ—
‘
Ð/°×1GÑ1Góñ		ð ŠJ÷	÷ 	÷ 	ñ 	ú÷ 	ð 	üs4   ‚6B¸6BÁ.BÁ3BÁ;	BÂB	Â	BÂBÂBc                ó^   — | j                  |«      }| j                  j                  |«       |S r   )rS   rZ   Úadd)r   ÚrecÚdbapi_connections      r   rR   z$ConnectionAccounting._invoke_creatorÏ   s,   € Ø×4Ñ4°SÓ9ÐØ�‰×ÑÐ*Ô+ØÐr   F©Ú	terminatec               ó  — 	 | j                  ||¬«       | j                  j                  |«       y # t        j                  $ r? |r;| j                  j                  j
                  r| j                  j                  |«       ‚ w xY w)Nrc   )rU   r+   ÚCancelledErrorrQ   Ú_dialectÚhas_terminater[   r`   )r   rb   rd   s      r   rT   z&ConnectionAccounting._close_connectionÔ   st   € ð	Ø×'Ñ'Ð(8ÀIÐ'ÔNð 	�‰×ÑÐ)Õ*øô ×%Ñ%ò 	ñ ˜TŸZ™Z×0Ñ0×>Ò>Ø—‘× Ñ Ð!1Ô2Øð	ús
   ‚1 ±ABc                ó4   — | j                   | j                  z
  S )z<Connections that were created but never successfully closed.)rZ   r[   r   s    r   ÚleakedzConnectionAccounting.leakedß   s   € ð �}‰}˜tŸ|™|Ñ+Ð+r   c                ó˜   — |r|j                  «       ry|j                  «       }|�dt        |«      j                  › �| _        yd| _        y)a  Record whether a cancellation delivered to ``task`` ended it.

        To be called once ``task`` is done.  ``cancelled_at`` is
        :attr:`.AwaitPoints.cancelled_at`; if it is empty, nothing was
        cancelled and there is nothing to record.

        Nzraised zreturned normally)Ú	cancelledÚ	exceptionÚtyper   rX   )r   r5   r)   Úerrs       r   Úrecord_cancellationz(ConnectionAccounting.record_cancellationå   sF   € ñ ˜tŸ~™~Ô/Øà�n‰nÓˆØˆ?Ø*1´$°s³)×2DÑ2DÐ1EÐ(FˆDÕ%à(;ˆDÕ%r   c                ój   — t        j                  «        | j                  j                  «       | _        y)a`  Record the pool slots still checked out.

        To be called once the application's task is done, and before the
        engine is disposed.  Every :class:`._ConnectionFairy` the task made
        is gone once garbage is collected, and :func:`._finalize_fairy` has
        returned its record; a record still checked out after that is lost.

        N)ÚgcÚcollectrQ   Ú
checkedoutrV   r   s    r   Úrecord_lost_slotsz&ConnectionAccounting.record_lost_slotsö   s"   € ô 	�
‰
ŒØŸ:™:×0Ñ0Ó2ˆÕr   c              ƒ  óŒ   K  — | j                   dkD  ry	  ||«      ƒ d{  –—†  y7 Œ# t        $ r}|| _        Y d}~yd}~ww xY w­w)aC  Run ``scenario`` once more, un-cancelled, and record what it
        raises, if anything.

        To be called once the application's task is done, and before the
        engine is disposed.  The application goes on using its engine after
        a cancellation, and whatever the pool hands out next has to work.

        r   N)rV   Ú	ExceptionrW   )r   ÚscenarioÚenginero   s       r   Úrecord_next_usez$ConnectionAccounting.record_next_use  sH   è ø€ ð ×Ñ˜aÒð ð	'Ù˜6Ó"×"Ò"ùÜò 	'Ø#&ˆD× Ñ ûð	'üs3   ‚A”' Ÿ% ' ¤A¥' §	A°<·A¼AÁAc                óÄ  — g }| j                   �|j                  d| j                   › �«       | j                  r=|j                  t        | j                  «      › dt        | j                  «      › d�«       | j
                  dkD  r|j                  | j
                  › d�«       | j                  �1|j                  dt        | j                  «      j                  › �«       |S )z˜Return a list of strings describing each leaked connection,
        lost pool slot and failed further use of the pool, empty if there
        were none.z)the cancelled task was not cancelled; it ú of z= connection(s) were left open with nothing able to close themr   zD pool slot(s) were left checked out with nothing able to return themz the next use of the pool raised )	rX   r0   rj   ÚlenrZ   rV   rW   rn   r   )r   Úfailuress     r   Úget_failure_messagesz)ConnectionAccounting.get_failure_messages  sç   € ð
 ˆØ×$Ñ$Ð0Ø�O‰OØ;Ø×,Ñ,Ð-ð/ôð �;Š;Ø�O‰OÜ�t—{‘{Ó#Ð$ D¬¨T¯]©]Ó);Ð(<ð =Að Aôð ×Ñ˜aÒØ�O‰OØ×#Ñ#Ð$ð %3ð 3ôð ×ÑÐ+Ø�O‰OØ2Ü˜×,Ñ,Ó-×6Ñ6Ð7ð9ôð ˆr   N)r   r   r   r   r   Ú
contextlibÚcontextmanagerr^   rR   rT   r8   rj   rp   ru   rz   r   r   r   r   rO   rO   «   s_   „ ñ	òð ×Ññó ðò ð
 @Eô 	+ð ñ,ó ð,ò
<ò"
3ò'ó&r   rO   c                óH   — t        | j                  «      j                  «       S )z�Account for the DBAPI connections created by ``engine``'s pool.

    Returns a context manager yielding a :class:`.ConnectionAccounting`.

    )rO   r\   r^   )ry   s    r   Úconnection_accountingrƒ   2  s   € ô   §¡Ó,×2Ñ2Ó4Ð4r   c              ƒ  óš  K  — |s	|rJ d«       ‚ | «       }t        |«      5 }|r- ||«      ƒ d{  –—†  |r|j                  j                  d«       t        |«      5 }|j	                   ||«      «      }	 |ƒ d{  –—†  ddd«       |j                  j                  «       |j                  «        |j                  ||«      ƒ d{  –—†  	 |j                  «       ƒ d{  –—†  t        j                  «       t        j                  «       hz
  }	|	rt        j                   |	d¬«      ƒ d{  –—†  t#        j$                  «        ddd«       dj'                  j)                  «       «      xs dfS 7 �ŒC7 Œú# t
        $ r |j                  s‚ Y �Œw xY w# 1 sw Y   �ŒxY w7 ŒØ7 ŒÁ# t        j                  $ r Y ŒÔw xY w7 Œ‘# 1 sw Y   Œ|xY w­w)aþ  Run ``scenario`` against a fresh engine, optionally cancelling it.

    ``engine_factory`` is a zero-argument callable returning a new
    :class:`_asyncio.AsyncEngine`; ``scenario`` is a coroutine function
    taking that engine.  If ``warm`` is True the scenario is run once
    un-cancelled first, so that the await points counted are those of
    checkout, execution and return-to-pool rather than those of
    ``connect()``.  If ``recycle`` is also True, the warmed pool is then
    invalidated, so that the checkout counted closes the old connection
    before opening its replacement.

    Returns the :class:`.AwaitPoints` for the run, and a description of
    what the cancellation cost the pool or the application, or ``None`` if
    it cost nothing.

    zrecycle requires 'warm'Né   )Útimeoutz; )rƒ   r\   Ú_invalidaterM   r,   ÚBaseExceptionr)   rp   ru   rz   Údisposer   ÚSQLAlchemyErrorr+   Ú	all_tasksr3   Úwaitrr   rs   Újoinr   )
Úengine_factoryrx   r$   ÚwarmÚrecyclery   Ú
accountingr>   r5   Úotherss
             r   Úrun_scenarior“   ;  s¹  è ø€ ñ& ‘wÐ9Ð 9Ó9ÐáÓ€FÜ	˜vÓ	&ð /¨*ÙÙ˜6Ó"×"Ð"ÙØ—‘×'Ñ'¨Ô-ä˜)Ó$ð 	¨Ø×%Ñ%¡h¨vÓ&6Ó7ˆDðØ—
�
÷	ð& 	×&Ñ& t¨V×-@Ñ-@ÔAð 	×$Ñ$Ô&ð ×(Ñ(¨°6Ó:×:Ð:ð	Ø—.‘.Ó"×"Ð"ô ×"Ñ"Ó$¬×(<Ñ(<Ó(>Ð'?Ñ?ˆÙÜ—,‘,˜v¨qÔ1×1Ð1Ü
�
‰
Œ÷_/ðb �4—9‘9˜Z×<Ñ<Ó>Ó?ÒGÀ4ÐGÐGð_ #ùð ùÜ ò ð ×*Ò*Øò +ðú÷		ñ 	úð2 	;øð #ùÜ×"Ñ"ò 	ñ ð	úð 2ø÷]/ð /üsÄ   ‚G F?®E1¯,F?ÁFÁ4E6Á9E4Á:E6Á>A	F?ÃF ÃF?ÃF$Ã F"Ã!F$Ã%AF?Ä+F=Ä,F?Å-GÅ1F?Å4E6Å6FÆFÆFÆFÆF	Æ	F?Æ"F$Æ$F:Æ7F?Æ9F:Æ:F?Æ?GÇGc              ƒ  óZ   ‡ ‡‡‡‡‡‡K  — g Šˆˆˆ ˆˆˆˆfd„Š ‰d«      ƒ d{  –—†  ‰S 7 Œ­w)a  Cancel ``scenario`` at each of its await points in turn.

    With ``cancels=2``, each run that was cancelled at point ``N`` is then
    repeated with a second cancellation at each await point after ``N``,
    which is to say at each point of the cleanup the first cancellation
    set off.

    Returns a list of strings describing what went wrong, empty if every
    cancellation point was handled cleanly.  The strings are meant to be
    read in an assertion failure::

        eq_(await sweep(engine_factory, scenario), [])

    c              “  óÞ  •K  — t        ‰‰| ‰‰¬«      ƒ d {  –—† \  }}|j                  }| r| d   dz   nd}t        ||dz   «      D ]�  }t        ‰‰| |fz   ‰‰¬«      ƒ d {  –—† \  }}|�Tdj                  d„ | |fz   D «       «      }dj                  |j                  «      }‰j                  d|› d|› d|› d	|› �«       t        | «      dz   ‰
k  sŒŠ ‰	| |fz   «      ƒ d {  –—†  ŒŸ y 7 ŒÏ7 Œˆ7 Œ­w)
N)r$   r�   r�   éÿÿÿÿr/   z, c              3  ó2   K  — | ]  }t        |«      –— Œ y ­wr   )Ústr)Ú.0Úis     r   ú	<genexpr>z(sweep.<locals>._sweep.<locals>.<genexpr>¬  s   è ø€ Ò#I¨q¤C¨§FÑ#Iùs   ‚zcancel at await point(s) r|   z (z): )r“   r&   Úranger�   r)   r0   r}   )r$   r>   Ú_Útotalr^   ÚindexÚfailureÚindexesÚ
awaitablesÚ_sweepÚcancelsrŽ   r�   Úreportedrx   r�   s            €€€€€€€r   r£   zsweep.<locals>._sweep™  s(  øè ø€ Ü&ØØØØØô
÷ 
‰	ˆ�ð —‘ˆÙ%.�	˜"‘ Ò!°AˆÜ˜5 %¨!¡)Ó,ò 	3ˆEÜ$0ØØØ# u hÑ.ØØô%÷ ‰OˆF�Gð Ð"ØŸ)™)Ñ#I°IÀÀÑ4HÔ#IÓI�Ø!ŸY™Y v×':Ñ':Ó;�
Ø—‘Ø/°¨y¸¸U¸Gð DØ"�| 3 w ið1ôô �9‹~ Ñ! GÓ+Ù˜Y¨%¨Ñ1Ó2×2Ñ2ñ!	3ð
øðøð 3ús;   ƒC-—C'˜AC-Á C)Á!A.C-ÃC-ÃC+Ã C-Ã)C-Ã+C-r   Nr   )rŽ   rx   r�   r�   r¤   r£   r¥   s   `````@@r   Úsweepr¦   …  s1   þè ø€ ð$ €H÷3ò 3ñ8 �‹*×ÐØ€Oð ús   ‰+¢)£+r7   )r   FF)FFr/   )r   Ú
__future__r   r+   r€   rr   Úunittestr   Ú r   Úutilr   r	   r   r�   rM   rO   rƒ   r“   r¦   r   r   r   ú<module>r«      s~   ðñ+õZ #ã Û Û 	Ý å Ý ÷*ñ *÷;ñ ;ð| ×Ñòó ð÷:Dñ DòN5ð AFóGHðV BCô1r   