ó
    °"³j˜*  ã                  óþ   • S SK Jr  S SKrS SKrS SKrS SKrS SKJrJ	r	  S SK
J
r
  S SKJr  S SKrSSKJr  Sr\R"                  " S	5      rS
rSSS jjrSSS jjr\ " S S5      5       r\ " S S5      5       r\" 5       rg)é    )ÚannotationsN)Ú	dataclassÚfield)Útime)ÚTracebackTypeé   )Údata_snapshot)ÚDEFAULT_UPDATE_URLÚUpdatePricesÚwait_prices_updated_syncÚwait_prices_updated_asynczgenai-priceszdhttps://raw.githubusercontent.com/pydantic/genai-prices/refs/heads/main/prices/new_data/v2/data.jsonc                ó¾   • [         R                     [         R                  S:X  a
   SSS5        g SSS5        [         R                  U 5      $ ! , (       d  f       N#= f)a  Wait for an update from the shared background task.

If the latest fetch failed, this raises its error while at least one instance is started.

Args:
    timeout: Maximum wait in seconds, or `None` to wait indefinitely.

Returns:
    True if prices were updated, False otherwise.
r   NF)Ú_shared_updaterÚlockÚ	ref_countÚwait©Útimeouts    ÚW/home/mande/repo/quber/.venv/lib/python3.13/site-packages/genai_prices/update_prices.pyr   r      sJ   € ô 
×	Ó	Ü×$Ñ$¨Ó)Ø÷ 
Ð	Ø)÷ 
ô ×Ñ Ó(Ð(÷ 
Õ	ús   ‘AÁ
Ac              ƒ  óT   #   • [         R                  " [        U 5      I Sh  v•N $  N7f)a'  Wait asynchronously for an update from the shared background task.

If the latest fetch failed, this raises its error while at least one instance is started.

Args:
    timeout: Maximum wait in seconds, or `None` to wait indefinitely.

Returns:
    True if prices were updated, False otherwise.
N)ÚasyncioÚ	to_threadr   r   s    r   r   r   -   s!   é € ô ×"Ò"Ô#;¸WÓE×EÐEÑEùs   ‚(¡&¢(c                  ó²   • \ rS rSr% SrSrS\S'    \rS\S'    \	" S S	9r
S
\S'    \	" SSSSS9rS\S'    SS.SS jjrSSS jjrS rS rSS jrSS jrSrg)r   é;   a‰  Update prices in one background task shared by all instances.

Each instance keeps the task running from `start()` until `stop()`. When an instance starts, it
supplies the settings and `fetch()` method for future fetches. Calling `start()` while it is
already started only waits if requested. Fetched prices stay in use.

Use this as a context manager or call `start()` and `stop()` yourself.
i  ÚfloatÚupdate_intervalÚstrÚurlc                 ó,   • [         R                  " SSS9$ )Né
   é   )r   Úconnect)Úhttpx2ÚTimeout© ó    r   Ú<lambda>ÚUpdatePrices.<lambda>J   s   € ÄFÇNÂNÐ[]ÐghÒDir&   ©Údefault_factoryzhttpx2.TimeoutÚrequest_timeoutF)ÚdefaultÚinitÚreprÚcompareÚboolÚ_started)r   c               óö   • [         R                     U R                  (       d  [         R                  U 5        SU l        SSS5        U(       a  [         R	                  USL a  SOUS9  gg! , (       d  f       N1= f)a8  Start this instance and keep the background task running.

Future fetches use this instance's settings and `fetch()` method. Calling `start()` while
it is already started only waits if requested.

Args:
    wait: `True` to wait up to 30 seconds, a number to wait that many seconds, or `False` to return at once.
TNé   r   )r   r   r1   Úacquirer   )Úselfr   s     r   ÚstartÚUpdatePrices.startO   sZ   € ô ×!Ó!Ø—=—=Ü×'Ñ'¨Ô-Ø $�”÷ "ö Ü× Ñ ¨t°tª|©ÀÐ ÒFð ÷	 "Õ!ús   ‘.A*Á*
A8Nc                óP   • U R                   (       d  g[        R                  U5      $ )a   Wait for a background price update.

If the latest fetch failed, this raises its error while this instance is started.

Args:
    timeout: Maximum wait in seconds, or `None` to wait indefinitely.

Returns:
    True if prices were updated, False otherwise.
F)r1   r   r   )r5   r   s     r   r   ÚUpdatePrices.wait_   s   € ð �}�}ØÜ×#Ñ# GÓ,Ð,r&   c                óÄ   • [         R                     U R                  (       d
   SSS5        gSU l        [         R                  5         SSS5        g! , (       d  f       g= f)aU  Stop this instance from keeping the background task running.

`stop()` does not wait for the task or raise fetch failures. The task exits when no instances
are started and any current fetch is finished. Any prices returned by that fetch are used.
Fetched prices stay in use. Calling `stop()` on an instance that is not started does nothing.
NF)r   r   r1   Úrelease©r5   s    r   ÚstopÚUpdatePrices.stopn   s@   € ô ×!Ó!Ø—=—=Ø÷ "Ð!ð "ˆDŒMÜ×#Ñ#Ô%÷	 "×!Ö!ús   ‘A­AÁ
Ac                ó&   • U R                  5         U $ ©N)r6   r<   s    r   Ú	__enter__ÚUpdatePrices.__enter__{   s   € Ø�
‰
ŒØˆr&   c                ó$   • U R                  5         g r@   )r=   )r5   Ú_argss     r   Ú__exit__ÚUpdatePrices.__exit__   s   € Ø�	‰	�r&   c                ó:  • SSK Jn  [        R                  " U R                  U R
                  S9nUR                  5         [        R                  " UR                  5      n[        U[        5      (       d  [        S5      eU" U5      n[        R                  " USS9$ )z9Fetches the latest provider data from the configured URL.r   )Ú_providers_from_rawr   z6Expected fetched prices payload to be a provider arrayT)Úfrom_auto_update)ÚtypesrH   r#   Úgetr   r+   Úraise_for_statusÚjsonÚloadsÚcontentÚ
isinstanceÚlistÚ
ValueErrorr	   ÚDataSnapshot)r5   rH   ÚrÚraw_payloadÚ	providerss        r   ÚfetchÚUpdatePrices.fetch‚   ss   € å.ä�JŠJ�t—x‘x¨×)=Ñ)=Ñ>ˆØ	×ÑÔÜ—j’j §¡Ó+ˆÜ˜+¤t×,Ñ,ÜÐUÓVÐVá'¨Ó4ˆ	Ü×)Ò)¨)ÀdÑKÐKr&   )r1   )r   zbool | floatr@   ©r   zfloat | NoneÚreturnr0   )rD   Úobject)rZ   z!data_snapshot.DataSnapshot | None)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__r   Ú__annotations__r
   r   r   r+   r1   r6   r   r=   rA   rE   rW   Ú__static_attributes__r%   r&   r   r   r   ;   sq   ‡ ñð "€O�UÓ!Ø0Ø!€CˆÓ!Ø'Ù&+Ñ<iÑ&j€O�^ÓjØ(Ù 5¨u¸5È%ÑP€HˆdÓPØ[à,1÷ Gö -ò&òô÷Lr&   r   c                  ó  • \ rS rSr% Sr\" \R                  S9rS\	S'   Sr
S\	S'    S	rS
\	S'    S	rS\	S'    \" \R                  S9rS\	S'    \" \R                  S9rS\	S'    S	rS\	S'    SS jrSS jrSS jrSS jrSS jrSS jrSrg	)Ú_SharedUpdateré�   a  The one background updater shared by every `UpdatePrices` instance in the process.

The thread runs while `ref_count` is above zero and uses `fetcher`, the instance started most
recently. `lock` guards that state and is never held across anything that blocks.
r)   zthreading.Lockr   r   Úintr   NzUpdatePrices | NoneÚfetcherzthreading.Thread | NoneÚthreadzthreading.EventÚwakeÚreadyz4tuple[Exception | None, TracebackType | None] | NoneÚoutcomec                ó”  • U R                   nUb~  UR                  UR                  UR                  4UR                  UR                  UR                  4:w  a6  [        R                  SUR                  UR                  UR                  5        Xl         U =R                  S-  sl        U R                  cb  SU l        U R                  R                  5         [        R                  " U R                  SSS9U l         U R                  R                  5         gg! [         a$    SU l        X l         U =R                  S-  sl        e f = f)zdCount `instance` in and use its settings; launch the thread if none is running. Caller holds `lock`.NzUgenai-prices background task now using url=%r, update_interval=%r, request_timeout=%rr   Tzgenai_prices:update)ÚtargetÚdaemonÚname)rg   r   r   r+   ÚloggerÚinfor   rh   rk   rj   ÚclearÚ	threadingÚThreadÚ_runr6   ÚBaseException)r5   ÚinstanceÚpreviouss      r   r4   Ú_SharedUpdater.acquire¦   s  € à—<‘<ˆØÑ X§\¡\°8×3KÑ3KÈX×MeÑMeÐ$fØ�L‰LØ×$Ñ$Ø×$Ñ$ðk
ó %
ô
 �K‰KØgØ—‘Ø×(Ñ(Ø×(Ñ(ô	ð  ŒØ�Š˜!Ñ�à�;‰;ÑàˆDŒLØ�J‰J×ÑÔÜ#×*Ò*°$·)±)ÀDÐOdÑeˆDŒKðØ—‘×!Ñ!Õ#ð øô !ó ð #�”Ø'”Ø—’ !Ñ#•Øðús   Ã=D Ä.Ec                ó’   • U =R                   S-  sl         U R                   S:X  a"  SU l        U R                  R                  5         gg)z\Count one instance out; the thread exits on its own once none are left. Caller holds `lock`.r   r   N)r   rg   ri   Úsetr<   s    r   r;   Ú_SharedUpdater.releaseÆ   s5   € à�Š˜!Ñ�Ø�>‰>˜QÓØˆDŒLØ�I‰I�M‰M�Oð r&   c                óì   • [         R                  " 5       U R                  L a  [        S5      eU R                  R                  US9(       d  gU R                  nUc  gUu  p4Ub  UR                  U5      eg)Nz3UpdatePrices background task cannot wait for itselfr   FT)rs   Úcurrent_threadrh   ÚRuntimeErrorrj   r   rk   Úwith_traceback)r5   r   rk   ÚerrorÚerror_tracebacks        r   r   Ú_SharedUpdater.waitÍ   sm   € Ü×#Ò#Ó%¨¯©Ò4ÜÐTÓUÐUØ�z‰z�‰ wˆÖ/ØØ—,‘,ˆØ‰?àØ!(ÑˆØÑð ×&Ñ& Ó7Ð7Ør&   c                óf   • Xb  UR                   OS 4U l        U R                  R                  5         g r@   )Ú__traceback__rk   rj   r{   )r5   r�   s     r   Ú_publishÚ_SharedUpdater._publishÞ   s'   € ØÑ6G˜u×2Ò2ÈTÐRˆŒØ�
‰
�‰Õr&   c                ó<  • [         R                  " 5       n [        R                  S5         U R                     U R
                  ULa   SSS5        [        R                  S5        gU R                  nUc@  SU l        U R                  R                  5          SSS5        [        R                  S5        gU R                  R                  5         SSS5         U R                  W5        U R                  R#                  WR$                  5        Må  ! , (       d  f       NG= f! [         aE  nU R                  U5        [        R                  S[        U5      R                   U5         SnAN‚SnAff = f! [&         al  nU R                     U R
                  UL a)  SU l        [)        S5      nX4l        U R                  U5        SSS5         SnAO! , (       d  f        SnAO= fSnAff = f[        R                  S5        g! [        R                  S5        f = f)z@The thread body: fetch while any instance is started, then exit.z%Starting genai-prices background taskNz$genai-prices background task stoppedz6Error updating genai-prices in the background (%s): %sz4UpdatePrices background task terminated unexpectedly)rs   r~   rp   rq   r   rh   rg   rj   r{   ri   rr   Ú_update_pricesÚ	Exceptionr†   r�   Útyper\   r   r   rv   r   Ú	__cause__)r5   Úmerg   Úer�   s        r   ru   Ú_SharedUpdater._runâ   sˆ  € ä×%Ò%Ó'ˆð	@Ü�K‰KÐ?Ô@ØØ—Y“YØ—{‘{¨"Ò,à÷ ô4 �K‰KÐ>Õ?ð- #Ÿl™l�GØ‘Ø&*˜œàŸ
™
Ÿ™Ô(Ø÷ ô4 �K‰KÐ>Õ?ð! —I‘I—O‘OÔ%÷ ðpØ×'Ñ'¨Ô0ð —	‘	—‘˜w×6Ñ6Ô7ñ# ß•Yûô !ó pØ—M‘M !Ô$Ü—L‘LÐ!YÔ[_Ð`aÓ[b×[kÑ[kÐmn×oÑoûðpûô ó 	)à—“Ø—;‘; "Ò$Ø"&�D”KÜ(Ð)_Ó`�EØ&'”OØ—M‘M %Ô(÷ ——–þð	)úô �K‰KÐ>Õ?øŒF�K‰KÐ>Õ?ús¦   —"E5 ¹DÁ
E5 Á(1DÂE5 Â7DÃE5 ÃD# Ã+'E5 Ä
D ÄE5 Ä#
E2Ä-;E-Å(E5 Å-E2Å2E5 Å5
G+Å?G&Æ9GÇG&ÇH Ç
G#	ÇG&ÇH Ç#G&Ç&G+Ç+H ÈHc                ó0  • [        5       nUR                  5       n[        5       U-
  nU(       a+  [        R                  S[	        UR
                  5      U5        O[        R                  SU5        [        R                  " U5        U R                  S 5        g )Nz1Successfully fetched %d providers in %.2f secondsz2Successfully fetched null snapshot in %.2f seconds)	r   rW   rp   rq   ÚlenrV   r	   Úset_custom_snapshotr†   )r5   rg   r6   ÚsnapshotÚintervals        r   r‰   Ú_SharedUpdater._update_prices  si   € Ü“ˆØ—=‘=“?ˆÜ“6˜E‘>ˆÞÜ�K‰KÐKÌSÐQY×QcÑQcÓMdÐfnÕoä�K‰KÐLÈhÔWä×)Ò)¨(Ô3Ø�‰�dÕr&   )rg   rk   rh   )rw   r   rZ   ÚNone)rZ   r–   rY   )r�   zException | NonerZ   r–   )rg   r   rZ   r–   )r\   r]   r^   r_   r`   r   rs   ÚLockr   ra   r   rg   rh   ÚEventri   rj   rk   r4   r;   r   r†   ru   r‰   rb   r%   r&   r   rd   rd   �   s    ‡ ññ !°·±Ñ@€Dˆ.Ó@Ø€IˆsÓØ)Ø#'€GÐ Ó'ØfØ&*€FÐ#Ó*Ø,Ù!°)·/±/ÑB€Dˆ/ÓBØWÙ"°9·?±?ÑC€Eˆ?ÓCØNØDH€GÐAÓHØHôô@ôô"ô @÷D
r&   rd   r@   rY   )Ú
__future__r   Ú_annotationsr   rM   Úloggingrs   Údataclassesr   r   r   rJ   r   r#   Ú r	   Ú__all__Ú	getLoggerrp   r
   r   r   r   rd   r   r%   r&   r   Ú<module>r       s–   ðÝ 2ã Û Û Û ß (Ý Ý ã å ð€ð 
×	Ò	˜>Ó	*€àjð ö
)ö"Fð ÷QLð QLó ðQLðh ÷}ð }ó ð}ñ@ !Ó"�r&   