+
    }¯³jU   ã                  ó
  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^RIH	t	 ^RI
Ht ]'       d   ^RIHt  ! R R4      t ! R	 R
4      t]P                   RR l4       t ! R R4      t]P                   R 4       tRR ltRR ltR# )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.

What is asserted afterwards is that nothing was leaked: every DBAPI
connection a pool creates must eventually be passed successfully through
``Pool._close_connection()``.  A connection that isn't has become
unreachable, and for an asyncio driver the garbage collector cannot close
it either, since closing needs the event loop.

Pool *availability* is deliberately not asserted.  A cancellation can leave
a record checked out until the ``_ConnectionFairy`` is collected and
``_finalize_fairy()`` hands it back, so what the pool has available
immediately afterwards is a function of garbage collection timing rather
than of anything the dialect did.

)ÚannotationsN)Úmock)Úexc)Úhave_greenlet)Ú_AsyncIoGreenletc                  ó*   € ] tR t^/tRtRtR tR tRtR# )Ú_InstrumentedAwaitablez6An awaitable that invokes ``hook`` when it is awaited.c                	ó   € Wn         W n        R # ©N©Ú	awaitableÚhook)Úselfr   r   s   &&&Ú`/home/luca/screen-checking/.venv/lib/python3.14/site-packages/sqlalchemy/testing/cancellation.pyÚ__init__Ú_InstrumentedAwaitable.__init__4   s   € Ø"ŒØŽ	ó    c                	ól   € V P                  V P                  4       V P                  P                  4       # r
   )r   r   Ú	__await__©r   s   &r   r   Ú _InstrumentedAwaitable.__await__8   s%   € Ø�	‰	�$—.‘.Ô!Ø�~‰~×'Ñ'Ó)Ð)r   r   N)	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú	__slots__r   r   Ú__static_attributes__© r   r   r   r   /   s   † Ù@à%€Iòö*r   r   c                  ó*   € ] tR t^=tRtRR ltR tRtR# )ÚAwaitPointszACounts await points, and cancels the running task at one of them.Nc                	ó.   € ^ V n         Wn        RV n        R# )é    N)ÚcountÚ	cancel_atÚcancelled_at)r   r$   s   &&r   r   ÚAwaitPoints.__init__@   s   € ØˆŒ
Ø"ŒØ ˆÖr   c                	ó  € V ;P                   ^,          un         V P                   V P                  8w  d   R# \        VR\        V4      4      V n        \
        P                  ! 4       pVf   Q R4       hVP                  4        R# )é   Nr   zQcancellation can only be delivered to an operation running within an asyncio task)r#   r$   ÚgetattrÚreprr%   ÚasyncioÚcurrent_taskÚcancel)r   r   Útasks   && r   Ú__call__ÚAwaitPoints.__call__E   sh   € Ø�
Š
�a��
Ø�:‰:˜Ÿ™Ô'Ùä# I¨~¼tÀI»ÓOˆÔä×#Ò#Ó%ˆØÒð 	
ð%ó	
Ðð 	�‰Žr   )r$   r%   r#   r
   )r   r   r   r   r   r   r/   r   r   r   r   r    r    =   s   † ÙKô!ö
r   r    c           	   #  óÂ  aaaa"  € \        V 4      o\        P                  o\        P                  oV3R loVV3R lpVV3R lp\        P
                  P                  \        RV4      ;_uu_ 4        \        P
                  P                  \        RV4      ;_uu_ 4        Sx € RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i5i)ziCount the await points performed within the block, cancelling the
running task at ``cancel_at`` if given.c                óD   <€ V P                   '       d   V# \        VS4      # r
   )Údeadr   )ÚgreenletÚresultÚpointss   &&€r   Ú
instrumentÚ await_points.<locals>.instrumenta   s    ø€ ð �=�=ˆ=ØˆMÜ% f¨fÓ5Ð5r   c                ó*   <€ S! V S! V .VO5/ VB 4      # r
   r   )r   ÚargÚkwr7   Úreal_switchs   &*,€€r   ÚswitchÚawait_points.<locals>.switchh   s   ø€ Ù˜$¡¨DÐ =°3Ò =¸"Ñ =Ó>Ð>r   c                ó&   <€ S! V S! V .VO5!  4      # r
   r   )r   r:   r7   Ú
real_throws   &*€€r   ÚthrowÚawait_points.<locals>.throwk   s   ø€ Ù˜$¡
¨4Ð 6°#Ó 6Ó7Ð7r   r=   rA   N)r    r   r=   rA   r   ÚpatchÚobject)r$   r=   rA   r7   r6   r<   r@   s   &  @@@@r   Úawait_pointsrE   X   s›   ûé € ô
 ˜Ó#€FÜ"×)Ñ)€KÜ!×'Ñ'€Jõ6ö?ö8ô 
�‰×	Ñ	Ü˜( F÷
õ 
ä‡z�z×ÑÔ)¨7°E×:Õ:ØŠ÷ ;÷
ñ 
ç:×:ú÷
÷ 
ð 
üs6   †A-CÁ3.CÂ!B8	Â&CÂ.
CÂ8CÃCÃC	Ã	Cc                  ó0   € ] tR t^ttRtR t]R 4       tRtR# )ÚConnectionAccountingzMRecords which DBAPI connections a pool created and which it managed
to close.c                	óB   € \        4       V n        \        4       V n        R # r
   )ÚsetÚcreatedÚclosedr   s   &r   r   ÚConnectionAccounting.__init__x   s   € Ü“uˆŒÜ“eˆŽr   c                ó<   € V P                   V P                  ,
          # )z<Connections that were created but never successfully closed.)rJ   rK   r   s   &r   ÚleakedÚConnectionAccounting.leaked|   s   € ð �|‰|˜dŸk™kÕ)Ð)r   )rK   rJ   N)	r   r   r   r   r   r   ÚpropertyrN   r   r   r   r   rG   rG   t   s    † ñòð ñ*ó ô*r   rG   c           	   #  ó²  aaa"  € \        4       oV P                  pVP                  oVP                  oVV3R lpRR/VV3R llp\        P
                  P                  VRV4      ;_uu_ 4        \        P
                  P                  VRV4      ;_uu_ 4        Sx € RRR4       RRR4       R#   + '       g   i     L; i  + '       g   i     R# ; i5i)aY  Account for the DBAPI connections created by ``engine``'s pool.

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                óN   <€ S! V 4      pSP                   P                  V4       V# r
   )rJ   Úadd)ÚrecÚdbapi_connectionÚ
accountingÚreal_creators   & €€r   Ú_invoke_creatorÚ.connection_accounting.<locals>._invoke_creator’   s)   ø€ Ù'¨Ó,ÐØ×Ñ×ÑÐ/Ô0ØÐr   Ú	terminateFc               óP   <€ S! WR 7       SP                   P                  V 4       R# ))rZ   N)rK   rS   )rU   rZ   rV   Ú
real_closes   &$€€r   Ú_close_connectionÚ0connection_accounting.<locals>._close_connection—   s!   ø€ ÙÐ#Õ9Ø×Ñ×ÑÐ.Ö/r   rX   r]   N)rG   ÚpoolrX   r]   r   rC   rD   )Úenginer_   rX   r]   rV   r\   rW   s   &   @@@r   Úconnection_accountingra   ƒ   s­   úé € ô &Ó'€JØ�;‰;€DØ×'Ñ'€LØ×'Ñ'€Jö ð
0¸÷ 0ð 0ô 
�‰×	Ñ	ØÐ ÷
õ 
ä‡z�z×Ñ˜Ð2Ð4E×FÕFØÒ÷ G÷
ñ 
çF×Fú÷
÷ 
ð 
üs6   …A*CÁ/*CÂB0	ÂCÂ&
CÂ0C Â;CÃC	Ã	Cc           	   ƒ  óÚ  "  € V ! 4       p\        V4      ;_uu_ 4       pV'       d   V! V4      G Rj  x€L
  \        V4      ;_uu_ 4       p \        P                  ! V! V4      4      G Rj  x€L
  RRR4       \        P                  ! 4         VP                  4       G Rj  x€L
  VP                  '       d>   XR\        VP                  4      \        VP                  4      3,          3uuRRR4       #  RRR4       XR3#  LÏ L˜  \         d    TP
                  f   h  L²i ; i  + '       g   i     L¾; i L—  \        P                   d     L¬i ; i  + '       g   i     XR3# ; i5i)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()``.

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

NzE%d of %d connection(s) were left open with nothing able to close them)ra   rE   r+   Úcreate_taskÚBaseExceptionr%   ÚgcÚcollectÚdisposer   ÚSQLAlchemyErrorrN   ÚlenrJ   )Úengine_factoryÚscenarior$   Úwarmr`   rV   r6   s   &&&&   r   Úrun_scenariorm   ¡   sH  é € ñ Ó€FÜ	˜v×	&Ô	&¨*ßÙ˜6Ó"×"Ð"ä˜)×$Ô$¨ðÜ×)Ò)©(°6Ó*:Ó;×;Ð;÷ %ô  	�
Š
Œð	Ø—.‘.Ó"×"Ð"ð ××ÐØð ä�z×(Ñ(Ó)¬3¨z×/AÑ/AÓ+BÐCõDð÷; 
'Ò	&ð8 ÷9 
'ðF �4ˆ<ÐñC #ñ <øÜ ô ð ×&Ñ&Ò.Øñ /ðú÷ %×$úñ$ #øÜ×"Ñ"ô 	ñ ð	ú÷/ 
'Ö	&ðF �4ˆ<Ðüs¶   ‚E+�E±D²EÁ	D%	ÁDÁ*DÁ+DÁ/EÂD:Â D8Â!D:Â%EÂ72EÃ)E+Ã5E+ÄEÄDÄD"ÄD%	Ä!D"Ä"D%	Ä%D5Ä0EÄ8D:Ä:EÅEÅEÅEÅE(	Å E+c              ƒ  ó  "  € \        WVR7      G Rj  x€L
 w  r4VP                  p. p\        ^V^,           4       FE  p\        WWrR7      G Rj  x€L
 w  r8Vf   K   VP                  RWuVP                  V3,          4       KG  	  V#  Lr L95i)a  Cancel ``scenario`` at each of its await points in turn.

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), [])

)rl   N)r$   rl   z'cancel at await point %d of %d (%s): %s)rm   r#   ÚrangeÚappendr%   )	rj   rk   rl   r6   Ú_ÚtotalÚreportedÚindexÚfailures	   &&&      r   Úsweeprv   Ö   s�   é € ô # >À$ÔG×G�I€FØ�L‰L€Eà€HÜ�q˜% !�)Ö$ˆÜ ,Ø°ô!
÷ 
‰ˆð ÔØ�O‰OØ9Ø ×!4Ñ!4°gÐ>õ?öñ %ð €Oñ Hñ

ùs'   ‚B
“B”:B
ÁBÁB
Á,B
ÂB
r
   )NF)F)r   Ú
__future__r   r+   Ú
contextlibre   Úunittestr   Ú r   Úutil.concurrencyr   Úutil._concurrency_py3kr   r   r    ÚcontextmanagerrE   rG   ra   rm   rv   r   r   r   Ú<module>r~      s„   ðñõ0 #ã Û Û 	Ý å Ý ,çÝ9÷*ñ *÷ñ ð6 ×Ñóó ð÷6*ñ *ð ×Ññó ðô:2öjr   