+
    wi0@                        ^ RI t ^ RIt^ RIt^ RIt^ RIHtHt ^ RIHtHt ^ RI	H
t
HtHtHtHtHtHtHtHtHt ^ RIt^ RIHt ^ RIHt ^ RIHt ^ RIHt ^ R	IHtHtH t H!t! ^ R
I"H#t#H$t$ ]PJ                  ! ]&4      t'] ! R R4      4       t(]PR                  ! 4       t*R R lt+R t,R R lt-R R lt. ! R R]/4      t0 ! R R4      t1 ^ RI2H3t3 ]3Ph                  ]1n5        ]1Ph                  ]3n4        ]]8]9]:]#]
3,          t;]];,          t<]];,          t=]]=]<3,          t> ! R R]4      t?R#   ]6 d    ]'Po                  R4        LRi ; i)    N)	dataclassfield)datetimetimezone)
AnyAsyncIterable	AwaitableCallable	CoroutineIteratorMappingOptionalSetUnion)BackgroundTask)iterate_in_threadpool)MutableHeaders)Response)ReceiveScopeSendMessage)ServerSentEventensure_bytesc                   F   a  ] tR t^!t o Rt]! ]R7      tRtV 3R lt	Rt
V tR# )_ShutdownStatezPer-thread state for shutdown coordination.

Issue #152 fix: Uses threading.local() instead of ContextVar to ensure
one watcher per thread rather than one per async context.
)default_factoryFc                V   < V ^8  d   Qh/ S[ S[P                  ,          ;R&   S[;R&   # )   eventswatcher_started)r   anyioEventbool)format__classdict__s   "E/home/ubuntu/.local/lib/python3.14/site-packages/sse_starlette/sse.py__annotate___ShutdownState.__annotate__!   s(      9  !      N)__name__
__module____qualname____firstlineno____doc__r   setr    r!   __annotate_func____static_attributes____classdictcell__r&   s   @r'   r   r   !   s"       %S9F!O  r*   r   c                $    V ^8  d   QhR\         /# r   return)r   )r%   s   "r'   r(   r(   1   s      ^ r*   c                 Z    \        \        RR4      p V f   \        4       p V \        n        V # )z4Get or create shutdown state for the current thread.shutdown_stateN)getattr_thread_stater   r:   )states    r'   _get_shutdown_stater>   1   s+    M#3T:E} ',$Lr*   c                      \         P                  ! \         P                  4      p \        V R4      '       d!   V P                  p\        VR4      '       d   V# R#   \
         d     R# i ; i)aM  
Try to get uvicorn Server instance via signal handler introspection.

When uvicorn registers signal handlers, they're bound methods on the Server instance.
We can retrieve the Server from the handler's __self__ attribute.

Returns None if:
- Not running under uvicorn
- Signal handler isn't a bound method
- Any introspection fails
__self__should_exitN)signal	getsignalSIGTERMhasattrr@   	Exception)handlerservers     r'   _get_uvicorn_serverrI   :   sa    ""6>>27J''%%Fv}--   s   AA A)(A)c                    V ^8  d   QhRR/# r   r8   Nr+   )r%   s   "r'   r(   r(   Q   s     !& !& !&r*   c                   "   \        4       p \        4       p  \        P                  '       d   MX\        P                  '       d#   Ve   VP                  '       d   R\        n        M \
        P                  ! R4      G Rj  xL
  Kp  \        V P                  4       F  pVP                  4        K  	  RV n
        R#  L;  RT n
        i ; i5i)aO  
Poll for shutdown and broadcast to all events in this context.

One watcher runs per thread (event loop). Checks two shutdown sources:
1. AppStatus.should_exit - set when our monkey-patch works
2. uvicorn Server.should_exit - via signal handler introspection (Issue #132 fix)

When either becomes True, signals all registered events.
TNg      ?F)r>   rI   	AppStatusrA   enable_automatic_graceful_drainr"   sleeplistr    r1   r!   )r=   uvicorn_serverevents      r'   _shutdown_watcherrS   Q   s       !E(*N&$$$ 999"."...(,	%++c""" %,,'EIIK ( !& # !&s?   CB? B? B? %B? B=2B? 4	C=B? ?	CCc                    V ^8  d   QhRR/# rK   r+   )r%   s   "r'   r(   r(   u   s     
* 
*d 
*r*   c                     \        4       p V P                  '       g9   RV n         \        P                  ! 4       pVP	                  \        4       4       R# R#   \         d    RT n         R# i ; i)zDEnsure the shutdown watcher is running for this thread (event loop).TFN)r>   r!   asyncioget_running_loopcreate_taskrS   RuntimeError)r=   loops     r'   $_ensure_watcher_started_on_this_loopr[   u   sa    !E    $	*++-D.01	 !
  	*$)E!	*s   .A A-,A-c                       ] tR t^tRtR# )SendTimeoutErrorr+   N)r,   r-   r.   r/   r3   r+   r*   r'   r]   r]      s    r*   r]   c                   l   a  ] tR t^t o RtRtRtRt]R 4       t	]R 4       t
]R 4       tV 3R ltR	tV tR# )
rM   z\Helper to capture a shutdown signal from Uvicorn so we can gracefully terminate SSE streams.FTNc                     R\         n        R# )a  
Prevent automatic SSE stream termination on server shutdown.

WARNING: When disabled, you MUST set AppStatus.should_exit = True
at some point during shutdown, or streams will never close and the
server will hang indefinitely (or until uvicorn's graceful shutdown
timeout expires).
FNrM   rN   r+   r*   r'    disable_automatic_graceful_drain*AppStatus.disable_automatic_graceful_drain   s     5:	1r*   c                     R\         n        R# )z
Re-enable automatic SSE stream termination on server shutdown.

This restores the default behavior where SIGTERM triggers immediate
stream draining. Call this to undo a previous call to
disable_automatic_graceful_drain().
TNr`   r+   r*   r'   $enable_automatic_graceful_drain_mode.AppStatus.enable_automatic_graceful_drain_mode   s     59	1r*   c                     \         P                  '       d   R \         n        \         P                  e   \         P                  ! V / VB  R# R# )TN)rM   rN   rA   original_handler)argskwargss   *,r'   handle_exitAppStatus.handle_exit   s:    444$(I!%%1&&77 2r*   c                6   < V ^8  d   Qh/ S[ S[,          ;R&   # )r   rg   )r   r
   )r%   r&   s   "r'   r(   AppStatus.__annotate__   s     
 x(/ r*   r+   )r,   r-   r.   r/   r0   rA   rN   rg   staticmethodra   rd   rj   r2   r3   r4   r5   s   @r'   rM   rM      sZ     fK&*#+/	: 	: 9 9 8 8?  r*   rM   )ServerzHUvicorn not installed. Graceful shutdown on server termination disabled.c                     a  ] tR t^t o Rt^tRtRV 3R lR llt]V 3R lR l4       t	]	P                  V 3R lR	 l4       t	RV 3R
 lR lltV 3R lR ltV 3R lR lt]V 3R lR l4       tV 3R lR ltV 3R lR ltV 3R lR ltRtV tR# )EventSourceResponsea  Streaming response implementing the SSE (Server-Sent Events) specification.

Args:
    content: Async iterable or sync iterator yielding SSE event data.
    status_code: HTTP status code. Default: 200.
    headers: Additional HTTP headers.
    media_type: Response media type. Default: "text/event-stream".
    background: Background task to run after response completes.
    ping: Ping interval in seconds (0 to disable). Default: 15.
    sep: Line separator for SSE messages ("\r\n", "\r", or "\n").
    ping_message_factory: Callable returning custom ping ServerSentEvent.
    data_sender_callable: Async callable for push-based data sending.
    send_timeout: Timeout in seconds for individual send operations.
    client_close_handler_callable: Async callback on client disconnect.
    shutdown_event: Optional ``anyio.Event`` set by the library when server
        shutdown is detected. Generators can watch this event to send farewell
        messages and exit cooperatively instead of receiving CancelledError.
    shutdown_grace_period: Seconds to wait after setting ``shutdown_event``
        before force-cancelling the generator. Must be >= 0. Should be less
        than your ASGI server's graceful shutdown timeout. Default: 0
        (immediate cancel, identical to pre-v3.3.0 behavior).

Nc                  < V ^8  d   QhRS[ RS[RS[S[S[S[3,          ,          RS[RS[S[,          RS[S[,          RS[S[,          RS[S[. S[3,          ,          R	S[S[. S[R,          3,          ,          RS[S[	,          RS[S[S[
.S[R
,          3,          ,          RS[S[P                  ,          RS[	RR
/# )r   contentstatus_codeheaders
media_type
backgroundpingsepping_message_factorydata_sender_callableNsend_timeoutclient_close_handler_callableshutdown_eventshutdown_grace_periodr8   )NNN)ContentStreamintr   r   strr   r
   r   r   floatr   r	   r"   r#   )r%   r&   s   "r'   r(    EventSourceResponse.__annotate__   s    G' G'G' G' '#s(+,	G'
 G' ^,G' smG' c]G' 'xO0C'DEG' 'R#3445
G' uoG' (0gY	$/0(
G'" !-#G'$  %%G'& 
'G'r*   c                z   VR
9  d   \        RV 24      hT;'       g    V P                  V n        \        V\        4      '       d   Wn        M\        V4      V n        W n        Vf   V P                  MTV n        WPn	        Wn
        Wn        \        4       pVe   VP                  V4       VP                  RR4       RVR&   RVR&   V P                  V4       Vf   V P                   MTV n        Wn        Wn        V^ 8  d   \        R4      hWn        Wn        R	V n        \.        P0                  ! 4       V n        R # )Nz'sep must be one of: \r\n, \r, \n, got: zCache-Controlzno-storez
keep-alive
ConnectionnozX-Accel-Bufferingz"shutdown_grace_period must be >= 0T)Nrr   
)
ValueErrorDEFAULT_SEPARATORrz   
isinstancer   body_iteratorr   ru   rw   rx   r|   r}   r   update
setdefaultinit_headersDEFAULT_PING_INTERVALping_intervalr{   r~   _shutdown_event_shutdown_grace_periodactiver"   Lock
_send_lock)selfrt   ru   rv   rw   rx   ry   rz   r{   r|   r}   r~   r   r   _headerss   &&&&&&&&&&&&&& r'   __init__EventSourceResponse.__init__   s'   * 00J3%PQQ00$00 g}--!(!6w!?D&-7-?$//Z$$8!( "#OOG$ 	OZ8!-(,$%(#;?<T77T$8!-J* !1$ABB-&;#**,r*   c                6   < V ^8  d   QhRS[ S[S[3,          /# r7   r   r   r   )r%   r&   s   "r'   r(   r   !  s     # #uS%Z0 #r*   c                    V P                   # N)_ping_intervalr   s   &r'   r   !EventSourceResponse.ping_interval   s    """r*   c                :   < V ^8  d   QhRS[ S[S[3,          RR/# )r   valuer8   Nr   )r%   r&   s   "r'   r(   r   %  s$     $ $5e#4 $ $r*   c                    \        V\        \        34      '       g   \        R 4      hV^ 8  d   \	        R4      hWn        R# )zping interval must be intz$ping interval must be greater than 0N)r   r   r   	TypeErrorr   r   )r   r   s   &&r'   r   r   $  s8    %#u..78819CDD#r*   c                $   < V ^8  d   QhRS[ RR/# )r   forcer8   N)r$   )r%   r&   s   "r'   r(   r   ,  s     S S S Sr*   c                    \        R 4      h)z-Compression is not supported for SSE streams.)NotImplementedError)r   r   s   &&r'   enable_compression&EventSourceResponse.enable_compression,  s    !"QRRr*   c                $   < V ^8  d   QhRS[ RR/# r   sendr8   Nr   )r%   r&   s   "r'   r(   r   /  s     X X4 XD Xr*   c                "  "   V! RRRV P                   RV P                  /4      G Rj  xL
  V P                    Rj  xL
  p\        W P                  4      p\
        P                  RV4       \        P                  ! V P                  4      ;_uu_ 4       pV! RRRVR	R
/4      G Rj  xL
  RRR4       X'       g   K  VP                  '       g   K  \        V P                  RR4      pVe   V! 4       G Rj  xL
  \        4       h L L Lb  + '       g   i     Lh; i L'DT P                  ;_uu_4       GRj  xL 
  RT n        T! RRRRR	R/4      G Rj  xL 
  RRR4      GRj  xL 
  R#   + GRj  xL 
 '       g   i     R# ; i5i)zHSend out SSE data to the client as it becomes available in the iterator.typezhttp.response.startstatusrv   Nz	chunk: %shttp.response.bodybody	more_bodyTacloseFr*   )ru   raw_headersr   r   rz   loggerdebugr"   move_on_afterr}   cancel_calledr;   r]   r   r   )r   r   datachunkcancel_scoper   s   &&    r'   _stream_response$EventSourceResponse._stream_response/  sL    -$**4++
 	
 	
 ,, 	) 	)$ xx0ELLe,$$T%6%677<165+tT   8
 | : : : !3!3XtD% (NN&(()	
	) 87 # - ????DK 4fc;PUVWWW #?????s   &FDFD"D	D"AFD(D
)D-F?F%F8D 9F	D"DD	F"F;D><F E2EE2F*E-+F2F	8E;9
F	F		Fc                $   < V ^8  d   QhRS[ RR/# )r   receiver8   N)r   )r%   r&   s   "r'   r(   r   K  s     	 	G 	 	r*   c                
  "   V P                   '       di   V! 4       G Rj  xL
 pVR,          R8X  g   K1  RV n         \        P                  R4       V P                  '       d   V P                  V4      G Rj  xL
  R# R#  L_ L
5i)z/Watch for a disconnect message from the client.Nr   zhttp.disconnectFz+Got event: http.disconnect. Stop streaming.)r   r   r   r~   )r   r   messages   && r'   _listen_for_disconnect*EventSourceResponse._listen_for_disconnectK  si     kkk#IoGv"33#JK555<<WEEE %
 Fs1   B
BA?B-B"B6B7	BBc                   < V ^8  d   QhRR/# rK   r+   )r%   r&   s   "r'   r(   r   W  s     ( (4 (r*   c                   "   \         P                  '       d   R# \        4        \        4       p \        P
                  ! 4       pV P                  P                  V4        \         P                  '       d    V P                  P                  V4       R# VP                  4       G Rj  xL
  V P                  P                  V4       R#  L!  T P                  P                  T4       i ; i5i)z0Wait for shutdown signal via the shared watcher.N)
rM   rA   r[   r>   r"   r#   r    adddiscardwait)r=   rR   s     r'   _listen_for_exit_signal+EventSourceResponse._listen_for_exit_signalV  s         ,.#%	($$$ LL  ' **,LL  ' LL  's<   AC+ C 7C+C 'C	(C ,C+	C C((C+c                   < V ^8  d   QhRR/# rK   r+   )r%   r&   s   "r'   r(   r   j  s     + +$ +r*   c                  "   V P                  4       G Rj  xL
  V P                  '       d   V P                  P                  4        V P                  ^ 8  dg   \        P
                  ! V P                  4      ;_uu_ 4        V P                  '       d!   \        P                  ! R4      G Rj  xL
  K2   RRR4       R# R#  L L  + '       g   i     R# ; i5i)aV  Wait for shutdown signal, then optionally give generator a grace period.

Issue #167: When a shutdown_event is provided, the library sets it before
returning, giving the generator a chance to send farewell events and exit
cooperatively. The shutdown_grace_period controls how long to wait before
force-cancelling via task group cancellation.
Ng?)r   r   r1   r   r"   r   r   rO   r   s   &r'   "_listen_for_exit_signal_with_grace6EventSourceResponse._listen_for_exit_signal_with_gracej  s      **,,,   $$& &&*$$T%@%@AAkkk++c*** " BA + 	- + BAAsE   CC CAC CC,C-C4CCC		Cc                $   < V ^8  d   QhRS[ RR/# r   r   )r%   r&   s   "r'   r(   r   ~  s        r*   c           
       "   V P                   '       Ed
   \        P                  ! V P                  4      G Rj  xL
  V P                  '       d   V P	                  4       M;\        R\        P                  ! \        P                  4       2V P                  R7      p\        W P                  4      p\        P                  RV4       V P                  ;_uu_4       GRj  xL
  V P                   '       d   V! RRRVRR	/4      G Rj  xL
  RRR4      GRj  xL
  EK  R#  L LC L L  + GRj  xL 
 '       g   i     EKA  ; i5i)
zPeriodically send ping messages to keep the connection alive on proxies.
- frequenccy ca every 15 seconds.
- Alternatively one can send periodically a comment line (one starting with a ':' character)
Nzping - )commentrz   zping: %sr   r   r   r   T)r   r"   rO   r   r{   r   r   nowr   utcrz   r   r   r   r   )r   r   sse_ping
ping_bytess   &&  r'   _pingEventSourceResponse._ping~  s     
 kkk++d11222 ,,, ))+$%hll8<<&@%AB  &h9JLLZ0;;;"$8"J'   ' 2 ' 's{   E#ED!EBED# E#$D)D%D)ED'
E#E%D)'E)E	/D20
E	;E	=
Ec                0   < V ^8  d   QhRS[ RS[RS[RR/# )r   scoper   r   r8   N)r   r   r   )r%   r&   s   "r'   r(   r     s)     $ $E $G $4 $D $r*   c                D  a aaa"   \         P                  ! 4       ;_uu_4       GRj  xL
 oR V3R llpSP                  VV V3R l4       SP                  VV V3R l4       SP                  VS P                  4       S P                  '       d   SP                  S P                  4       SP                  VVV 3R l4       RRR4      GRj  xL
  S P
                  e   S P                  4       G Rj  xL
  R# R#  L L0  + GRj  xL 
 '       g   i     LG; i L(5i)zEntrypoint for Starlette's ASGI contract. We spin up tasks:
- _stream_response to push events
- _ping to keep the connection alive
- _listen_for_exit_signal to respond to server shutdown
- _listen_for_disconnect to respond to client disconnect
Nc                L    V ^8  d   QhR\         . \        R,          3,          /# )r   coroN)r
   r	   )r%   s   "r'   r(   2EventSourceResponse.__call__.<locals>.__annotate__  s!     1 1Xb)D/6I-J 1r*   c                 f   <"   V ! 4       G R j  xL
  SP                   P                  4        R #  L 5ir   )r   cancel)r   
task_groups   &r'   cancel_on_finish6EventSourceResponse.__call__.<locals>.cancel_on_finish  s&     f''..0 s   1/!1c                  &   < S P                  S4      # r   )r   r   r   s   r'   <lambda>.EventSourceResponse.__call__.<locals>.<lambda>  s    D<Q<QRV<Wr*   c                  &   < S P                  S4      # r   )r   r   s   r'   r   r     s    DJJt<Lr*   c                  &   < SP                  S 4      # r   )r   )r   r   s   r'   r   r     s    $*E*Eg*Nr*   )r"   create_task_group
start_soonr   r|   rx   )r   r   r   r   r   r   s   f&ff @r'   __call__EventSourceResponse.__call__  s      **,,,
1 1 !!"24WX!!"24LM!! $"I"I (((%%d&?&?@ !! "N! -,( ??&//### ') -,,,* $sW   "D C>D BDD D %D 5D6	D  D D	D	
D	D		D )r   r   r   r   r   rx   r   r~   r|   rw   r   r{   r}   rz   ru   )   Nztext/event-streamNNNNNNNNr   )F)r,   r-   r.   r/   r0   r   r   r   propertyr   setterr   r   r   rn   r   r   r   r   r3   r4   r5   s   @r'   rq   rq      s     . G' G'R # # $ $S SX X8	 	 ( (&+ +( 6$ $r*   rq   )@rV   loggingrB   	threadingdataclassesr   r   r   r   typingr   r   r	   r
   r   r   r   r   r   r   r"   starlette.backgroundr   starlette.concurrencyr   starlette.datastructuresr   starlette.responsesr   starlette.typesr   r   r   r   sse_starlette.eventr   r   	getLoggerr,   r   r   localr<   r>   rI   rS   r[   TimeoutErrorr]   rM   uvicorn.mainro   rj   rg   ImportErrorr   r   bytesdictContentSyncContentStreamAsyncContentStreamr   rq   r+   r*   r'   <module>r	     s5       ( '    / 7 3 ( 9 9 = 
		8	$ " " " !.!&H
*	| 	#8 #8L#!'!3!3I"..F UD/36
7W% "7+ (*;;<y$( y$  
LLRs   (D& &E E